Está en la página 1de 3560

Díganos qué opina sobre la experiencia de descarga del PDF.

Cómo usar la documentación de


PowerShell
Artículo • 04/10/2023

Le damos la bienvenida a la documentación en línea de PowerShell. Este sitio contiene


referencia de cmdlets para las siguientes versiones de PowerShell:

PowerShell 7.4 (versión preliminar)


PowerShell 7.3
PowerShell 7.2 (LTS-Current)
PowerShell 5.1

Navegación por la documentación

La página web contiene varios elementos que le ayudan a navegar por la


documentación.

Navegación de nivel de sitio: la navegación de nivel de sitio aparece en la parte


superior de la página. Contiene vínculos a otro contenido en la plataforma de
Microsoft Learn.
Navegación de contenido relacionado: la barra de contenido relacionado está
justo debajo de la navegación de nivel de sitio. Contiene vínculos a contenido
relacionado con el conjunto de documentación actual que, en este caso, es
PowerShell.
Selector de versión: el selector de versión aparece sobre la tabla de contenido
(TOC) y controla qué versión de la referencia del cmdlet aparece en esta.
Tabla de contenido: la TOC del lado izquierdo de la página se divide en dos
secciones: conceptual y referencia. Observe la línea que hay entre el nodo
Referencia de la TOC. Los documentos conceptuales aparecen sobre la línea. El
contenido de referencia aparece en el nodo Referencia que hay debajo de la línea.
Botones de acción: los botones de acción proporcionan una manera de agregar
contenido a una colección, proporcionar comentarios, editar el contenido o
compartirlo con otros usuarios.

Selección de la versión de PowerShell


Use el selector de versiones situado encima de la TOC para seleccionar la versión de
PowerShell que quiera. De manera predeterminada, la página se carga con la versión
estable más actual seleccionada. El selector de versión controla qué versión de la
referencia de cmdlet aparece en la TOC del nodo Referencia. Algunos cmdlets funcionan
de forma distinta en las diferentes versiones de PowerShell que se estén usando.
Asegúrese de que está viendo la documentación de la versión correcta de PowerShell.

El selector de versiones no afecta a la documentación conceptual. Los documentos


conceptuales se muestran por encima del nodo Referencia en la TOC. Aparecen los
mismos artículos conceptuales para cada versión seleccionada. Si hay diferencias
específicas de la versión, la documentación toma nota de ellas.
Revise el valor $PSversionTable.PSVersion para comprobar la versión de PowerShell que
usa. En el ejemplo siguiente se muestra la salida de Windows PowerShell 5.1.

PowerShell

$PSVersionTable.PSVersion

Output

Major Minor Build Revision


----- ----- ----- --------
5 1 22621 963

Búsqueda de artículos
Hay dos maneras de buscar contenido en Docs.

El cuadro de búsqueda de la barra de navegación de nivel de sitio busca en todo el


sitio. Devuelve una lista de artículos coincidentes de todos los conjuntos de
documentación.
El cuadro de filtro TOC situado bajo el selector de versiones permite filtrar por
palabras que aparecen en el título de un artículo. El filtro muestra una lista de
artículos coincidentes a medida que escribe. También puede seleccionar la opción
para buscar las palabras de un artículo. Al buscar desde aquí, la búsqueda se limita
a la documentación de PowerShell.
En el ejemplo siguiente, la búsqueda en la barra de navegación de nivel de sitio
devuelve 840 resultados para la palabra idempotent . Al escribir la palabra invoke en el
cuadro de filtro TOC, se muestra una lista de artículos que contienen la palabra invoke
en el título. Escribir la palabra idempotent en el filtro TOC no muestra ningún artículo. Al
hacer clic en el vínculo de búsqueda, se busca idempotent en la documentación de
PowerShell. Esta búsqueda solo devuelve 9 resultados.

Descarga de la documentación como PDF


Para descargar la documentación como PDF, haga clic en el botón Descargar PDF
situado en la parte inferior de la TOC.
Si está viendo un artículo conceptual, la plataforma Learn crea un PDF que
contiene todo el contenido conceptual de la versión seleccionada.
Si está viendo un artículo de referencia, la plataforma Learn crea un PDF que
contiene todo el contenido de referencia de la versión seleccionada.

Búsqueda de artículos de versiones anteriores


La documentación de las versiones anteriores de PowerShell está archivado en el sitio
Versiones anteriores . Puede elegir Versiones anteriores en el selector de versiones.
Este sitio contiene documentación sobre los siguientes temas:

PowerShell 3.0
PowerShell 4.0
PowerShell 5.0
PowerShell 6
PowerShell 7.0
PowerShell 7.1
Flujos de trabajo de PowerShell
Acceso web a PowerShell

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
¿Qué es PowerShell?
Artículo • 28/06/2023

PowerShell es una solución de automatización de tareas multiplataforma formada por


un shell de línea de comandos, un lenguaje de scripting y un marco de administración
de configuración. PowerShell funciona en Windows 10, Linux y macOS.

Shell de línea de comandos


PowerShell es un shell de comandos moderno que incluye las mejores características de
otros shells populares. A diferencia de la mayoría de los shells que solo aceptan y
devuelven texto, PowerShell acepta y devuelve objetos .NET. El shell incluye las
siguientes características:

Un historial de línea de comandos sólido.


Finalización con tabulación y predicción de comandos (vea about_PSReadLine).
Admite alias de comando y parámetro.
Canalización para encadenar comandos.
Sistema de ayuda en la consola, similar a las páginas man de UNIX.

Lenguaje de scripting
Como lenguaje de scripting, PowerShell se usa normalmente para automatizar la
administración de sistemas. También se usa para compilar, probar e implementar
soluciones, a menudo en entornos de CI/CD. PowerShell se basa en .NET Common
Language Runtime (CLR). Todas las entradas y salidas son objetos de .NET. No es
necesario analizar la salida de texto para extraer información de la salida. El lenguaje de
scripting de PowerShell incluye las siguientes características:

Extensible mediante funciones, clases, scriptsy módulos.


Sistema de formato extensible para una salida fácil.
Sistema de tipos extensible para crear tipos dinámicos.
Compatibilidad integrada con formatos de datos comunes, como CSV, JSONy XML.

Plataforma de automatización
La naturaleza extensible de PowerShell ha habilitado un ecosistema de módulos de
PowerShell para implementar y administrar casi cualquier tecnología con la que trabaje.
Por ejemplo:
Microsoft

Azure
Windows
Exchange
SQL

Aplicaciones de terceros

AWS
VMWare
Google Cloud

Administración de configuración
Desired State Configuration (DSC) de PowerShell es un marco de administración en
PowerShell que permite administrar la infraestructura empresarial con configuración
como código. Con DSC, puede:

Crear configuraciones declarativas y scripts personalizados para implementaciones


repetibles.
Aplicar valores de configuración e informar sobre el desplazamiento de
configuración.
Implementar la configuración mediante los modelos de inserción o extracción.

Pasos siguientes

Introducción
¿Es nuevo en PowerShell y no sabe por dónde empezar? Para empezar, consulte estos
recursos:

Instalación de PowerShell
Tutoriales PowerShell Bits
Conceptos básicos sobre PowerShell
Vídeos de Microsoft Virtual Academy
Módulos de aprendizaje de PowerShell

PowerShell en acción
Eche un vistazo a cómo se usa PowerShell en diferentes escenarios y en distintas
plataformas.

Comunicación remota de PowerShell a través de SSH


Introducción a Azure PowerShell
Compilación de una canalización de CI/CD con DSC
Administración de Microsoft Exchange
¿Qué es un comando de PowerShell
(cmdlet)?
Artículo • 13/04/2023

Los comandos de PowerShell se conocen como cmdlets. Además de los cmdlets,


PowerShell permite ejecutar cualquier comando disponible en el sistema.

¿Qué es un cmdlet?
Los cmdlets son comandos de PowerShell nativos, no ejecutables independientes. Los
cmdlets se recopilan en módulos de PowerShell que se pueden cargar a petición. Los
cmdlets se pueden escribir en cualquier lenguaje .NET compilado o en el mismo
lenguaje de scripting de PowerShell.

Nombres de cmdlets
PowerShell usa un par de términos verbo-nombre para asignar nombres a los cmdlets.
Por ejemplo, el cmdlet Get-Command incluido en PowerShell se usa para obtener todos
los cmdlets que están registrados en el shell de comandos. El verbo identifica la acción
que realiza el cmdlet y el nombre identifica el recurso en el que el cmdlet realiza la
acción.

Pasos siguientes
Para más información sobre PowerShell y cómo buscar otros cmdlets, consulte el tutorial
Descripción de PowerShell.

Para más información acerca de cómo crear sus propios cmdlets, consulte los siguientes
recursos:

Cmdlets basados en scripts

about_Functions_Advanced
about_Functions_CmdletBindingAttribute
about_Functions_Advanced_Methods

Cmdlets compilados (documentos de SDK para PowerShell)

Información general del cmdlet


Descripción de PowerShell
Artículo • 30/03/2023

PowerShell es un shell de línea de comandos y un lenguaje de scripting, todo en uno.


PowerShell se inició en Windows para ayudar a automatizar las tareas administrativas.
Ahora, se ejecuta entre plataformas y se puede usar para varias tareas.

Lo que hace que PowerShell sea único es que acepta y devuelve objetos .NET, en lugar
de texto. Esta característica facilita la conexión de distintos comandos en una
canalización.

¿Para qué se puede usar PowerShell?


El uso de PowerShell ha crecido desde los días en los que era exclusivo de Windows.
Todavía se usa para la automatización de tareas de Windows, pero hoy en día se puede
utilizar para tareas como las siguientes:

Administración de la nube. PowerShell se puede usar para recursos de nube. Por


ejemplo, puede recuperar información sobre los recursos de nube, así como para
actualizar o implementar nuevos recursos.
CI/CD. También se puede usar como parte de una canalización de implementación
continua o de integración continua.
Automatización de tareas para Active Directory y Exchange. Se puede usar para
automatizar prácticamente cualquier tarea en Windows, como la creación de
usuarios en Active Directory y buzones de Exchange.

Hay muchas más áreas de uso, pero la lista anterior le ofrece una sugerencia de todo lo
que ha evolucionado PowerShell.

¿Quién usa PowerShell?


PowerShell es una herramienta eficaz que puede ayudar a las personas que trabajan en
una multitud de roles. Tradicionalmente, el uso de PowerShell ha correspondido al rol de
administrador del sistema, pero ahora lo utilizan usuarios que se denominan DevOps,
operaciones en la nube e incluso desarrolladores.

Cmdlets de PowerShell
PowerShell incluye cientos de comandos preinstalados. Los comandos de PowerShell se
conocen como cmdlets.
El nombre de cada cmdlet consta de un par de verbo-sustantivo. Por ejemplo, Get-
Process . Esta convención de nomenclatura hace que sea más fácil comprender lo que
hace el cmdlet. También facilita la búsqueda del comando que se necesita. Al buscar un
cmdlet para usar, puede filtrar por el verbo o el sustantivo.

Uso de cmdlets para explorar PowerShell


La primera vez que se selecciona PowerShell, es posible que le intimide, ya que hay
mucho que aprender. PowerShell está diseñado para ayudarle a aprender
progresivamente, según lo necesite.

PowerShell incluye cmdlets que ayudan a descubrir PowerShell. Con estos tres cmdlets,
puede descubrir qué comandos están disponibles, qué hacen y con qué tipos funcionan.

Get-Verb . Al ejecutar este comando se devuelve una lista de verbos a los que se

adhieren la mayoría de los comandos. La respuesta incluye una descripción de lo


que hacen estos verbos. Como la mayoría de los comandos siguen esta
convención de nomenclatura, establece las expectativas sobre lo que hace un
comando. Esto le ayuda a seleccionar el comando adecuado y qué nombre asignar
a un comando, si va a crear uno.
Get-Command . Este comando recupera una lista de todos los comandos instalados
en la máquina.
Get-Member . Funciona en la salida basada en objetos y puede detectar qué objetos,

propiedades y métodos están disponibles para un comando.


Get-Help . Al invocar este comando con el nombre de un comando como

argumento, se muestra una página de ayuda en la que se describen varios


elementos de un comando.

Con estos comandos, puede descubrir prácticamente todo lo que necesita saber sobre
PowerShell.

Verbo
El concepto de verbo es importante en PowerShell. Se trata de un estándar de
nomenclatura que siguen la mayoría de los cmdlets. También es un estándar de
nomenclatura que se espera que siga al escribir comandos propios. La idea es que el
verbo indique lo que se intenta hacer, como leer datos o posiblemente cambiarlos.
PowerShell tiene una lista normalizada de verbos. Para obtener una lista completa de
todos los verbos posibles, use el cmdlet Get-Verb :

PowerShell
Get-Verb

El cmdlet devuelve una lista larga de verbos. La Descripción proporciona el contexto de


lo que el verbo debe hacer. Estas son las primeras filas de la salida:

Output

Verb AliasPrefix Group Description


---- ----------- ----- -----------
Add a Common Adds a resource to a container, or attaches
an item to another item
Clear cl Common Removes all the resources from a container
but does not delete the container
Close cs Common Changes the state of a resource to make it
inaccessible, unavailable, or unusab…
Copy cp Common Copies a resource to another name or to
another container
Enter et Common Specifies an action that allows the user to
move into a resource
Exit ex Common Sets the current environment or context to
the most recently used context
...

Búsqueda de comandos con Get-Command


El cmdlet Get-Command devuelve una lista de todos los comandos disponibles que están
instalados en el sistema. La lista que recibe es bastante grande. Puede limitar la cantidad
de información obtenida filtrando la respuesta mediante parámetros o cmdlets
auxiliares.

Filtrado por nombre


Puede filtrar la salida de Get-Command mediante parámetros diferentes. El filtrado
permite buscar comandos que tengan determinadas propiedades. El parámetro Name
permite buscar un comando específico por nombre.

PowerShell

Get-Command -Name Get-Process

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Get-Process 7.0.0.0 Microsoft.PowerShell.Management
¿Y si desea encontrar todos los comandos que funcionan con procesos? Puede usar un
carácter comodín * para que coincida con otras formas de la cadena. Por ejemplo:

PowerShell

Get-Command -Name *-Process

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Debug-Process 7.0.0.0 Microsoft.PowerShell.Management
Cmdlet Get-Process 7.0.0.0 Microsoft.PowerShell.Management
Cmdlet Start-Process 7.0.0.0 Microsoft.PowerShell.Management
Cmdlet Stop-Process 7.0.0.0 Microsoft.PowerShell.Management
Cmdlet Wait-Process 7.0.0.0 Microsoft.PowerShell.Management

Filtrado por sustantivo y verbo


Hay otros parámetros que filtran los valores del verbo y del nombre. La parte del verbo
del nombre de un comando es la situada más a la izquierda. El verbo debe ser uno de
los valores devueltos por el cmdlet Get-Verb . El elemento situado más a la derecha de
un comando es la parte del sustantivo. Un nombre puede ser cualquier cosa.

Filtrado por verbo. En el comando Get-Process , la parte del verbo es Get . Para
filtrar por la parte de verbo, use el parámetro Verb.

PowerShell

Get-Command -Verb 'Get'

En este ejemplo se enumeran todos los comandos que usan el verbo Get .

Filtrado por sustantivo. En el comando Get-Process , la parte del sustantivo es


Process . Para filtrar por el sustantivo, use el parámetro Noun. En el ejemplo
siguiente se devuelven todos los cmdlets que tienen nombres que comienzan por
la letra U .

PowerShell

Get-Command -Noun U*
Además, puede combinar parámetros para restringir la búsqueda, por ejemplo:

PowerShell

Get-Command -Verb Get -Noun U*

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Get-UICulture 7.0.0.0
Microsoft.PowerShell.Utility
Cmdlet Get-Unique 7.0.0.0
Microsoft.PowerShell.Utility
Cmdlet Get-Uptime 7.0.0.0
Microsoft.PowerShell.Utility

Uso de cmdlets de asistente para filtrar los resultados


También puede usar otros cmdlets para filtrar los resultados.

Select-Object . Este comando versátil le ayuda a elegir propiedades específicas de

uno o más objetos. También puede limitar el número de elementos que obtiene.
En el ejemplo siguiente se devuelven los valores de propiedad Name y Source de
los primeros 5 comandos disponibles en la sesión actual.

PowerShell

Get-Command | Select-Object -First 5 -Property Name, Source

Output

Name Source
---- ------
Add-AppPackage Appx
Add-AppPackageVolume Appx
Add-AppProvisionedPackage Dism
Add-AssertionOperator Pester
Add-ProvisionedAppPackage Dism

Para más información, vea Selección de objeto.

Where-Object . Este cmdlet permite filtrar los objetos devueltos en función de los
valores de las propiedades. El comando toma una expresión que puede probar el
valor de una propiedad. En el ejemplo siguiente se devuelven todos los procesos
en los que ProcessName comienza por p .

PowerShell

Get-Process | Where-Object {$_.ProcessName -like "p*"}

El cmdlet Get-Process devuelve una colección de objetos de proceso. Para filtrar la


respuesta, canalice la salida a Where-Object . El proceso de canalización significa
que dos o más comandos están conectados a través de un carácter de barra
vertical | . La salida de un comando se envía como la entrada del siguiente. La
expresión de filtro para Where-Object usa el operador -like para buscar
coincidencias con los procesos que comienzan por la letra p .

Exploración de objetos con Get-Member


Una vez que haya podido encontrar el cmdlet que quiere, le interesará saber más sobre
lo que genera, El cmdlet Get-Member muestra el tipo, las propiedades y los métodos de
un objeto. Canalice la salida que quiera inspeccionar a Get-Member .

PowerShell

Get-Process | Get-Member

En el resultado se muestra el tipo devuelto como TypeName y todas las propiedades y los
métodos del objeto. Este es un fragmento de este resultado:

Output

TypeName: System.Diagnostics.Process

Name MemberType Definition


---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
...

Con el parámetro MemberType, puede limitar la información devuelta.

PowerShell

Get-Process | Get-Member -MemberType Method


De forma predeterminada, PowerShell solo muestra algunas propiedades. En el ejemplo
anterior se muestran los miembros Name , MemberType y Definition . Puede usar Select-
Object para especificar las propiedades que desea ver. Por ejemplo, solo quiere mostrar

las propiedades Name y Definition :

PowerShell

Get-Process | Get-Member | Select-Object Name, Definition

Búsqueda por tipo de parámetro


Get-Member nos mostró que Get-Process devuelve objetos de tipo Process. El parámetro

ParameterType de Get-Command se puede usar para buscar otros comandos que toman
objetos Process como entrada.

PowerShell

Get-Command -ParameterType Process

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Debug-Process 7.0.0.0
Microsoft.PowerShell.Managem…
Cmdlet Enter-PSHostProcess 7.1.0.0
Microsoft.PowerShell.Core
Cmdlet Get-Process 7.0.0.0
Microsoft.PowerShell.Managem…
Cmdlet Get-PSHostProcessInfo 7.1.0.0
Microsoft.PowerShell.Core
Cmdlet Stop-Process 7.0.0.0
Microsoft.PowerShell.Managem…
Cmdlet Wait-Process 7.0.0.0
Microsoft.PowerShell.Managem…

Conocer el tipo de salida de un comando puede ayudar a reducir la búsqueda de


comandos relacionados.

Recursos adicionales
Get-Command
Get-Member
Select-Object
Instalación de PowerShell en Windows,
Linux y macOS
Obtenga información sobre la instalación de PowerShell en Windows, Linux y macOS.

Windows

e INFORMACIÓN GENERAL

Instalación de PowerShell en Windows

Versiones de Windows compatibles

Instalación de Windows PowerShell 5.1

macOS

e INFORMACIÓN GENERAL

Instalación en macOS

Versiones de macOS compatibles

Linux

e INFORMACIÓN GENERAL

Información general de Linux

Alpine

Debian

Raspberry Pi OS

Red Hat Enterprise Linux

Ubuntu

Q&A
b INTRODUCCIÓN

Métodos de instalación alternativos

SDK con soporte de la comunidad

Uso de PowerShell en el Docker

Compatibilidad con procesadores Arm

Peguntas más frecuentes de Microsoft Update para PowerShell

Ciclo de vida de soporte técnico de PowerShell


Instalación de PowerShell en Windows
Artículo • 22/09/2023

Hay varias formas de instalar PowerShell en Windows. Cada método de instalación está
diseñado para admitir diferentes escenarios y flujos de trabajo. Elija el método de
instalación que mejor se adapte a sus necesidades.

Winget: forma recomendada de instalar PowerShell en clientes Windows.


Paquete MSI: mejor opción para escenarios de implementación empresarial y
servidores de Windows.
Paquete ZIP: forma más sencilla de "cargarlo localmente" o instalar varias
versiones.
Use este método de instalación para Windows Nano Server, Windows IoT y los
sistemas basados en ARM.
Herramienta global de .NET: una buena opción para los desarrolladores de .NET
que instalan y usan otras herramientas globales.
Paquete de Microsoft Store: una manera fácil de instalar para los usuarios
ocasionales de PowerShell, pero que tiene limitaciones.

7 Nota

Los comandos de instalación de este artículo son para la versión estable más
reciente de PowerShell. Para instalar otra versión de PowerShell, ajuste el comando
para que se adapte a la versión que necesita. Los vínculos siguientes lo dirigen a la
página de lanzamiento de cada versión en el repositorio de PowerShell en GitHub.

Versión estable: https://aka.ms/powershell-release?tag=stable


Versión de LTS: https://aka.ms/powershell-release?tag=lts
Versión preliminar: https://aka.ms/powershell-release?tag=preview

Los vínculos de descarga de cada paquete se encuentran en la sección Activos de


la página de versiones. Es posible que la sección Assets (Recursos) esté contraída,
por lo que tendría que hacer clic para expandirla.

Instalación de PowerShell mediante Winget


(recomendada)
Winget, el administrador de paquetes de Windows, es una herramienta de línea de
comandos que permite a los usuarios detectar, instalar, actualizar, quitar y configurar
aplicaciones en equipos cliente de Windows. Esta herramienta es la interfaz cliente para
el servicio del Administrador de paquetes de Windows. La herramienta de línea de
comandos winget se incluye con Windows 11 y las versiones modernas de Windows 10
de forma predeterminada como Instalador de aplicación.

7 Nota

Vea la documentación de winget para obtener una lista de los requisitos del
sistema y las instrucciones de instalación. Actualmente, Winget no se ejecuta en
servidores Windows.

Los siguientes comandos se pueden usar para instalar PowerShell mediante los
paquetes de winget publicados:

Búsqueda de la versión más reciente de PowerShell

PowerShell

winget search Microsoft.PowerShell

Output

Name Id Version Source


--------------------------------------------------------------
PowerShell Microsoft.PowerShell 7.3.7.0 winget
PowerShell Preview Microsoft.PowerShell.Preview 7.4.0.3 winget

Instalación de PowerShell o PowerShell (versión preliminar) mediante el parámetro id

PowerShell

winget install --id Microsoft.Powershell --source winget


winget install --id Microsoft.Powershell.Preview --source winget

7 Nota

En los sistemas Windows que usan el procesador X86 o X64, winget instala el
paquete MSI. En los sistemas que usan el procesador Arm64, winget instala el
paquete de Microsoft Store (MSIX). Para obtener más información, consulte
Instalación desde Microsoft Store.
Instalación del paquete MSI
Para instalar PowerShell en Windows, use los siguientes vínculos para descargar el
paquete de instalación desde GitHub.

PowerShell:7.3.7-win-x64.msi
PowerShell-7.3.7-win-x86.msi

Una vez descargado, haga doble clic en el archivo instalador y siga las indicaciones.

El instalador crea un acceso directo en el menú de inicio de Windows.

De forma predeterminada, el paquete se instala en $env:ProgramFiles\PowerShell\


<version>

Puede iniciar PowerShell mediante el menú Inicio o $env:ProgramFiles\PowerShell\


<version>\pwsh.exe

7 Nota

PowerShell 7.3 se instala en un nuevo directorio y se ejecuta en paralelo con


Windows PowerShell 5.1. PowerShell 7.3 es una actualización local que reemplaza a
PowerShell 7.0 y versiones anteriores.

PowerShell 7.3 se instala en $env:ProgramFiles\PowerShell\7 .


La carpeta $env:ProgramFiles\PowerShell\7 se agrega a $env:PATH
Se eliminan las carpetas de las versiones publicadas anteriormente.

Si necesita ejecutar PowerShell 7.3 en paralelo con otras versiones, use el método
de instalación ZIP para instalar la otra versión en una carpeta diferente.

Compatibilidad de Microsoft Update con PowerShell 7.2 y


versiones posteriores
PowerShell 7.2 y versiones posteriores admiten Microsoft Update. Al habilitar esta
característica, recibirá las actualizaciones más recientes de PowerShell 7 en el flujo de
administración tradicional de Microsoft Update (MU), ya sea con Windows Update para
empresas, WSUS, Microsoft Endpoint Configuration Manager o el cuadro de diálogo
interactivo de MU en Configuración.

El paquete MSI de PowerShell 7.3 incluye las siguientes opciones de línea de comandos:

USE_MU : esta propiedad tiene dos valores posibles:


1 (valor predeterminado): permite realizar las actualizaciones mediante

Microsoft Update, WSUS o Configuration Manager


0 : no permite realizar las actualizaciones mediante Microsoft Update, WSUS o

Configuration Manager
ENABLE_MU

1 (valor predeterminado): permite usa Microsoft Update para las

actualizaciones automáticas
0 : no permite participar con Microsoft Update

7 Nota

Es posible que la habilitación de las actualizaciones se haya establecido en una


instalación anterior o en una configuración manual. Con ENABLE_MU=0 , no quita la
configuración existente. Además, esta configuración la puede invalidar la
configuración de directiva de grupo controlada por el administrador.

Para más información, consulte las Preguntas más frecuentes sobre Microsoft Update
para PowerShell.

Instalación del paquete MSI desde la línea de comandos


Los paquetes MSI se pueden instalar desde la línea de comandos, lo que permite a los
administradores implementar paquetes sin la interacción del usuario. El paquete MSI
incluye las siguientes propiedades para controlar las opciones de instalación:

ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL : esta propiedad controla la opción para

agregar el elemento Open PowerShell al menú contextual en el Explorador de


Windows.
ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL : esta propiedad controla la opción para

agregar el elemento Run with PowerShell al menú contextual en el Explorador de


Windows.
ENABLE_PSREMOTING : esta propiedad controla la opción para habilitar la

comunicación remota de PowerShell durante la instalación.


REGISTER_MANIFEST : esta propiedad controla la opción para registrar el manifiesto

de registro de eventos de Windows.


ADD_PATH : esta propiedad controla la opción para agregar PowerShell a la variable

de entorno PATH de Windows.


DISABLE_TELEMETRY : esta propiedad controla la opción para deshabilitar la

telemetría de PowerShell estableciendo la variable de entorno


POWERSHELL_TELEMETRY_OPTOUT .

En los ejemplos siguientes se muestra cómo instalar PowerShell de forma silenciosa con
todas las opciones de instalación habilitadas.

PowerShell

msiexec.exe /package PowerShell-7.3.7-win-x64.msi /quiet


ADD_EXPLORER_CONTEXT_MENU_OPENPOWERSHELL=1
ADD_FILE_CONTEXT_MENU_RUNPOWERSHELL=1 ENABLE_PSREMOTING=1
REGISTER_MANIFEST=1 USE_MU=1 ENABLE_MU=1 ADD_PATH=1

Puede encontrar una lista completa de opciones de línea de comandos para


Msiexec.exe en Opciones de línea de comandos.

Instalación del paquete ZIP


Se proporcionan archivos binarios ZIP de PowerShell para permitir escenarios de
implementación avanzada. Descargue uno de estos archivos ZIP desde la página de la
versión actual .

PowerShell:7.3.7-win-x64.zip
PowerShell:7.3.7-win-x86.zip
PowerShell:7.3.7-win-arm64.zip

En función de cómo descargue el archivo, es posible que deba desbloquearlo mediante


el cmdlet Unblock-File . Descomprima el contenido en la ubicación que quiera y ejecute
pwsh.exe desde allí. A diferencia de la instalación de paquetes MSI, la instalación del

archivo ZIP no comprueba los requisitos previos. Para que la comunicación remota en
WSMan funcione correctamente, asegúrese de que se han cumplido los requisitos
previos.

Use este método para instalar la versión basada en ARM de PowerShell en equipos
como Microsoft Surface Pro X. Para obtener los mejores resultados, instale PowerShell
en la carpeta para $env:ProgramFiles\PowerShell\7 .

Instalación como una herramienta global de


.NET
Si ya tiene instalado el SDK de .NET Core, puede instalar PowerShell como una
herramienta global de .NET.
dotnet tool install --global PowerShell

El instalador de la herramienta dotnet agrega $HOME\.dotnet\tools a la variable de


entorno $env:PATH . Sin embargo, el shell que se ejecuta actualmente no tiene
$env:PATH actualizado. Para iniciar PowerShell desde un nuevo shell, escriba pwsh .

Instalación desde Microsoft Store


PowerShell 7.3 se puede instalar desde Microsoft Store. Puede encontrar la versión de
PowerShell en el sitio de Microsoft Store o en la aplicación de la tienda en Windows.

Ventajas del paquete de Microsoft Store:

Actualizaciones automáticas integradas en Windows


Se integra con otros mecanismos de distribución de software como Intune y
Configuration Manager
Se puede instalar en sistemas Windows con procesadores x86, x64 o Arm64

Limitaciones conocidas
De manera predeterminada, los paquetes de Windows Store se ejecutan en un espacio
aislado de aplicación que virtualiza el acceso a algunas ubicaciones del Registro y del
sistema de archivos. Los cambios en las ubicaciones del registro y los archivos
virtualizados no se conservan fuera del espacio aislado de la aplicación.

Este espacio aislado bloquea todos los cambios realizados a la carpeta raíz de la
aplicación. No se pueden modificar las opciones de configuración de nivel de sistema
almacenadas en $PSHOME . Esto incluye la configuración de WSMAN. Esto impide que las
sesiones remotas se conecten a instalaciones basadas en el almacén de PowerShell. Se
admiten las configuraciones de nivel de usuario y la comunicación remota de SSH.

Los siguientes comandos necesitan escribir en $PSHOME . Estos comandos no se admiten


en una instancia de Microsoft Store de PowerShell.

Register-PSSessionConfiguration

Update-Help -Scope AllUsers


Enable-ExperimentalFeature -Scope AllUsers

Set-ExecutionPolicy -Scope LocalMachine


Para más información, consulte Cómo se ejecutan las aplicaciones de escritorio
empaquetadas en Windows.

Cambios para PowerShell 7.2


A partir de PowerShell 7.2, el paquete de PowerShell está exento de la virtualización de
registro y archivos. Los cambios en las ubicaciones del registro y los archivos
virtualizados ahora se conservan fuera del espacio aislado de la aplicación. Sin embargo,
los cambios en la carpeta raíz de la aplicación siguen bloqueados.

) Importante

Debe ejecutar la compilación 1903 de Windows o una superior para que esta
exención funcione.

Instalación de una versión preliminar


Las versiones preliminares de PowerShell 7 se instalan en
$env:ProgramFiles\PowerShell\7-preview , por lo que se pueden ejecutar en paralelo con

versiones no preliminares de PowerShell. PowerShell 7.4 es la siguiente versión


preliminar.

Actualización de una instalación existente


Para obtener los mejores resultados al actualizar, debe usar el mismo método de
instalación que usó la primera vez que instaló PowerShell. Cada método de instalación
instala PowerShell en una ubicación diferente. Si no está seguro de cómo se instaló
PowerShell, puede comparar la ubicación de instalación con la información del paquete
de este artículo. Si instaló mediante el paquete MSI, la información aparece en el panel
de control Programas y características.

7 Nota

Al actualizar, PowerShell no lo hará de una versión LTS a una versión que no sea
LTS. Solo se actualiza a la versión más reciente de LTS, por ejemplo, de 7.2.3 a
7.2.14. Para actualizar desde una versión LTS a una versión estable más reciente o a
la siguiente LTS, debe instalar la nueva versión con MSI para esa versión.
Cuando la versión instalada no es una versión LTS, PowerShell se actualiza a la
versión estable más reciente.

Implementación en Windows 10 IoT Enterprise


Windows 10 IoT Enterprise incluye Windows PowerShell, que se puede usar para
implementar PowerShell 7.

PowerShell

# Replace the placeholder information for the following variables:


$deviceip = '<device ip address'
$zipfile = 'PowerShell-7.3.7-win-arm64.zip'
$downloadfolder = 'u:\users\administrator\Downloads' # The download
location is local to the device.
# There should be enough space for the zip file and the unzipped
contents.

# Create PowerShell session to target device


Set-Item -Path WSMan:\localhost\Client\TrustedHosts $deviceip
$S = New-PSSession -ComputerName $deviceIp -Credential Administrator
# Copy the ZIP package to the device
Copy-Item $zipfile -Destination $downloadfolder -ToSession $S

#Connect to the device and expand the archive


Enter-PSSession $S
Set-Location u:\users\administrator\Downloads
Expand-Archive .\PowerShell-7.3.7-win-arm64.zip

# Set up remoting to PowerShell 7


Set-Location .\PowerShell-7.3.7-win-arm64
# Be sure to use the -PowerShellHome parameter otherwise it tries to create
a new
# endpoint with Windows PowerShell 5.1
.\Install-PowerShellRemoting.ps1 -PowerShellHome .

Cuando configure la comunicación remota de PowerShell, recibirá un mensaje de error y


se desconectará del dispositivo. PowerShell tiene que reiniciar WinRM. Ahora se puede
conectar al punto de conexión de PowerShell 7 en el dispositivo.

PowerShell

# Be sure to use the -Configuration parameter. If you omit it, you connect
to Windows PowerShell 5.1
Enter-PSSession -ComputerName $deviceIp -Credential Administrator -
Configuration PowerShell.7.3.7
Implementación en Windows 10 IoT Core
Windows 10 IoT Core agrega Windows PowerShell cuando se incluye la característica
IOT_POWERSHELL, que se puede usar para implementar PowerShell 7. Los pasos
definidos anteriormente para Windows 10 IoT Enterprise también se pueden seguir para
IoT Core.

Para agregar la última versión de PowerShell en la imagen de envío, use el comando


Import-PSCoreRelease para incluir el paquete en el área de trabajo y agregar la
característica OPENSRC_POWERSHELL a la imagen.

7 Nota

En el caso de la arquitectura ARM64, Windows PowerShell no se agrega cuando se


incluye IOT_POWERSHELL. Por lo tanto, la instalación basada en ZIP no funciona.
Tiene que usar el comando Import-PSCoreRelease para agregarlo a la imagen.

Desarrollo en Nano Server


En estas instrucciones se da por supuesto que Nano Server es un sistema operativo "sin
periféricos" con una versión de PowerShell que ya se ejecuta en él. Para más
información, consulte la documentación del compilador de imágenes de Nano Server.

Los archivos binarios de PowerShell se pueden implementar mediante dos métodos


diferentes.

1. Sin conexión: monte el VHD de Nano Server y descomprima el contenido del


archivo ZIP en la ubicación seleccionada de la imagen montada.
2. En línea: transfiera el archivo ZIP a través de una sesión de PowerShell y
descomprímalo en la ubicación seleccionada.

En ambos casos, necesita el paquete de la versión ZIP de Windows x64 . Ejecute los
comandos en una instancia de "administrador" de PowerShell.

Implementación sin conexión de PowerShell


1. Use su utilidad ZIP favorita para descomprimir el paquete en un directorio de la
imagen montada de Nano Server.
2. Desmonte la imagen e iníciela.
3. Conéctese a la instancia integrada de Windows PowerShell.
4. Siga las instrucciones para crear un punto de conexión de comunicación remota
mediante "otra técnica de instancia".

Implementación con conexión de PowerShell


Implemente PowerShell en Nano Server mediante los pasos siguientes.

PowerShell

# Replace the placeholder information for the following variables:


$ipaddr = '<Nano Server IP address>'
$credential = Get-Credential # <An Administrator account on the system>
$zipfile = 'PowerShell-7.3.7-win-x64.zip'
# Connect to the built-in instance of Windows PowerShell
$session = New-PSSession -ComputerName $ipaddr -Credential $credential
# Copy the file to the Nano Server instance
Copy-Item $zipfile c:\ -ToSession $session
# Enter the interactive remote session
Enter-PSSession $session
# Extract the ZIP file
Expand-Archive -Path C:\PowerShell-7.3.7-win-x64.zip -DestinationPath
'C:\Program Files\PowerShell 7'

Si le interesa la comunicación remota basada en WSMan, siga las instrucciones para


crear un punto de conexión de comunicación remota mediante "otra técnica de
instancia".

Comunicación remota con PowerShell


PowerShell admite el Protocolo de comunicación remota de PowerShell (PSRP) a través
de WSMan y SSH. Para más información, consulte:

Comunicación remota mediante SSH en PowerShell


Comunicación remota mediante WSMan en PowerShell

Se deben cumplir estos requisitos previos para habilitar la comunicación remota de


PowerShell a través de WSMan en versiones anteriores de Windows.

Instale Windows Management Framework (WMF) 5.1 (según sea necesario). Para
más información sobre WMF, consulte la información general sobre WMF.
Instale el entorno de ejecución de C universal en las versiones de Windows
anteriores a Windows 10. Está disponible mediante descarga directa o Windows
Update. Los sistemas con revisión completa ya tienen instalado este paquete.
Versiones compatibles de Windows
En la tabla siguiente se muestra una lista de las versiones de PowerShell y las versiones
de Windows en las que se admiten. Estas versiones se admitirán hasta que la versión de
PowerShell o la de Windows lleguen al final del soporte técnico.

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Windows 7.2 (LTS- 7.3 7.4 (versión


Current) preliminar)

Windows Server 2016, 2019, o 2022

Windows Server 2012 R2

Windows Server Core (2012 R2 o


posterior)

Windows Server Nano (1809 o posterior)

Windows 11

Windows 10 1607+

7 Nota

La compatibilidad con una versión específica de Windows la determinan las


directivas de ciclo de vida de Soporte técnico de Microsoft. Para más información,
consulte:

Preguntas más frecuentes sobre el ciclo de vida del cliente Windows


Preguntas más frecuentes sobre la directiva moderna de ciclo de vida

PowerShell recibe soporte técnico en Windows para las arquitecturas de procesador


siguientes.
Windows 7.2 (LTS- 7.3 7.4 (versión
Current) preliminar)

Nano Server, versión 1803+ x64 x64 x64

Windows Server 2012 R2+ x64, x86 x64, x86 x64, x86

Windows Server Core 2012 x64, x86 x64, x86 x64, x86
R2+

Cliente de Windows 10 u 11 x64, x86, Arm64 x64, x86, x64, x86, Arm64
Arm64

Ejecute winver.exe para comprobar la versión que utiliza.

Compatibilidad con la instalación


Microsoft admite los métodos de instalación de este documento, aunque puede haber
otros de terceros disponibles desde otros orígenes. Si bien esas herramientas y métodos
pueden funcionar, Microsoft no los admite.

6 Collaborate with us on PowerShell


GitHub
A cross-platform task automation
The source for this content can solution made up of a command-
be found on GitHub, where you line shell and a scripting language.
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Instalación de PowerShell en Linux
Artículo • 07/09/2023

PowerShell se puede instalar en varias distribuciones de Linux diferentes. La mayoría de


las plataformas y las distribuciones de Linux tienen una versión principal todos los años
y ofrecen un administrador de paquetes que se usa para instalar PowerShell. PowerShell
se puede instalar en algunas distribuciones de Linux que no son compatibles con
Microsoft. En esos casos, puede encontrar soporte técnico de la comunidad para
PowerShell en esas plataformas.

Para obtener más información, consulte la documentación del ciclo de vida del soporte
de PowerShell.

En este artículo se enumeran las distribuciones de Linux y los administradores de


paquetes admitidos. Todas las versiones de PowerShell siguen teniendo soporte hasta
que la versión de PowerShell o la versión de la distribución de Linux llega al final del
soporte.

Para conseguir la mejor compatibilidad, elija una versión de lanzamiento a largo plazo
(LTS).

Alpine
En la tabla siguiente se muestra una lista de versiones de PowerShell admitidas y las
versiones de Alpine en las que se admiten. Estas versiones recibirán soporte técnico
hasta que la versión de PowerShell o la de Alpine lleguen al final de la vida útil .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

3.15
Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

3.14

Alpine 3.15 se está probando.

PowerShell recibe soporte técnico en Alpine para las siguientes arquitecturas de


procesador.

Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64 x64 x64

PowerShell no se ha probado en Alpine con procesadores ARM.

Para más información, consulte Instalación de PowerShell en Alpine.

Debian
Debian usa APT (herramienta avanzada de paquetes) como administrador de paquetes.

En la tabla siguiente se muestra una lista de versiones de PowerShell actualmente


compatibles y las versiones de Debian en las que se admiten. Estas versiones se seguirán
admitiendo hasta que la versión de PowerShell o la de Debian lleguen al final del ciclo
de vida .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Debian 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

11

10
PowerShell recibe soporte técnico en Debian para las siguientes arquitecturas de
procesador.

Debian 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Versión 9+ x64 x64 x64

Para obtener más información, consulte Instalación de PowerShell en Debian Linux.

Red Hat Enterprise Linux (RHEL)


RHEL 7 usa yum y RHEL 8 usa el administrador de paquetes dnf.

En la tabla siguiente se muestra una lista de las versiones admitidas actualmente de


PowerShell y las versiones de RHEL en las que se admiten. Estas versiones se siguen
admitiendo hasta que la versión de PowerShell o la de RHEL lleguen al final del soporte
técnico .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

RHEL 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

PowerShell recibe soporte técnico en RHEL para las siguientes arquitecturas de


procesador.

RHEL 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64 x64 x64


Para obtener más información, consulte Instalación de PowerShell en
Red Hat Enterprise Linux (RHEL).

Ubuntu
Ubuntu usa APT (herramienta avanzada de paquetes) como administrador de paquetes.

En la tabla siguiente se muestra una lista de las versiones de PowerShell admitidas


actualmente y las versiones de Ubuntu en las que se admiten. Estas versiones se
seguirán admitiendo hasta que la versión de PowerShell o la de Ubuntu lleguen al final
del soporte técnico .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico.
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible.

Ubuntu 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

con la versión 22.04 (LTS)

con la versión 20.04 (LTS)

con la versión 18.04 (LTS)

Solo se admiten oficialmente las versiones LTS de Ubuntu. Microsoft no ofrece soporte
técnico para las versiones provisionales ni sus equivalentes. La comunidad sí admite
las versiones provisionales. Para obtener más información, vea Distribuciones admitidas
por la comunidad.

PowerShell recibe soporte técnico en Ubuntu para las siguientes arquitecturas de


procesador.

Ubuntu 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64, Arm32 x64, Arm32 x64, Arm32

Para obtener más información, consulte Instalación de PowerShell en Ubuntu.


Distribuciones admitidas por la comunidad
PowerShell se puede instalar en muchas distribuciones de Linux que no son compatibles
con Microsoft. En esos casos, puede encontrar soporte técnico de la comunidad para
PowerShell en esas plataformas.

Para recibir soporte técnico de Microsoft, debe cumplir los criterios siguientes:

.NET Core admite la versión y la arquitectura de la distribución.


La versión de la distribución recibirá soporte técnico durante al menos un año.
La versión de la distribución no es una versión provisional ni equivalente.
El equipo de PowerShell ha probado la versión de la distribución.

Para obtener información, consulte Soporte técnico de la comunidad para PowerShell en


Linux.

Métodos de instalación alternativos


Hay otras tres formas de instalar PowerShell en Linux, incluidas las distribuciones de
Linux que no se admiten oficialmente. Puede intentar instalar PowerShell mediante el
paquete Snap de PowerShell. También puede intentar implementar archivos binarios de
PowerShell directamente mediante el paquete tar.gz de Linux. Para obtener más
información, consulte Formas alternativas para instalar PowerShell en Linux.

6 Collaborate with us on PowerShell


GitHub
A cross-platform task automation
The source for this content can solution made up of a command-
be found on GitHub, where you line shell and a scripting language.
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Instalación de PowerShell en Alpine
Linux
Artículo • 07/10/2023

Todos los paquetes están disponibles en nuestra página de versiones de GitHub. Una
vez instalado el paquete, ejecute pwsh desde un terminal. Ejecute pwsh-preview si
instaló una versión preliminar. Antes de llevar a cabo la instalación, consulte la lista de
versiones admitidas a continuación.

7 Nota

PowerShell 7.3 es una actualización local que quita las versiones anteriores de
PowerShell 7. Las versiones preliminares de PowerShell se pueden instalar en
paralelo con otras versiones de PowerShell. Si necesita ejecutar PowerShell 7.3 en
paralelo con una versión anterior, vuelva a instalar la versión anterior con el
método de archivo binario.

Pasos de instalación
La instalación en Alpine se basa en la descarga del paquete tar.gz desde la página de
versiones . La dirección URL del paquete depende de la versión de PowerShell que
quiera instalar.

PowerShell 7.3.7:
https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershell-

7.3.7-linux-alpine-x64.tar.gz

PowerShell 7.2.14:
https://github.com/PowerShell/PowerShell/releases/download/v7.2.14/powershell-

7.2.14-linux-alpine-x64.tar.gz

A continuación, en el terminal, ejecute los siguientes comandos de shell para instalar


PowerShell 7.3:

sh

# install the requirements


sudo apk add --no-cache \
ca-certificates \
less \
ncurses-terminfo-base \
krb5-libs \
libgcc \
libintl \
libssl1.1 \
libstdc++ \
tzdata \
userspace-rcu \
zlib \
icu-libs \
curl

sudo apk -X https://dl-cdn.alpinelinux.org/alpine/edge/main add --no-cache \


lttng-ust

# Download the powershell '.tar.gz' archive


curl -L
https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershell
-7.3.7-linux-alpine-x64.tar.gz -o /tmp/powershell.tar.gz

# Create the target folder where powershell will be placed


sudo mkdir -p /opt/microsoft/powershell/7

# Expand powershell to the target folder


sudo tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7

# Set execute permissions


sudo chmod +x /opt/microsoft/powershell/7/pwsh

# Create the symbolic link that points to pwsh


sudo ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh

# Start PowerShell
pwsh

Desinstalación de PowerShell
sh

sudo rm -rf /usr/bin/pwsh /opt/microsoft/powershell

Rutas de acceso de PowerShell


$PSHOME es /opt/microsoft/powershell/7/ .

Los scripts de perfiles se almacenan en las siguientes ubicaciones:


AllUsersAllHosts: $PSHOME/profile.ps1
AllUsersCurrentHost: $PSHOME/Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts: ~/.config/powershell/profile.ps1
CurrentUserCurrentHost:
~/.config/powershell/Microsoft.PowerShell_profile.ps1

Los módulos se almacenan en las siguientes ubicaciones:


Módulos de usuario: ~/.local/share/powershell/Modules
Módulos compartidos: /usr/local/share/powershell/Modules
Módulos predeterminados: $PSHOME/Modules
El historial de PSReadLine se registra en
~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt

Los perfiles respetan la configuración de cada host de PowerShell, por lo que hay
perfiles predeterminados específicos del host en Microsoft.PowerShell_profile.ps1 en
las mismas ubicaciones.

PowerShell respeta la especificación de directorio base de XDG en Linux.

Versiones compatibles
En la tabla siguiente se muestra una lista de versiones de PowerShell admitidas y las
versiones de Alpine en las que se admiten. Estas versiones recibirán soporte técnico
hasta que la versión de PowerShell o la de Alpine lleguen al final de la vida útil .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

3.15

3.14

Alpine 3.15 se está probando.

PowerShell recibe soporte técnico en Alpine para las siguientes arquitecturas de


procesador.
Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64 x64 x64

PowerShell no se ha probado en Alpine con procesadores ARM.

Compatibilidad con la instalación


Microsoft admite los métodos de instalación de este documento, aunque puede haber
otros métodos de instalación disponibles desde otros orígenes de terceros. Si bien esas
herramientas y métodos pueden funcionar, Microsoft no los admite.

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Instalación de PowerShell en Debian
Artículo • 07/10/2023

Todos los paquetes están disponibles en nuestra página de versiones de GitHub.


Antes de llevar a cabo la instalación, consulte la lista de versiones admitidas a
continuación. Una vez instalado el paquete, ejecute pwsh desde un terminal. Ejecute
pwsh-preview si instaló una versión preliminar.

7 Nota

PowerShell 7.3 es una actualización local que quita las versiones anteriores de
PowerShell 7. Las versiones preliminares de PowerShell se pueden instalar en
paralelo con otras versiones de PowerShell. Si necesita ejecutar PowerShell 7.3 en
paralelo con una versión anterior, vuelva a instalar la versión anterior con el
método de archivo binario.

Debian usa APT (herramienta avanzada de paquetes) como administrador de paquetes.

Instalación en Debian 10 o 11 mediante el


repositorio de paquetes
Microsoft compila y admite una variedad de productos de software para sistemas Linux
y los pone a disposición mediante clientes de empaquetado de Linux (apt, dnf, yum,
etc.). Estos paquetes de software de Linux están alojados en el repositorio de paquetes de
Linux para productos de Microsoft, https://packages.microsoft.com , también conocido
como PMC.

La instalación de PowerShell desde PMC es el método preferido de instalación.

7 Nota

Este script solo funciona para versiones compatibles de Debian.

sh

###################################
# Prerequisites

# Update the list of packages


sudo apt-get update
# Install pre-requisite packages.
sudo apt-get install -y wget

# Get the version of Debian


source /etc/os-release

# Download the Microsoft repository GPG keys


wget -q https://packages.microsoft.com/config/debian/$VERSION_ID/packages-
microsoft-prod.deb

# Register the Microsoft repository GPG keys


sudo dpkg -i packages-microsoft-prod.deb

# Delete the the Microsoft repository GPG keys file


rm packages-microsoft-prod.deb

# Update the list of packages after we added packages.microsoft.com


sudo apt-get update

###################################
# Install PowerShell
sudo apt-get install -y powershell

# Start PowerShell
pwsh

Instalación mediante descarga directa


PowerShell 7.2 introdujo un paquete universal que facilita la instalación. Descargue el
paquete universal desde la página de versiones en la máquina Debian.

El vínculo a la versión actual es:

Paquete universal de PowerShell 7.3.7 para versiones compatibles de Debian


https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershel

l_7.3.7-1.deb_amd64.deb

Paquete universal de PowerShell 7.2.14 para versiones compatibles de Debian


https://github.com/PowerShell/PowerShell/releases/download/v7.2.14/powershe

ll-lts_7.2.14-1.deb_amd64.deb
Paquete universal de PowerShell 7.4-preview.5 para versiones compatibles de
Debian
https://github.com/PowerShell/PowerShell/releases/download/v7.4.0-

preview.5/powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

El siguiente script de shell descarga e instala la versión preliminar actual de PowerShell.


Puede cambiar la dirección URL para descargar una versión de PowerShell que desea
instalar.

sh

###################################
# Prerequisites

# Update the list of packages


sudo apt-get update

# Install pre-requisite packages.


sudo apt-get install -y wget

# Download the PowerShell package file


wget https://github.com/PowerShell/PowerShell/releases/download/v7.4.0-
preview.5/powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

###################################
# Install the PowerShell package
sudo dpkg -i powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

# Resolve missing dependencies and finish the install (if necessary)


sudo apt-get install -f

# Delete the downloaded package file


rm powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

# Start PowerShell Preview


pwsh-preview

Desinstalación de PowerShell
sh

sudo apt-get remove powershell

Rutas de acceso de PowerShell


$PSHOME es /opt/microsoft/powershell/7/ .

Los scripts de perfiles se almacenan en las siguientes ubicaciones:


AllUsersAllHosts: $PSHOME/profile.ps1
AllUsersCurrentHost: $PSHOME/Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts: ~/.config/powershell/profile.ps1
CurrentUserCurrentHost:
~/.config/powershell/Microsoft.PowerShell_profile.ps1
Los módulos se almacenan en las siguientes ubicaciones:
Módulos de usuario: ~/.local/share/powershell/Modules
Módulos compartidos: /usr/local/share/powershell/Modules
Módulos predeterminados: $PSHOME/Modules
El historial de PSReadLine se registra en
~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt

PowerShell respeta la especificación de directorio base de XDG en Linux.

Versiones compatibles
En la tabla siguiente se muestra una lista de versiones de PowerShell actualmente
compatibles y las versiones de Debian en las que se admiten. Estas versiones se seguirán
admitiendo hasta que la versión de PowerShell o la de Debian lleguen al final del ciclo
de vida .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Debian 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

11

10

PowerShell recibe soporte técnico en Debian para las siguientes arquitecturas de


procesador.

Debian 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Versión 9+ x64 x64 x64

Compatibilidad con la instalación


Microsoft admite los métodos de instalación de este documento, aunque puede haber
otros métodos de instalación disponibles desde otros orígenes de terceros. Si bien esas
herramientas y métodos pueden funcionar, Microsoft no los admite.

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Instalación de PowerShell en Red Hat
Enterprise Linux (RHEL)
Artículo • 07/10/2023

Todos los paquetes están disponibles en nuestra página de versiones de GitHub.


Antes de llevar a cabo la instalación, consulte la lista de versiones admitidas a
continuación. Una vez instalado el paquete, ejecute pwsh desde un terminal. Ejecute
pwsh-preview si instaló una versión preliminar.

7 Nota

PowerShell 7.3 es una actualización local que quita las versiones anteriores de
PowerShell 7. Las versiones preliminares de PowerShell se pueden instalar en
paralelo con otras versiones de PowerShell. Si necesita ejecutar PowerShell 7.3 en
paralelo con una versión anterior, vuelva a instalar la versión anterior con el
método de archivo binario.

RHEL 7 utiliza yum y RHEL 8 y versiones posteriores usan el administrador de paquetes


dnf .

Instalación mediante el repositorio de paquetes


Microsoft compila y admite una variedad de productos de software para sistemas Linux
y los pone a disposición mediante clientes de empaquetado de Linux (apt, dnf, yum,
etc.). Estos paquetes de software de Linux están alojados en el repositorio de paquetes de
Linux para productos de Microsoft, https://packages.microsoft.com , también conocido
como PMC.

La instalación de PowerShell desde PMC es el método preferido de instalación. Los RPM


de PowerShell aún no se publican en el repositorio de RHEL 9. Para RHEL 9, debe instalar
PowerShell mediante descarga directa.

7 Nota

Este script solo funciona para versiones compatibles de RHEL.

sh
###################################
# Prerequisites

# Get version of RHEL


source /etc/os-release
if [ $(bc<<<"$VERSION_ID < 8") = 1 ]
then majorver=7
elif [ $(bc<<<"$VERSION_ID < 9") = 1 ]
then majorver=8
else majorver=9
fi

# Register the Microsoft RedHat repository


curl -sSL -O https://packages.microsoft.com/config/rhel/$majorver/packages-
microsoft-prod.rpm

# Register the Microsoft repository keys


sudo rpm -i packages-microsoft-prod.rpm

# Delete the repository keys after installing


rm packages-microsoft-prod.rpm

# RHEL 7.x uses yum and RHEL 8+ uses dnf


if [ $(bc<<<"$majorver < 8") ]
then
# Update package index files
sudo yum update
# Install PowerShell
sudo yum install powershell -y
else
# Update package index files
sudo dnf update
# Install PowerShell
sudo dnf install powershell -y
fi

Instalación mediante descarga directa


PowerShell 7.2 introdujo un paquete universal que facilita la instalación. Descargue el
paquete universal desde la página de versiones en la máquina RHEL.

El vínculo a la versión actual es:

Paquete universal de PowerShell 7.3.7 para versiones compatibles de RHEL


https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershell-

7.3.7-1.rh.x86_64.rpm

Paquete universal de PowerShell 7.2.14 para versiones compatibles de RHEL


https://github.com/PowerShell/PowerShell/releases/download/v7.2.14/powershell-
lts-7.2.14-1.rh.x86_64.rpm

Paquete universal de PowerShell 7.4-preview.5 para versiones compatibles de RHEL


https://github.com/PowerShell/PowerShell/releases/download/v7.4.0-

preview.5/powershell-preview-7.4.0_preview.5-1.rh.x86_64.rpm

El siguiente script de shell descarga e instala la versión preliminar actual de PowerShell.


Puede cambiar la dirección URL para descargar una versión de PowerShell que desea
instalar.

En RHEL 8 o 9:

sh

sudo dnf install


https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershell
-7.3.7-1.rh.x86_64.rpm

En RHEL 7:

sh

sudo yum install


https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershell
-7.3.7-1.rh.x86_64.rpm

Desinstalación de PowerShell
En RHEL 8 o 9:

sh

sudo dnf remove powershell

En RHEL 7:

sh

sudo yum remove powershell

Compatibilidad con procesadores ARM


PowerShell 7.2 y versiones posteriores admiten la ejecución en RHEL con procesadores
ARM de 64 bits. Use el método de instalación de archivo binario para instalar
PowerShell, que se describe en Formas alternativas de instalar PowerShell en Linux.

Rutas de acceso de PowerShell


$PSHOME es /opt/microsoft/powershell/7/ .

Los scripts de perfiles se almacenan en las siguientes ubicaciones:


AllUsersAllHosts: $PSHOME/profile.ps1
AllUsersCurrentHost: $PSHOME/Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts: ~/.config/powershell/profile.ps1
CurrentUserCurrentHost:
~/.config/powershell/Microsoft.PowerShell_profile.ps1
Los módulos se almacenan en las siguientes ubicaciones:
Módulos de usuario: ~/.local/share/powershell/Modules
Módulos compartidos: /usr/local/share/powershell/Modules
Módulos predeterminados: $PSHOME/Modules
El historial de PSReadLine se registra en
~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt

PowerShell respeta la especificación de directorio base de XDG en Linux.

Versiones compatibles
En la tabla siguiente se muestra una lista de las versiones admitidas actualmente de
PowerShell y las versiones de RHEL en las que se admiten. Estas versiones se siguen
admitiendo hasta que la versión de PowerShell o la de RHEL lleguen al final del soporte
técnico .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible
RHEL 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

PowerShell recibe soporte técnico en RHEL para las siguientes arquitecturas de


procesador.

RHEL 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64 x64 x64

Compatibilidad con la instalación


Microsoft admite los métodos de instalación de este documento, aunque puede haber
otros métodos de instalación disponibles desde otros orígenes de terceros. Si bien esas
herramientas y métodos pueden funcionar, Microsoft no los admite.

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Instalación de PowerShell en Ubuntu
Artículo • 07/10/2023

Todos los paquetes están disponibles en nuestra página de versiones de GitHub.


Antes de llevar a cabo la instalación, consulte la lista de versiones admitidas a
continuación. Una vez instalado el paquete, ejecute pwsh desde un terminal. Ejecute
pwsh-preview si instaló una versión preliminar.

7 Nota

PowerShell 7.3 es una actualización local que quita las versiones anteriores de
PowerShell 7. Las versiones preliminares de PowerShell se pueden instalar en
paralelo con otras versiones de PowerShell. Si necesita ejecutar PowerShell 7.3 en
paralelo con una versión anterior, vuelva a instalar la versión anterior con el
método de archivo binario.

Ubuntu usa APT (herramienta avanzada de paquetes) como administrador de paquetes.

Instalación a través del repositorio de paquetes


del repositorio de paquetes
Microsoft compila y admite una variedad de productos de software para sistemas Linux
y los pone a disposición mediante clientes de empaquetado de Linux (apt, dnf, yum,
etc.). Estos paquetes de software de Linux están alojados en el repositorio de paquetes de
Linux para productos de Microsoft, https://packages.microsoft.com , también conocido
como PMC.

La instalación de PowerShell desde PMC es el método preferido de instalación.

7 Nota

Este script solo funciona para versiones compatibles de Ubuntu.

sh

###################################
# Prerequisites

# Update the list of packages


sudo apt-get update
# Install pre-requisite packages.
sudo apt-get install -y wget apt-transport-https software-properties-common

# Get the version of Ubuntu


source /etc/os-release

# Download the Microsoft repository keys


wget -q https://packages.microsoft.com/config/ubuntu/$VERSION_ID/packages-
microsoft-prod.deb

# Register the Microsoft repository keys


sudo dpkg -i packages-microsoft-prod.deb

# Delete the the Microsoft repository keys file


rm packages-microsoft-prod.deb

# Update the list of packages after we added packages.microsoft.com


sudo apt-get update

###################################
# Install PowerShell
sudo apt-get install -y powershell

# Start PowerShell
pwsh

Instalación mediante descarga directa


PowerShell 7.2 introdujo un paquete universal que facilita la instalación. Descargue el
paquete universal desde la página de versiones en la máquina Ubuntu.

El vínculo a la versión actual es:

Paquete universal de PowerShell 7.3.7 para versiones compatibles de Ubuntu


https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershel

l_7.3.7-1.deb_amd64.deb

Paquete universal de PowerShell 7.2.14 para versiones compatibles de Ubuntu


https://github.com/PowerShell/PowerShell/releases/download/v7.2.14/powershe

ll-lts_7.2.14-1.deb_amd64.deb
Paquete universal de PowerShell 7.4-preview.5 para versiones compatibles de
Ubuntu
https://github.com/PowerShell/PowerShell/releases/download/v7.4.0-

preview.5/powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

El siguiente script de shell descarga e instala la versión preliminar actual de PowerShell.


Puede cambiar la dirección URL para descargar una versión de PowerShell que desea
instalar.

sh

###################################
# Prerequisites

# Update the list of packages


sudo apt-get update

# Install pre-requisite packages.


sudo apt-get install -y wget

# Download the PowerShell package file


wget https://github.com/PowerShell/PowerShell/releases/download/v7.4.0-
preview.5/powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

###################################
# Install the PowerShell package
sudo dpkg -i powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

# Resolve missing dependencies and finish the install (if necessary)


sudo apt-get install -f

# Delete the downloaded package file


rm powershell-preview_7.4.0-preview.5-1.deb_amd64.deb

# Start PowerShell Preview


pwsh-preview

Desinstalación de PowerShell
sh

sudo apt-get remove powershell

Compatibilidad con procesadores ARM


PowerShell 7.2 y versiones posteriores admiten la ejecución en Ubuntu con
procesadores ARM de 32 bits. Use el método de instalación de archivo binario para
instalar PowerShell, que se describe en [Formas alternativas de instalar PowerShell en
Linux][07].

Rutas de acceso de PowerShell


$PSHOME es /opt/microsoft/powershell/7/ .

Los scripts de perfiles se almacenan en las siguientes ubicaciones:


AllUsersAllHosts: $PSHOME/profile.ps1
AllUsersCurrentHost: $PSHOME/Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts: ~/.config/powershell/profile.ps1
CurrentUserCurrentHost:
~/.config/powershell/Microsoft.PowerShell_profile.ps1

Los módulos se almacenan en las siguientes ubicaciones:


Módulos de usuario: ~/.local/share/powershell/Modules
Módulos compartidos: /usr/local/share/powershell/Modules
Módulos predeterminados: $PSHOME/Modules
El historial de PSReadLine se registra en
~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt

PowerShell respeta la especificación de directorio base de XDG en Linux.

Versiones compatibles
En la tabla siguiente se muestra una lista de las versiones de PowerShell admitidas
actualmente y las versiones de Ubuntu en las que se admiten. Estas versiones se
seguirán admitiendo hasta que la versión de PowerShell o la de Ubuntu lleguen al final
del soporte técnico .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico.
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible.

Ubuntu 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

con la versión 22.04 (LTS)

con la versión 20.04 (LTS)

con la versión 18.04 (LTS)


Solo se admiten oficialmente las versiones LTS de Ubuntu. Microsoft no ofrece soporte
técnico para las versiones provisionales ni sus equivalentes. La comunidad sí admite
las versiones provisionales. Para obtener más información, vea Distribuciones admitidas
por la comunidad.

PowerShell recibe soporte técnico en Ubuntu para las siguientes arquitecturas de


procesador.

Ubuntu 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64, Arm32 x64, Arm32 x64, Arm32

Compatibilidad con la instalación


Microsoft admite los métodos de instalación de este documento, aunque puede haber
otros métodos de instalación disponibles desde otros orígenes de terceros. Si bien esas
herramientas y métodos pueden funcionar, Microsoft no los admite.

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Soporte técnico de la comunidad para
PowerShell en Linux
Artículo • 22/09/2023

PowerShell se puede instalar en algunas distribuciones de Linux que no son compatibles


con Microsoft. En esos casos, puede encontrar soporte técnico de la comunidad para
PowerShell en esas plataformas.

Para recibir soporte técnico de Microsoft, debe cumplir los criterios siguientes:

.NET Core admite la versión y la arquitectura de la distribución.


La versión de la distribución recibirá soporte técnico durante al menos un año.
La versión de la distribución no es una versión provisional ni equivalente.
El equipo de PowerShell ha probado la versión de la distribución.

Para obtener más información, consulte la documentación del ciclo de vida del soporte
de PowerShell.

Las siguientes distribuciones reciben soporte técnico de la comunidad. Cada


distribución tiene sus propios mecanismos de soporte técnico de la comunidad.
Consulte el sitio web de la distribución para encontrar los recursos de la comunidad.
También puede obtener ayuda de estos recursos de la comunidad de PowerShell.

Versiones provisionales de Ubuntu


Los pasos documentados para instalar PowerShell en Ubuntu pueden funcionar en
versiones provisionales de Ubuntu. Sin embargo, PowerShell solo se admite en las
versiones LTS de Ubuntu. Microsoft no ofrece soporte técnico a las versiones
provisionales de Ubuntu.

Arch Linux

7 Nota

Microsoft no admite de forma oficial la compatibilidad con Arch, cuyo


mantenimiento lo realiza la comunidad.

PowerShell está disponible en el repositorio de usuario Arch Linux (AUR).


Se puede compilar con la versión etiquetada más reciente .
Se puede compilar desde la última confirmación en maestro .
Se puede instalar mediante el binario de la versión más reciente .

La comunidad mantiene los paquetes de AUR. Para más información sobre cómo
instalar paquetes desde el AUR, consulte la wiki de Arch Linux o Uso de PowerShell en
el Docker.

Kali

7 Nota

Microsoft no admite de forma oficial la compatibilidad con Kali, cuyo


mantenimiento lo realiza la comunidad.

Instalación, Kali
sh

# Install PowerShell package


apt update && apt -y install powershell

# Start PowerShell
pwsh

Desinstalación, Kali
sh

# Uninstall PowerShell package


apt -y remove powershell

Raspberry Pi OS
Sistema operativo Raspberry Pi (anteriormente Raspbian) es un sistema operativo
gratuito basado en Debian.

) Importante
.NET no se admite en dispositivos de arquitectura ARMv6, incluidos los dispositivos
Raspberry Pi Zero y Raspberry Pi anteriores a Raspberry Pi 2.

Instalación en el sistema operativo Raspberry Pi


Descargue el paquete tar.gz desde la página de versiones en el equipo Raspberry Pi. Los
vínculos a las versiones actuales son:

PowerShell 7.3.7: versión estable más reciente


https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershel
l-7.3.7-linux-arm32.tar.gz

https://github.com/PowerShell/PowerShell/releases/download/v7.3.7/powershel
l-7.3.7-linux-arm64.tar.gz

PowerShell 7.2.14: versión LTS


https://github.com/PowerShell/PowerShell/releases/download/v7.2.14/powershe

ll-7.2.14-linux-arm32.tar.gz

https://github.com/PowerShell/PowerShell/releases/download/v7.2.14/powershe
ll-7.2.14-linux-arm64.tar.gz

Use los siguientes comandos de shell para descargar e instalar el paquete. Este script
detecta si ejecuta un sistema operativo de 32 o 64 bits e instala la versión estable más
reciente de PowerShell para ese tipo de procesador.

sh

###################################
# Prerequisites

# Update package lists


sudo apt-get update

# Install dependencies
sudo apt-get install jq libssl1.1 libunwind8 -y

###################################
# Download and extract PowerShell

# Grab the latest tar.gz


bits=$(getconf LONG_BIT)
release=$(curl -sL
https://api.github.com/repos/PowerShell/PowerShell/releases/latest)
package=$(echo $release | jq -r ".assets[].browser_download_url" | grep
"linux-arm${bits}.tar.gz")
wget $package

# Make folder to put powershell


mkdir ~/powershell

# Unpack the tar.gz file


tar -xvf "./${package##*/}" -C ~/powershell

# Start PowerShell
~/powershell/pwsh

Opcionalmente, puede crear un vínculo simbólico para iniciar PowerShell sin especificar
la ruta de acceso al archivo binario pwsh .

sh

# Start PowerShell from bash with sudo to create a symbolic link


sudo ~/powershell/pwsh -command 'New-Item -ItemType SymbolicLink -Path
"/usr/bin/pwsh" -Target "$PSHOME/pwsh" -Force'

# alternatively you can run following to create a symbolic link


# sudo ln -s ~/powershell/pwsh /usr/bin/pwsh

# Now to start PowerShell you can just run "pwsh"

Desinstalación: sistema operativo Raspberry Pi


sh

rm -rf ~/powershell

6 Collaborate with us on PowerShell


GitHub
A cross-platform task automation
The source for this content can solution made up of a command-
be found on GitHub, where you line shell and a scripting language.
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Formas alternativas para instalar
PowerShell en Linux
Artículo • 28/06/2023

Todos los paquetes están disponibles en nuestra página de versiones de GitHub. Una
vez instalado el paquete, ejecute pwsh desde un terminal. Ejecute pwsh-preview si
instaló una versión preliminar.

Hay otras tres maneras de instalar PowerShell en una distribución de Linux:

Instalación mediante el paquete Snap


Instalación mediante archivos binarios
Instalación como una herramienta global de .NET

Paquete Snap
Los complementos son paquetes de aplicación fáciles de instalar, seguros,
multiplataforma y dependencias gratuitos. Los snaps se reconocen y se instalan desde el
almacén de snaps. Los paquetes Snap se admiten del mismo modo que la distribución
en la que se ejecuta el paquete.

) Importante

Snap Store contiene paquetes Snap de PowerShell para muchas distribuciones de


Linux que no son compatibles oficialmente con Microsoft. Para obtener soporte
técnico, consulte la lista de opciones de soporte técnico de la comunidad.

Obtención de snapd
snapd es necesario para ejecutar paquetes Snap. Use estas instrucciones para
asegurarse de que tiene snapd instalado.

Instalación mediante Snap


PowerShell para Linux se publica en la tienda de Snap para facilitar la instalación y las
actualizaciones.

El método preferido es el siguiente:


sh

# Install PowerShell
sudo snap install powershell --classic

# Start PowerShell
pwsh

Para instalar la versión más reciente de LTS, use el método siguiente:

sh

# Install PowerShell
sudo snap install powershell --channel=lts/stable --classic

# Start PowerShell
pwsh

Para instalar una versión preliminar, use el método siguiente:

sh

# Install PowerShell
sudo snap install powershell-preview --classic

# Start PowerShell
pwsh-preview

Después de la instalación, Snap se actualizará automáticamente. Puede desencadenar


una actualización mediante sudo snap refresh powershell o sudo snap refresh
powershell-preview .

Desinstalación
sh

sudo snap remove powershell

or

sh

sudo snap remove powershell-preview


Archivos binarios
Se proporcionan archivos binarios tar.gz de PowerShell para plataformas Linux, a fin de
permitir escenarios de implementación avanzados.

7 Nota

Puede usar este método para instalar cualquier versión de PowerShell, incluidas las
más recientes:

Versión estable: https://aka.ms/powershell-release?tag=stable


Versión de LTS: https://aka.ms/powershell-release?tag=lts
Versión preliminar: https://aka.ms/powershell-release?tag=preview

Dependencias
PowerShell compila archivos binarios portátiles para todas las distribuciones de Linux.
Aun así, el entorno de ejecución de .NET Core requiere dependencias diferentes en otras
distribuciones, y PowerShell también.

Al instalar PowerShell, es posible que las dependencias específicas no estén instaladas,


como cuando se realiza la instalación manual desde archivos binarios. En la lista
siguiente se detallan las distribuciones de Linux que son compatibles con Microsoft y
que contienen dependencias que es posible que deba instalar. Consulte la página de la
distribución para obtener más información:

Alpine
Debian
RHEL
SLES
Ubuntu

Para implementar archivos binarios de PowerShell en distribuciones de Linux que no se


admiten oficialmente, debe instalar las dependencias necesarias para el sistema
operativo de destino en varios pasos. Por ejemplo, nuestro dockerfile de Amazon
Linux instala primero las dependencias y, después, extrae el archivo tar.gz de Linux.

Instalación mediante un archivo binario

) Importante
Este método se puede usar para instalar PowerShell en cualquier versión de Linux,
incluidas las distribuciones no reciben soporte técnico oficial de Microsoft.
Asegúrese de instalar las dependencias necesarias. Para obtener soporte técnico,
consulte la lista de opciones de soporte técnico de la comunidad.

En el ejemplo siguiente se muestran los pasos para instalar el archivo binario x64. Debe
elegir el archivo binario correcto que coincida con el tipo de procesador de la
plataforma.

powershell-7.3.5-linux-arm32.tar.gz

powershell-7.3.5-linux-arm64.tar.gz
powershell-7.3.5-linux-x64.tar.gz

Use los siguientes comandos de shell para descargar e instalar PowerShell desde el
archivo binario tar.gz . Cambie la dirección URL para que coincida con la versión de
PowerShell que desea instalar.

sh

# Download the powershell '.tar.gz' archive


curl -L -o /tmp/powershell.tar.gz
https://github.com/PowerShell/PowerShell/releases/download/v7.3.5/powershell
-7.3.5-linux-x64.tar.gz

# Create the target folder where powershell will be placed


sudo mkdir -p /opt/microsoft/powershell/7

# Expand powershell to the target folder


sudo tar zxf /tmp/powershell.tar.gz -C /opt/microsoft/powershell/7

# Set execute permissions


sudo chmod +x /opt/microsoft/powershell/7/pwsh

# Create the symbolic link that points to pwsh


sudo ln -s /opt/microsoft/powershell/7/pwsh /usr/bin/pwsh

Desinstalación de archivos binarios


sh

sudo rm -rf /usr/bin/pwsh /opt/microsoft/powershell


Instalación como una herramienta global de
.NET
Si ya tiene instalado el SDK de .NET Core, es fácil instalar PowerShell como una
herramienta global de .NET.

sh

dotnet tool install --global PowerShell

El instalador de la herramienta dotnet agrega ~/.dotnet/tools a la variable de entorno


PATH . Sin embargo, el shell que se está ejecutando actualmente no tiene
PATH actualizado. Debe poder iniciar PowerShell desde un nuevo shell escribiendo pwsh .
Instalación de PowerShell en macOS
Artículo • 20/10/2023

PowerShell 7.0 o posteriores requiere macOS 10.13 y versiones posteriores. Todos los
paquetes están disponibles en nuestra página de versiones de GitHub. Una vez
instalado el paquete, ejecute pwsh desde un terminal. Antes de llevar a cabo la
instalación, consulte la lista de versiones admitidas a continuación.

7 Nota

PowerShell 7.3 es una actualización local que quita las versiones anteriores de
PowerShell 7. Las versiones preliminares de PowerShell se pueden instalar en
paralelo con otras versiones de PowerShell. Si necesita ejecutar PowerShell 7.3 en
paralelo con una versión anterior, vuelva a instalar la versión anterior con el
método de archivo binario.

Instalación de la versión estable más reciente


de PowerShell
Existen varias maneras de instalar PowerShell en macOS. Elija uno de los métodos
siguientes:

Realice la instalación mediante Homebrew . Homebrew es el administrador de


paquetes preferido de macOS.
Realice la instalación de PowerShell mediante descarga directa.
Realice la instalación a partir de archivos binarios.

Si no se encuentra el comando brew , debe instalar Homebrew según sus


instrucciones .

Bash

/bin/bash -c "$(curl -fsSL


https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

Una vez instalado brew podrá instalar PowerShell.

El siguiente comando instala la versión estable más reciente de PowerShell:

sh
brew install powershell/tap/powershell

Por último, compruebe que la instalación funciona correctamente:

sh

pwsh

Cuando se publiquen nuevas versiones de PowerShell, actualice PowerShell y las


fórmulas de Homebrew:

sh

brew update
brew upgrade powershell

7 Nota

Los comandos anteriores pueden llamarse desde un host de PowerShell (pwsh),


pero, acto seguido, el shell de PowerShell se debe cerrar y volver a iniciar para
finalizar la actualización y actualizar los valores que aparecen en $PSVersionTable .

Instalación de la versión preliminar más


reciente de PowerShell
Una vez instalado Homebrew, puede instalar PowerShell.

sh

brew install powershell/tap/powershell-preview

Ejecute el siguiente comando para iniciar la versión preliminar de PowerShell:

sh

pwsh-preview

Cuando se publiquen nuevas versiones de PowerShell, actualice PowerShell y las


fórmulas de Homebrew:
sh

brew update
brew upgrade powershell-preview

7 Nota

Los comandos anteriores pueden llamarse desde dentro de un host de PowerShell


(pwsh), pero, en este caso, es necesario salir y reiniciar el shell de PowerShell para
completar la actualización. y actualice los valores mostrados en $PSVersionTable .

Instalación de la versión más reciente de LTS de


PowerShell
sh

brew install powershell/tap/powershell-lts

Ahora puede comprobar la instalación.

sh

pwsh

Cuando se publiquen nuevas versiones de PowerShell, ejecute el siguiente comando.

sh

brew upgrade powershell-lts

7 Nota

Si usa el método Cask o TAP, al actualizar a una versión más reciente de PowerShell,
use el mismo método que para instalar PowerShell inicialmente. Si usa otro
método, al abrir una nueva sesión de pwsh seguirá usando la versión anterior de
PowerShell.

Si decide usar métodos diferentes, hay formas de corregir el problema con el


método de vínculo de Homebrew .
Instalación mediante descarga directa
A partir de la versión 7.2, PowerShell admite el procesador M1 de Apple. Descargue el
paquete de instalación desde la página de versiones en el equipo. Los vínculos a las
versiones actuales son:

PowerShell 7.3.8
Procesadores x64: powershell-7.3.8-osx-x64.pkg
Procesadores M1: powershell-7.3.8-osx-arm64.pkg
PowerShell 7.2.15 (LTS)
Procesadores x64: powershell-7.2.15-osx-x64.pkg
Procesadores M1: powershell-7.2.15-osx-arm64.pkg

Puede hacer doble clic en el archivo y seguir las indicaciones, o bien instalarlo desde el
terminal mediante los siguientes comandos. Cambie el nombre del archivo para que
coincida con el archivo que ha descargado.

sh

sudo installer -pkg powershell-7.3.8-osx-x64.pkg -target /

Si usa macOS Big Sur 11.5 o una versión posterior, es posible que reciba el mensaje de
error siguiente al instalar el paquete:

"powershell-7.3.8-osx-x64.pkg" no se puede abrir porque Apple no puede


comprobar si contiene software malintencionado.

Hay dos formas de evitar este problema:

Uso de Finder

1. Busque el paquete en Finder.


2. Haga clic con la tecla Control pulsada en el paquete.
3. Seleccione Abrir en el menú contextual.

Desde la línea de comandos

1. Ejecute sudo xattr -rd com.apple.quarantine powershell-7.3.8-osx-x64.pkg . Si


usa PowerShell 7 o superior, puede usar el cmdlet Unblock-File . Incluya la ruta de
acceso completa al archivo .pkg .
2. Instale el paquete como lo haría normalmente.

7 Nota
Se trata de un problema conocido relacionado con la certificación de paquetes que
se solucionará en el futuro.

Instalación como una herramienta global de


.NET
Si ya tiene instalado el SDK de .NET Core, es fácil instalar PowerShell como una
herramienta global de .NET.

dotnet tool install --global PowerShell

El instalador de la herramienta dotnet agrega ~/.dotnet/tools a la variable de entorno


PATH . Sin embargo, el shell que se ejecuta actualmente no tiene PATH actualizado. Debe

poder iniciar PowerShell desde un nuevo shell escribiendo pwsh .

Archivos binarios
Se proporcionan archivos binarios tar.gz de PowerShell para la plataforma macOS, a fin
de permitir escenarios de implementación avanzados. Al realizar la instalación con este
método, también debe instalar manualmente las dependencias.

7 Nota

Puede usar este método para instalar cualquier versión de PowerShell, incluidas las
más recientes:

Versión estable: https://aka.ms/powershell-release?tag=stable


Versión de LTS: https://aka.ms/powershell-release?tag=lts
Versión preliminar: https://aka.ms/powershell-release?tag=preview

Instalación de archivos binarios en macOS


Descargue el paquete de instalación desde la página de versiones en el equipo. Los
vínculos a las versiones actuales son:

PowerShell 7.3.8
Procesadores x64: powershell-7.3.8-osx-x64.tar.gz
Procesadores M1: powershell-7.3.8-osx-arm64.tar.gz
PowerShell 7.2.15
Procesadores x64: powershell-7.2.15-osx-x64.tar.gz
Procesadores M1: powershell-7.2.15-osx-arm64.tar.gz

Use los siguientes comandos para instalar PowerShell desde el archivo binario. Cambie
la dirección URL de descarga para que coincida con la versión que quiere instalar.

sh

# Download the powershell '.tar.gz' archive


curl -L -o /tmp/powershell.tar.gz
https://github.com/PowerShell/PowerShell/releases/download/v7.3.8/powershell
-7.3.8-osx-x64.tar.gz

# Create the target folder where powershell is placed


sudo mkdir -p /usr/local/microsoft/powershell/7.3.8

# Expand powershell to the target folder


sudo tar zxf /tmp/powershell.tar.gz -C /usr/local/microsoft/powershell/7.3.8

# Set execute permissions


sudo chmod +x /usr/local/microsoft/powershell/7.3.8/pwsh

# Create the symbolic link that points to pwsh


sudo ln -s /usr/local/microsoft/powershell/7.3.8/pwsh /usr/local/bin/pwsh

Desinstalación de PowerShell
Si ha instalado PowerShell con Homebrew, use el siguiente comando para desinstalar:

sh

brew uninstall --cask powershell

Si ha instalado PowerShell mediante descarga directa, deberá quitar PowerShell


manualmente:

sh

sudo rm -rf /usr/local/bin/pwsh /usr/local/microsoft/powershell

Para quitar las rutas de acceso de PowerShell adicionales, consulte la sección de rutas de
acceso de este documento y elimine las rutas de acceso deseadas mediante sudo rm .
7 Nota

Este paso no es necesario si ha realizado la instalación con Homebrew.

Rutas de acceso
$PSHOME es /usr/local/microsoft/powershell/7.3.8/ .

Los perfiles de usuario se leerán de ~/.config/powershell/profile.ps1


Los perfiles predeterminados se leerán de $PSHOME/profile.ps1
Los módulos de usuario se leerán de ~/.local/share/powershell/Modules
Los módulos compartidos se leerán de /usr/local/share/powershell/Modules
Los módulos predeterminados se leerán de $PSHOME/Modules
El historial de PSReadLine se registrará en
~/.local/share/powershell/PSReadLine/ConsoleHost_history.txt .

Los perfiles respetan la configuración por host de PowerShell. Así que el perfil
predeterminado específico del host está en Microsoft.PowerShell_profile.ps1 en las
mismas ubicaciones.

PowerShell respeta la especificación de directorio base de XDG en macOS.

Dado que macOS es una derivación de BSD, se usa el prefijo /usr/local en lugar de
/opt . Por lo tanto, $PSHOME es /usr/local/microsoft/powershell/7.3.8/ , y el vínculo

simbólico se coloca en /usr/local/bin/pwsh .

Versiones compatibles
La tabla siguiente contiene una lista de versiones de PowerShell y el estado de
compatibilidad con versiones de macOS. Estas versiones se seguirán admitiendo hasta
que la versión de macOS o la de PowerShell llegue al final del soporte técnico.

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

macOS 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

con Big Sur 11.5

macOS 12 (Monterey) y macOS 13 (Ventura) no se han probado.

Apple define la compatibilidad con macOS. Para más información, consulte:

Notas de la versión de macOS


Actualizaciones de seguridad de Apple

PowerShell recibe soporte técnico en macOS para las siguientes arquitecturas de


procesador:

macOS 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

macOS Big Sur 11.5 x64, Arm64 x64, Arm64 x64, Arm64

Compatibilidad con la instalación


Microsoft admite los métodos de instalación de este documento, aunque puede haber
otros disponibles desde otros orígenes. Si bien esas herramientas y métodos pueden
funcionar, Microsoft no los admite.

Recursos adicionales
Homebrew Web
Repositorio GitHub de Homebrew
Homebrew-Cask

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue

 Provide product feedback


more information, see our
contributor guide.
PowerShell en procesadores ARM
Artículo • 13/04/2023

La compatibilidad con el procesador ARM se basa en la directiva de compatibilidad de la


versión de .NET que usa PowerShell. Aunque .NET admite muchos más sistemas
operativos y versiones, la compatibilidad con PowerShell se limita a las versiones que se
han probado.

Puede ser posible usar versiones basadas en ARM de PowerShell en otras distribuciones
y versiones de Linux, pero no se admite oficialmente.

PowerShell 7.3
PowerShell 7.3 se basa en la directiva de ciclo de vida del sistema operativo compatible
con .NET Core 7.0 y admite las siguientes plataformas:

SO Arquitecturas Ciclo de vida

Windows 11 versión de cliente 22000+ Arm64 Windows

Windows 10 versión de cliente 1607+ Arm64 Windows

macOS 10.15+ Arm64 macOS

Sistema operativo Raspberry Pi ARM32 Sistema operativo Raspberry Pi y


(Debian 10) Debian

Ubuntu 22.04, 20.04, 18.04: ARM32 Ubuntu

PowerShell 7.2
PowerShell 7.2 se basa en la directiva de ciclo de vida del sistema operativo compatible
con .NET Core 6.0 y admite las siguientes plataformas:

SO Arquitecturas Ciclo de vida

Windows 11 versión de cliente 22000+ Arm64 Windows

Windows 10 versión de cliente 1607+ Arm64 Windows

macOS 10.14+ Arm64 macOS

Sistema operativo Raspberry Pi ARM32 Sistema operativo Raspberry Pi y


(Debian 10) Debian
SO Arquitecturas Ciclo de vida

Ubuntu 22.04, 20.04, 18.04 ARM32 Ubuntu

Instalación de PowerShell Core en sistemas


basados en ARM
Para obtener instrucciones sobre la instalación, vea los artículos siguientes:

Windows

Windows 10 en ARM
Windows 10 IoT Enterprise
Windows 10 IoT Core

Linux: instalación desde los archivos binarios

Formas alternativas para instalar PowerShell en Linux

macOS

Instalación de PowerShell en macOS

Raspbery Pi

Raspberry Pi OS
Uso de PowerShell en el Docker
Artículo • 28/06/2023

Publicamos imágenes de Docker con PowerShell preinstalado. En este artículo se


muestra cómo empezar a usar PowerShell en el contenedor de Docker.

Búsqueda de imágenes disponibles


Las imágenes publicadas requieren Docker 17.05 o una versión más reciente. También
podría ejecutar Docker sin sudo ni derechos administrativos locales. Siga las
instrucciones oficiales de Docker para instalar docker correctamente.

Los contenedores de versión proceden de la imagen de distribución oficial, luego


instalan las dependencias y, por último, el paquete de PowerShell.

Estos contenedores residen en hub.docker.com/r/microsoft/powershell .

Para obtener más información sobre estas imágenes de Docker, visite el repositorio
PowerShell-Docker en GitHub.

Uso de PowerShell en un contenedor


En los pasos siguientes se muestran los comandos de Docker necesarios para descargar
la imagen e iniciar una sesión interactiva de PowerShell.

Consola

docker run -it mcr.microsoft.com/powershell

Eliminación de la imagen cuando ya no se necesite


El siguiente comando se usa para eliminar la imagen de Docker cuando ya no se
necesita.

Consola

docker rmi mcr.microsoft.com/powershell

Información legal y licencias


PowerShell se publica en virtud de la licencia de MIT .

Licencias de archivos e imágenes de Docker de Windows


Al solicitar y usar la imagen del sistema operativo de contenedor para los contenedores
de Windows, usted comprende y acepta los términos de licencia complementarios
disponibles en Docker Hub:

Windows Server Core


Nano Server

Telemetría
De forma predeterminada, PowerShell recopila datos de telemetría limitados sin
información de identificación personal para ayudar a desarrollar versiones futuras de
PowerShell. Si no quiere participar en el envío de telemetría, cree una variable de
entorno llamada POWERSHELL_TELEMETRY_OPTOUT establecida en un valor de 1 antes de
iniciar PowerShell desde la ubicación de instalación. Puede consultar qué telemetría
recopilamos en la declaración de privacidad de Microsoft .
Preguntas más frecuentes sobre
Microsoft Update para PowerShell
Preguntas más frecuentes

A partir de PowerShell 7.2, cuando realice la instalación mediante el paquete MSI, tendrá
la opción de habilitar la compatibilidad de Microsoft Update con PowerShell.

Información general
¿Qué es la característica Microsoft Update de
PowerShell?
La característica Microsoft Update de PowerShell permite recibir las actualizaciones más
recientes de PowerShell 7 en el flujo de administración tradicional de Microsoft Update
(MU), ya sea con Windows Update para empresas, WSUS, Microsoft Endpoint
Configuration Manager o el cuadro de diálogo interactivo de MU en Configuración.
Microsoft Update y los servicios relacionados permiten implementar actualizaciones:

Según la programación
Después de realizar pruebas para el entorno
A gran escala en toda la empresa

¿Cuánto tiempo después del lanzamiento


Microsoft Update anuncia las actualizaciones?
Cuando se lanza una versión nueva de PowerShell, esa versión puede tardar hasta dos
semanas en estar disponible a través de Microsoft Update. Las actualizaciones se
entregan como actualizaciones de software opcionales, incluso si incluyen alguna
corrección de seguridad.

Si necesita implementar la actualización antes de que esté disponible en Microsoft


Update, descargue la actualización desde la página Versiones en GitHub.

Tengo PowerShell 7.2, ¿por qué no se ha


actualizado a la versión 7.3?
La característica Microsoft Update para PowerShell solo actualiza versiones en el mismo
canal de versión. PowerShell 7.2 es la versión compatible a largo plazo más reciente
(LTS). PowerShell 7.3 es la versión estable más reciente (no LTS). Microsoft Update
efectúa la actualización automática a las siguientes versiones de nivel de revisión para
las versiones 7.2 y 7.3. Por ejemplo, 7.2.x a 7.2.y y 7.3.x a 7.3.y. Para obtener más
información sobre los ciclos de vida de soporte técnico, consulte Ciclo de vida de
soporte técnico de PowerShell.

Configuración
¿Qué versión de Windows se necesita para
admitir la característica Microsoft Update?
Debe tener Windows, versión 1709 (10.0.16299) o posterior, instalado en un sistema
basado en x64. La versión 1709 es la actualización Windows 10 Fall Creators Update o la
actualización de octubre de Windows Server 2016. Las versiones anteriores a la
versión 1709 no admiten Microsoft Update para PowerShell.

¿Es necesario activar ambas casillas en el cuadro


de diálogo de configuración?
Si bien las dos opciones del cuadro de diálogo son independientes, en la mayoría de los
casos es mejor activar ambas casillas.
¿Qué hace cada casilla?
La primera casilla habilita las actualizaciones de PowerShell. Estas actualizaciones se
pueden entregar mediante Microsoft Update, un servidor WSUS o SCCM. Si esta casilla
está desactivada, no podrá recibir actualizaciones a través de ninguno de estos canales.

La segunda casilla habilita Microsoft Update en el sistema. Esto le permite recibir


actualizaciones de cualquier software compatible de Microsoft, no solo de Windows. Si
la casilla está desactivada, no recibirá la actualización de Microsoft Update, pero sí
podrá recibir actualizaciones de WSUS o SCCM.

¿Qué ocurre si más adelante quiero dejar de


recibir las actualizaciones?
Si más adelante quiere dejar de recibir las actualizaciones, puede ejecutar el paquete de
instalación MSI y desactivar la primera casilla. Desactivar la segunda casilla no tiene
ningún efecto.
¿Puedo habilitar estas opciones de actualización
desde la línea de comandos o en un script?
Sí. El paquete MSI incluye dos opciones de MSI nuevas para habilitar las características
de actualización:

USE_MU : esta propiedad tiene dos valores posibles:


1 (valor predeterminado): permite realizar las actualizaciones mediante

Microsoft Update, WSUS o SCCM


0 : no permite realizar la actualización mediante Microsoft Update, WSUS o SCCM

ENABLE_MU

1 (valor predeterminado): permite usa Microsoft Update para las

actualizaciones automáticas
0 : no permite utilizar Microsoft Update

7 Nota

La configuración ENABLE_MU=0 no deshabilita Microsoft Update.

Solución de problemas
No he recibido ninguna actualización para la
versión nueva. ¿Por qué no?
Puede haber varios motivos por los cuales no recibe la actualización:

Es posible que aún no hayamos publicado la actualización. Tenemos como objetivo


que la actualización esté disponible para Microsoft Update dos semanas después
del lanzamiento, pero no hay ninguna garantía de esa disponibilidad.

Hay configuraciones de directiva de grupo que controlan Microsoft Update. El


administrador del sistema puede tener directivas establecidas que le impiden usar
Microsoft Update. Activar la casilla del instalador no invalida la directiva de grupo.

Asegúrese de haber activado ambas casillas. Al realizar una instalación de


reparación, el instalador no muestra las opciones de casilla. Para habilitar las
actualizaciones de MU, ejecute el siguiente comando:

PowerShell
msiexec.exe /fmu .\PowerShell-7.3.8-win-x64.msi USE_MU=1 ENABLE_MU=1

Para obtener más información sobre cómo ejecutar msiexec.exe desde la línea de
comandos, consulte msiexec.

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Introducción
Artículo • 13/04/2023

Este contenido apareció originalmente en el libro PowerShell 101 de Mike F. Robbins.


Agradecemos a Mike que nos haya concedido permiso para reutilizar su contenido aquí.
El contenido se ha editado a partir de la publicación original. Puede obtener el libro
original desde Leanpub en PowerShell 101 .

¿A quién va dirigido este libro?


Se trata de un libro introductorio para cualquiera que quiera aprender a usar
PowerShell.

Este libro se centra en la versión 5.1 de PowerShell que se ejecuta en Windows 10 y


Windows Server 2016 en un entorno de dominio de Microsoft Active Directory. Sin
embargo, los conceptos básicos se aplican a todas las versiones de PowerShell que se
ejecutan en cualquier plataforma compatible.

Acerca de este libro


Este libro es una colección de lo que me gustaría que alguien me hubiera dicho cuando
empecé a usar PowerShell, junto con las sugerencias, los trucos y los procedimientos
recomendados que he aprendido al usar PowerShell durante los últimos 10 años.

En lugar de proporcionar una enorme cantidad de información, este libro intenta ofrecer
la suficiente información de utilidad para alguien que se está iniciando en PowerShell.
Cada capítulo contiene vínculos a temas de ayuda concretos para aquellos que quieran
obtener más información sobre los temas tratados en ese capítulo.

Acerca del autor


Mike F. Robbins es un antiguo Microsoft MVP, coautor de Windows PowerShell TFM 4th
Edition y uno de los autores del libro PowerShell Deep Dives. Mike ha sido un gran
colaborador de la comunidad de PowerShell y ahora es el redactor jefe de Azure
PowerShell en Microsoft. Blog en mikefrobbins.com y se puede encontrar en twitter
@mikefrobbins .

Entorno de laboratorio
Los ejemplos de este libro se diseñaron y probaron en Windows 10 Anniversary Edition
(compilación 1607) y Windows Server 2016 con PowerShell versión 5.1. Si usa otra
versión de PowerShell o del sistema operativo, los resultados pueden diferir de los
presentados aquí.
Capítulo 1: Introducción a PowerShell
Artículo • 13/04/2023

A menudo, veo que los presentadores de conferencias y reuniones de grupos de


usuarios ya tienen PowerShell en ejecución cuando empiezan sus presentaciones de
nivel básico. Este libro empieza por responder a las preguntas que los asistentes que no
han usado PowerShell anteriormente preguntan en ese tipo de sesiones.

En concreto, este capítulo se centra en la búsqueda y el inicio de PowerShell, así como


en resolver algunos de los problemas iniciales que experimentan los nuevos usuarios de
PowerShell. No olvide seguir los ejemplos que se muestran en este capítulo en el equipo
del entorno de laboratorio de Windows 10.

¿Qué es necesario para comenzar a usar


PowerShell?
Todas las versiones modernas de los sistemas operativos Windows se incluyen con
PowerShell instalado. Si está ejecutando una versión anterior a la 5.1, debe instalar la
versión más reciente.

Para actualizar a Windows PowerShell 5.1, consulte Actualización de Windows


PowerShell existente.
Para instalar la versión más reciente de PowerShell, consulte Instalación de
PowerShell.

¿Dónde puedo encontrar PowerShell?


La forma más fácil de encontrar PowerShell en Windows 10 es escribir PowerShell en la
barra de búsqueda, tal como se muestra en la ilustración 1-1.
Observe que en la ilustración 1-1 se muestran cuatro accesos directos diferentes para
PowerShell. El equipo que se usa con fines de demostración en este libro ejecuta la
versión de 64 bits de Windows 10, por lo que hay una versión de 64 bits de la consola
de PowerShell y PowerShell ISE (entorno de scripting integrado) y una versión de 32 bits
de cada una, tal y como se indica mediante el sufijo (x86) en los accesos directos. Si está
ejecutando una versión de 32 bits de Windows 10, solo tendrá dos accesos directos.
Esos elementos no tienen el sufijo (x86), pero son versiones de 32 bits. Si tiene un
sistema operativo de 64 bits, mi recomendación es ejecutar la versión de 64 bits de
PowerShell a menos que tenga un motivo concreto para ejecutar la versión de 32 bits.

Para obtener información sobre cómo iniciar PowerShell en otras versiones de Windows,
consulte Inicio de Windows PowerShell.

¿Cómo puedo iniciar PowerShell?


En los entornos empresariales de producción a los que doy soporte, utilizo tres cuentas
de usuario de Active Directory diferentes. He reflejado esas cuentas en el entorno de
laboratorio que se usa en este libro. Inicio sesión en el equipo con Windows 10 como un
usuario de dominio que no es un administrador local o de dominio.

Para iniciar la consola de PowerShell, he hecho clic en el acceso directo "Windows


PowerShell", tal como se muestra en la ilustración 1-1.

Observe que la barra de título de la consola de PowerShell indica "Windows PowerShell",


tal como se muestra en la ilustración 1-4. Algunos comandos se ejecutan correctamente,
pero PowerShell no puede participar en el Control de cuentas de usuario (UAC). Esto
significa que no puede solicitar la elevación para las tareas que requieren la aprobación
de un administrador. Se genera un mensaje de error que indica lo siguiente:

PowerShell

Get-Service -Name W32Time | Stop-Service

Output

Stop-Service : Service 'Windows Time (W32Time)' cannot be stopped due to the


following
error: Cannot open W32Time service on computer '.'.
At line:1 char:29
+ Get-Service -Name W32Time | Stop-Service
+
+ CategoryInfo : CloseError:
(System.ServiceProcess.ServiceController:ServiceController)
[Stop-Service], ServiceCommandException
+ FullyQualifiedErrorId :
CouldNotStopService,Microsoft.PowerShell.Commands.StopServiceCommand

La solución a este problema es ejecutar PowerShell como un usuario de dominio que


sea un administrador local. De esta forma se configura mi segunda cuenta de usuario de
dominio. Con el principio de privilegios mínimos, esta cuenta NO debe ser un
administrador de dominio o tener privilegios elevados en el dominio.

Cierre PowerShell. Vuelva a iniciar la consola de PowerShell, pero esta vez haga clic con
el botón derecho en el acceso directo Windows PowerShell y seleccione Ejecutar como
administrador, tal como se muestra en la ilustración 1-5.
Si ha iniciado sesión en Windows como un usuario normal, se le pedirán las
credenciales. Escribiré las credenciales de la cuenta de usuario que es un usuario de
dominio y un administrador local, tal como se muestra en la ilustración 1-6.
Una vez que PowerShell se ha reiniciado como administrador, la barra de título indicará
"Administrador: Windows PowerShell", tal como se muestra en la ilustración 1-7.

Ahora que PowerShell se está ejecutando con privilegios elevados como administrador
local, UAC dejará de ser un problema cuando se ejecute un comando en el equipo local
que normalmente requeriría una solicitud de elevación de privilegios. Tenga en cuenta
que cualquier comando que se ejecute desde esta instancia con privilegios elevados de
la consola de PowerShell también se ejecutará con privilegios elevados.

Para simplificar la búsqueda de PowerShell y su inicio como administrador, recomiendo


anclarlo a la barra de tareas y configurarlo para que se inicie automáticamente como
administrador cada vez que se ejecute.

Vuelva a buscar PowerShell, pero esta vez haga clic con el botón derecho en él y
seleccione "Anclar a la barra de tareas", tal como se muestra en la ilustración 1-8.
Haga clic con el botón derecho en el acceso directo de PowerShell que ahora está
anclado a la barra de tareas y seleccione las propiedades como se muestra en la
ilustración 1-9.

Haga clic en "Avanzado", tal como se indica en el n.º 1 de la ilustración 1-10, marque la
casilla "Ejecutar como administrador" como se indica el n.º 2 de la ilustración 1-10 y,
finalmente, haga clic en Aceptar dos veces para aceptar los cambios y salir de ambos
cuadros de diálogo.
Nunca más tendrá que volver a preocuparse de buscar PowerShell o de si se está
ejecutando como administrador.

Ejecutar PowerShell con privilegios elevados como administrador para evitar problemas
con UAC solo afecta a los comandos que se ejecutan en el equipo local. No tiene ningún
efecto en los comandos que tienen como destino equipos remotos.

¿Qué versión de PowerShell estoy usando?


Hay varias variables automáticas en PowerShell que almacenan información de estado.
Una de estas variables es $PSVersionTable , que contiene una tabla hash que se puede
usar para mostrar la información de versión de PowerShell pertinente:

PowerShell

$PSVersionTable

Output
Name Value
---- -----
PSVersion 5.1.19041.1
PSEdition Desktop
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
BuildVersion 10.0.19041.1
CLRVersion 4.0.30319.42000
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1

Las versiones más recientes de Windows PowerShell se distribuyen como parte de


Windows Management Framework (WMF). Se requiere una versión concreta de .NET
Framework en función de la versión de WMF. Para actualizar a Windows PowerShell 5.1,
consulte Actualización de Windows PowerShell existente.

Directiva de ejecución
Contrariamente a lo que la mayoría de usuarios cree, la directiva de ejecución en
PowerShell no es un límite de seguridad. Se ha diseñado para evitar que un usuario
ejecute un script sin saberlo. Un usuario resuelto puede omitir fácilmente la directiva de
ejecución en PowerShell. En la tabla 1-2 se muestra la directiva de ejecución
predeterminada para los sistemas operativos Windows actuales.

Versión del sistema operativo Windows Directiva de ejecución predeterminada

Server 2019 Remota firmada

Server 2016 Remota firmada

Windows 10 Restringido

Independientemente de la configuración de la directiva de ejecución, cualquier


comando de PowerShell puede ejecutarse de forma interactiva. La directiva de ejecución
solo afecta a los comandos que se ejecutan en un script. El cmdlet Get-ExecutionPolicy
se usa para determinar cuál es la configuración de la directiva de ejecución actual y el
cmdlet Set-ExecutionPolicy se usa para cambiar la directiva de ejecución. Mi
recomendación es usar la directiva RemoteSigned, que requiere que los scripts
descargados estén firmados por un editor de confianza para poder ejecutarse.

Consulte la directiva de ejecución actual:

PowerShell
Get-ExecutionPolicy

Output

Restricted

Los scripts de PowerShell no se pueden ejecutar en absoluto cuando la directiva de


ejecución está establecida en Restricted. Esta es la configuración predeterminada en
todos los sistemas operativos de cliente de Windows. Para mostrar el problema, guarde
el código siguiente como un .ps1 archivo con nombre Stop-TimeService.ps1 .

PowerShell

Get-Service -Name W32Time | Stop-Service -PassThru

Ese comando se ejecuta de forma interactiva sin errores, siempre que PowerShell se
ejecute con privilegios elevados como administrador. Pero en cuanto se guarda como
un archivo de script e intenta ejecutar el script, se genera un error:

PowerShell

.\Stop-TimeService.ps1

Output

.\Stop-TimeService.ps1 : File C:\demo\Stop-TimeService.ps1 cannot be loaded


because
running scripts is disabled on this system. For more information, see
about_Execution_Policies at http://go.microsoft.com/fwlink/?LinkID=135170.
At line:1 char:1
+ .\Stop-TimeService.ps1
+
+ CategoryInfo : SecurityError: (:) [], PSSecurityException
+ FullyQualifiedErrorId : UnauthorizedAccess

Observe que el error que se muestra en el conjunto de resultados anterior indica


exactamente cuál es el problema (la ejecución de scripts está deshabilitada en este
sistema). Al ejecutar un comando en PowerShell que genera un mensaje de error,
asegúrese de leer el mensaje de error en lugar de simplemente volver a ejecutar el
comando y esperar que se ejecute correctamente.

Cambie la directiva de ejecución de PowerShell a remota firmada.


PowerShell

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned

Output

Execution Policy Change


The execution policy helps protect you from scripts that you do not trust.
Changing the execution
policy might expose you to the security risks described in the
about_Execution_Policies help topic
at http://go.microsoft.com/fwlink/?LinkID=135170. Do you want to change the
execution policy?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is
"N"):y

Asegúrese de leer la advertencia que se muestra al cambiar la directiva de ejecución.


También recomiendo echar un vistazo al tema de ayuda about_Execution_Policies para
asegurarse de que comprende las implicaciones de seguridad de cambiar la directiva de
ejecución.

Ahora que la directiva de ejecución se ha establecido en RemoteSigned, el script Stop-


TimeService.ps1 se ejecuta sin errores.

PowerShell

.\Stop-TimeService.ps1

Output

Status Name DisplayName


------ ---- -----------
Stopped W32Time Windows Time

Asegúrese de iniciar el servicio Hora de Windows antes de continuar; de lo contrario,


puede que se produzcan problemas imprevistos.

PowerShell

Start-Service -Name w32time

Resumen
En este capítulo, ha aprendido a buscar e iniciar PowerShell, así como a crear un acceso
directo que inicia PowerShell como administrador. También ha obtenido información
acerca de la directiva de ejecución predeterminada y cómo cambiarla.

Revisar
1. ¿Cómo puede determinar qué versión de PowerShell está ejecutando un equipo?
2. ¿Por qué es importante iniciar PowerShell con privilegios elevados como
administrador?
3. ¿Cómo puede determinar la directiva de ejecución actual de PowerShell?
4. ¿Qué impide que ocurra la directiva de ejecución predeterminada de PowerShell
en los equipos cliente de Windows?
5. ¿Cómo puede cambiar la directiva de ejecución de PowerShell?

Lecturas recomendadas
Para aquellos que deseen obtener más información acerca de los temas que se abordan
en este capítulo, recomiendo leer los siguientes temas de ayuda de PowerShell.

about_Automatic_Variables
about_Hash_Tables
about_Execution_Policies

En el siguiente capítulo, obtendrá información sobre la detectabilidad de los comandos


de PowerShell. Uno de los aspectos que se abordarán es cómo actualizar PowerShell
para que los temas de ayuda se puedan ver directamente desde PowerShell en lugar de
tener que verlos en Internet.
Capítulo 2: Sistema de ayuda
Artículo • 13/04/2023

Se proporcionó una prueba escrita sin acceso a un equipo a dos grupos de


profesionales de TI para determinar su nivel de conocimientos de PowerShell. Los
principiantes de PowerShell se ubicaron en un grupo y los expertos, en otro. Según los
resultados de la prueba, no pareció haber mucha diferencia en el nivel de conocimientos
entre ambos grupos. A ambos grupos se les proporcionó una segunda prueba similar a
la primera. En esta ocasión, se les dio acceso a un equipo con PowerShell que no tenía
acceso a Internet. Los resultados de la segunda prueba mostraron una gran diferencia
en el nivel de conocimientos entre ambos grupos. Los expertos no siempre conocen las
respuestas, pero saben cómo averiguarlas.

¿Cuál fue la diferencia en los resultados de la primera y la segunda prueba entre estos
dos grupos?

Las diferencias observadas en estas dos pruebas se debieron a que los expertos no
memorizan cómo usar miles de comandos en PowerShell. En cambio, aprenden a usar
muy bien el sistema de ayuda de PowerShell. Esto les permite encontrar los comandos
necesarios cuando los necesitan y cómo usarlos una vez que los han encontrado.

He escuchado a Jeffrey Snover, el inventor de PowerShell, referirse a casos similares en


numerosas ocasiones.

Dominar el sistema de ayuda es la clave para utilizar PowerShell correctamente.

Detectabilidad
Los comandos compilados en PowerShell se denominan cmdlets. Se pronuncia
"command-let" (y no "CMD-let"). Los nombres de los cmdlets tienen la forma de
comandos "verbo-sustantivo" singulares para poder descubrirlos con facilidad. Por
ejemplo, el cmdlet para determinar qué procesos se están ejecutando es Get-Process y
el cmdlet para recuperar una lista de servicios y sus estados es Get-Service . Hay otros
tipos de comandos en PowerShell, tales como alias y funciones, que se tratarán más
adelante en este libro. El término comando de PowerShell es un término genérico que
se suele usar para hacer referencia a cualquier tipo de comando de PowerShell,
independientemente de si se trata de un cmdlet, una función o un alias.

Los tres cmdlets principales de PowerShell


Get-Command

Get-Help
Get-Member (se aborda en el capítulo 3)

Una pregunta que se me plantea con frecuencia es cómo se averigua qué son los
comandos en PowerShell. Tanto Get-Command como Get-Help se pueden usar para
determinar los comandos.

Get-Help
Get-Help es un comando multipropósito. Get-Help le ayuda a aprender a usar

comandos una vez que los haya encontrado. Get-Help también se puede usar para
facilitar la búsqueda de comandos, pero de una forma diferente y más indirecta en
comparación con Get-Command .

Cuando Get-Help se usa para buscar comandos, primero busca coincidencias con
caracteres comodín de los nombres de comando en función de la entrada
proporcionada. Si no encuentra ninguna coincidencia, busca en los temas de ayuda y, si
tampoco se encuentra ninguna coincidencia, se devuelve un error. Al contrario de lo que
la mayoría de usuarios creen, Get-Help se puede usar para buscar comandos que no
tienen temas de ayuda.

Lo primero que necesita saber sobre el sistema de ayuda de PowerShell es cómo usar el
cmdlet Get-Help . El siguiente comando se usa para mostrar el tema de ayuda de Get-
Help .

PowerShell

Get-Help -Name Get-Help

Output

Do you want to run Update-Help?


The Update-Help cmdlet downloads the most current Help files for Windows
PowerShell
modules, and installs them on your computer. For more information about the
Update-Help
cmdlet, see http://go.microsoft.com/fwlink/?LinkId=210614.
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"):

A partir de la versión 3 de PowerShell, la ayuda de PowerShell no se distribuye con el


sistema operativo. La primera vez que se ejecuta Get-Help para buscar un comando, se
muestra el mensaje anterior. Si usa la función help o el alias man en lugar del cmdlet
Get-Help , no recibirá este mensaje.

Al responder afirmativamente presionando Y , se ejecuta el cmdlet Update-Help , que


requiere acceso a Internet de forma predeterminada. Y se puede especificar en
mayúsculas o en minúsculas.

Una vez que se ha descargado la ayuda y se ha completado la actualización, se devuelve


el tema de ayuda para el comando especificado:

PowerShell

Get-Help -Name Get-Help

Dedique un momento a ejecutar ese ejemplo en el equipo, revise el resultado y tome


nota del modo en que se agrupa la información:

NAME
SINOPSIS
SINTAXIS
DESCRIPTION
VÍNCULOS RELACIONADOS
COMENTARIOS

Como puede ver, los temas de ayuda pueden contener una cantidad enorme de
información, y esto no es ni siquiera el tema de ayuda completo.

Si bien no es específico de PowerShell, los parámetros son una forma de proporcionar la


entrada a un comando. Get-Help tiene muchos parámetros que se pueden especificar
para devolver el tema de ayuda completo o un subconjunto de él.

La sección sintaxis del tema de ayuda que se muestra en el conjunto anterior de


resultados muestra todos los parámetros de Get-Help . A primera vista, parece que los
mismos parámetros aparecen seis veces diferentes. Cada uno de esos bloques
diferentes de la sección de sintaxis es un conjunto de parámetros. Esto significa que el
cmdlet Get-Help tiene seis conjuntos de parámetros diferentes. Si echa un vistazo con
más detenimiento, observará que al menos un parámetro es diferente en cada uno de
los conjuntos de parámetros.

Los conjuntos de parámetros se excluyen mutuamente. Una vez que se usa un


parámetro único que solo existe en uno de los conjuntos de parámetros, solo se pueden
usar los parámetros incluidos en ese conjunto de parámetros. Por ejemplo, los
parámetros Full y Detailed no se podrían especificar al mismo tiempo porque se
encuentran en conjuntos de parámetros diferentes.

Cada uno de los parámetros siguientes se encuentra en un conjunto de parámetros


diferente:

Completo
Detallado
Ejemplos
En línea
Parámetro
ShowWindow

Toda la sintaxis críptica, como, por ejemplo, los corchetes angulares y cuadrados de la
sección de sintaxis, significa algo, pero se abordará en el Apéndice A de este libro. Si
bien es importante, conocer cuál es la sintaxis críptica a menudo es difícil de recordar
para un usuario que no está familiarizado con PowerShell y que puede que no lo utilice
a diario.

Para obtener más información para comprender mejor la sintaxis críptica, consulte el
Apéndice A.

En el caso de los principiantes, hay una manera más fácil de averiguar la misma
información, salvo en lenguaje sin formato.

Cuando se especifica el parámetro Full de Get-Help , se devuelve todo el tema de ayuda.

PowerShell

Get-Help -Name Get-Help -Full

Dedique un momento a ejecutar ese ejemplo en el equipo, revise el resultado y tome


nota del modo en que se agrupa la información:

NAME
SINOPSIS
SINTAXIS
DESCRIPTION
PARAMETERS
ENTRADAS
SALIDAS
NOTAS
EJEMPLOS
VÍNCULOS RELACIONADOS

Tenga en cuenta que el uso del parámetro Full devolvió varias secciones adicionales,
una de las cuales es la sección PARÁMETROS, que proporciona más información que la
sección SINTAXIS críptica.

El parámetro Full es un parámetro de modificador. Un parámetro que no requiere un


valor se denomina parámetro de modificador. Cuando se especifica un parámetro de
modificador, su valor es true y, cuando no se especifica, su valor es false.

Si ha estado trabajando en este capítulo en la consola de PowerShell, habrá observado


que el comando anterior para mostrar el tema de ayuda completo de Get-Help
desapareció de la pantalla sin darle la oportunidad de leerlo. Hay una forma mejor de
realizar esto.

Help es una función que canaliza Get-Help en una función denominada more , que es un
contenedor del archivo ejecutable more.com en Windows. En la consola de PowerShell,
help proporciona las páginas de ayuda de una en una. En el ISE, funciona de la misma
manera que Get-Help . Mi recomendación es usar la función help en lugar del cmdlet
Get-Help , ya que proporciona una mejor experiencia y no requiere escribir tanto.

Sin embargo, escribir menos no siempre es bueno. Si va a guardar los comandos como
un script o va a compartirlos con otro usuario, asegúrese de usar los nombres de
parámetro y cmdlet completos. Los nombres completos se autodocumentan, lo que
facilita su comprensión. Piense en la siguiente persona que va a tener que leer y
entender los comandos. Podría ser usted. Sus compañeros de trabajo y usted mismo se
lo agradecerán.

Intente ejecutar los siguientes comandos en la consola de PowerShell en el equipo del


entorno de laboratorio de Windows 10.

PowerShell

Get-Help -Name Get-Help -Full


help -Name Get-Help -Full
help Get-Help -Full

¿Ha observado alguna diferencia en la salida de los comandos enumerados


anteriormente al ejecutarlos en el equipo del entorno de laboratorio de Windows 10?

No hay ninguna diferencia excepto el hecho que las dos últimas opciones devuelven los
resultados en una página cada vez. La barra espaciadora se usa para mostrar la siguiente
página de contenido al usar la función Help y Ctrl + C cancela los comandos que se
están ejecutando en la consola de PowerShell.

En el primer ejemplo, se usa el cmdlet Get-Help ; en el segundo, se usa la función Help ;


y, en el tercero, se omite el parámetro Name al usar la función Help . Name es un
parámetro posicional y se utiliza de forma posicional en ese ejemplo. Esto significa que
el valor se puede especificar sin especificar el nombre del parámetro, siempre que el
valor se especifique en la posición correcta. ¿Cómo sé en qué posición se debe
especificar el valor? Leyendo la ayuda como se muestra en el ejemplo siguiente.

PowerShell

help Get-Help -Parameter Name

Output

-Name <String>
Gets help about the specified command or concept. Enter the name of a
cmdlet, function,
provider, script, or workflow, such as Get-Member, a conceptual article
name, such as
about_Objects, or an alias, such as ls. Wildcard characters are
permitted in cmdlet and
provider names, but you can't use wildcard characters to find the names
of function help and
script help articles.

To get help for a script that isn't located in a path that's listed in
the $env:Path
environment variable, type the script's path and file name.

If you enter the exact name of a help article, Get-Help displays the
article contents.

If you enter a word or word pattern that appears in several help article
titles, Get-Help
displays a list of the matching titles.

If you enter a word that doesn't match any help article titles, Get-Help
displays a list of
articles that include that word in their contents.

The names of conceptual articles, such as about_Objects, must be entered


in English, even in
non-English versions of PowerShell.

Required? false
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName)
Accept wildcard characters? true

Tenga en cuenta que, en el ejemplo anterior, el parámetro Parameter se usó con la


función Help para devolver únicamente información del tema de ayuda asociado con el
parámetro Name. Esto es mucho más conciso que intentar examinar manualmente lo
que a veces parece un tema de ayuda de cien páginas.

En función de esos resultados, puede ver que el parámetro Name es posicional y debe
especificarse en la posición cero (la primera posición) cuando se usa de forma
posicional. El orden en que se especifican los parámetros no importa si se especifica el
nombre del parámetro.

Otro dato importante es que el parámetro Name espera que el tipo de datos de su valor
sea una sola cadena, que se indica mediante <String> . Si aceptase varias cadenas, el
tipo de datos se enumeraría como <String[]> .

En ocasiones, puede que no desee mostrar el tema de ayuda completo de un comando.


Hay algunos otros parámetros además de Full que se pueden especificar con Get-Help
o Help . Intente ejecutar los siguientes comandos en el equipo del entorno de
laboratorio de Windows 10:

PowerShell

Get-Help -Name Get-Command -Full


Get-Help -Name Get-Command -Detailed
Get-Help -Name Get-Command -Examples
Get-Help -Name Get-Command -Online
Get-Help -Name Get-Command -Parameter Noun
Get-Help -Name Get-Command -ShowWindow

Normalmente, uso help <command name> con el parámetro Full u Online. Si solo me
interesan los ejemplos, usaré el parámetro Examples y, si solo me interesa un parámetro
específico, usaré el parámetro Parameter. El parámetro ShowWindow abre el tema de
ayuda en una ventana independiente utilizable en búsquedas que se puede colocar en
un monitor diferente si tiene varios monitores. He evitado el parámetro ShowWindow
porque existe un error conocido en el que no muestra el tema de ayuda completo.

Si desea obtener ayuda en una ventana independiente, mi recomendación es usar el


parámetro Online o usar el parámetro Full y canalizar los resultados a Out-GridView , tal
como se muestra en el ejemplo siguiente.

PowerShell
help Get-Command -Full | Out-GridView

Tanto el cmdlet Out-GridView como el parámetro ShowWindow del cmdlet Get-Help


requieren un sistema operativo con una GUI (interfaz gráfica de usuario). Generarán un
mensaje de error si intenta usarlos en una instancia de Windows Server que se instaló
con la opción de instalación Server Core (no-GUI).

Para usar Get-Help para buscar comandos, use el carácter comodín de asterisco ( * ) con
el parámetro Name. Especifique un término para el que esté buscando comandos como
valor para el parámetro Name, tal como se muestra en el ejemplo siguiente.

PowerShell

help *process*

Output

Name Category Module


Synopsis
---- -------- ------ ------
--
Enter-PSHostProcess Cmdlet Microsoft.PowerShell.Core
Connects to and ...
Exit-PSHostProcess Cmdlet Microsoft.PowerShell.Core Closes
an intera...
Get-PSHostProcessInfo Cmdlet Microsoft.PowerShell.Core
Debug-Process Cmdlet Microsoft.PowerShell.M... Debugs
one or mo...
Get-Process Cmdlet Microsoft.PowerShell.M... Gets
the process...
Start-Process Cmdlet Microsoft.PowerShell.M... Starts
one or mo...
Stop-Process Cmdlet Microsoft.PowerShell.M... Stops
one or mor...
Wait-Process Cmdlet Microsoft.PowerShell.M... Waits
for the pr...
Get-AppvVirtualProcess Function AppvClient ...
Start-AppvVirtualProcess Function AppvClient ...

En el ejemplo anterior, los caracteres comodín * no son necesarios y, si se omiten, se


produce el mismo resultado. Get-Help agrega automáticamente los caracteres comodín
en segundo plano.

PowerShell

help process
El comando anterior produce los mismos resultados que si se especifica el carácter
comodín * en cada extremo del proceso.

Prefiero agregarlos, ya que es la opción que siempre funciona de forma coherente. De lo


contrario, solo se requieren en determinados escenarios. En cuanto se agrega un
carácter comodín en el centro del valor, ya no se agregan automáticamente en segundo
plano al valor especificado.

PowerShell

help pr*cess

Ese comando no devuelve ningún resultado a menos que se agregue el carácter


comodín * al principio, al final o al principio y al final de pr*cess .

Si el valor que especificó comienza con un guión, se genera un error porque PowerShell
lo interpreta como un nombre de parámetro y no existe ese nombre de parámetro para
el cmdlet Get-Help .

PowerShell

help -process

Si lo que está intentando buscar son comandos que finalizan con -process , solo tiene
que agregar el carácter comodín * al principio del valor.

PowerShell

help *-process

Al buscar comandos de PowerShell con Get-Help , querrá ser un poco más abstracto en
lugar de ser demasiado específico con lo que está buscando.

La búsqueda de process antes solo encontró comandos que contenían process en el


nombre del comando y devolvió solo esos resultados. Cuando se usa Get-Help para
buscar processes , no encuentra ninguna coincidencia con los nombres de comando,
por lo que realiza una búsqueda de todos los temas de ayuda de PowerShell en el
sistema y devuelve todas las coincidencias que encuentra. Esto hace que devuelva un
número enorme de resultados.

PowerShell
Get-Help processes

Output

Name Category Module


Synopsis
---- -------- ------ ------
--
Disconnect-PSSession Cmdlet Microsoft.PowerShell.Core
Disconnects from...
Enter-PSHostProcess Cmdlet Microsoft.PowerShell.Core
Connects to and ...
ForEach-Object Cmdlet Microsoft.PowerShell.Core
Performs an oper...
Get-PSSessionConfiguration Cmdlet Microsoft.PowerShell.Core Gets
the registe...
New-PSTransportOption Cmdlet Microsoft.PowerShell.Core
Creates an objec...
Out-Host Cmdlet Microsoft.PowerShell.Core Sends
output to ...
Where-Object Cmdlet Microsoft.PowerShell.Core
Selects objects ...
Clear-Variable Cmdlet Microsoft.PowerShell.U...
Deletes the valu...
Compare-Object Cmdlet Microsoft.PowerShell.U...
Compares two set...
Convert-String Cmdlet Microsoft.PowerShell.U...
Formats a string...
ConvertFrom-Csv Cmdlet Microsoft.PowerShell.U...
Converts object ...
ConvertTo-Html Cmdlet Microsoft.PowerShell.U...
Converts Microso...
ConvertTo-Xml Cmdlet Microsoft.PowerShell.U...
Creates an XML-b...
Debug-Runspace Cmdlet Microsoft.PowerShell.U... Starts
an intera...
Export-Csv Cmdlet Microsoft.PowerShell.U...
Converts objects...
Export-FormatData Cmdlet Microsoft.PowerShell.U... Saves
formatting...
Format-List Cmdlet Microsoft.PowerShell.U...
Formats the outp...
Format-Table Cmdlet Microsoft.PowerShell.U...
Formats the outp...
Get-Random Cmdlet Microsoft.PowerShell.U... Gets a
random nu...
Get-Unique Cmdlet Microsoft.PowerShell.U...
Returns unique i...
Group-Object Cmdlet Microsoft.PowerShell.U... Groups
objects t...
Import-Clixml Cmdlet Microsoft.PowerShell.U...
Imports a CLIXML...
Import-Csv Cmdlet Microsoft.PowerShell.U...
Creates table-li...
Measure-Object Cmdlet Microsoft.PowerShell.U...
Calculates the n...
Out-File Cmdlet Microsoft.PowerShell.U... Sends
output to ...
Out-GridView Cmdlet Microsoft.PowerShell.U... Sends
output to ...
Select-Object Cmdlet Microsoft.PowerShell.U...
Selects objects ...
Set-Variable Cmdlet Microsoft.PowerShell.U... Sets
the value o...
Sort-Object Cmdlet Microsoft.PowerShell.U... Sorts
objects by...
Tee-Object Cmdlet Microsoft.PowerShell.U... Saves
command ou...
Trace-Command Cmdlet Microsoft.PowerShell.U...
Configures and s...
Write-Output Cmdlet Microsoft.PowerShell.U... Sends
the specif...
Debug-Process Cmdlet Microsoft.PowerShell.M... Debugs
one or mo...
Get-Process Cmdlet Microsoft.PowerShell.M... Gets
the process...
Get-WmiObject Cmdlet Microsoft.PowerShell.M... Gets
instances o...
Start-Process Cmdlet Microsoft.PowerShell.M... Starts
one or mo...
Stop-Process Cmdlet Microsoft.PowerShell.M... Stops
one or mor...
Wait-Process Cmdlet Microsoft.PowerShell.M... Waits
for the pr...
Get-Counter Cmdlet Microsoft.PowerShell.D... Gets
performance...
Invoke-WSManAction Cmdlet Microsoft.WSMan.Manage...
Invokes an actio...
Remove-WSManInstance Cmdlet Microsoft.WSMan.Manage...
Deletes a manage...
Get-WSManInstance Cmdlet Microsoft.WSMan.Manage...
Displays managem...
New-WSManInstance Cmdlet Microsoft.WSMan.Manage...
Creates a new in...
Set-WSManInstance Cmdlet Microsoft.WSMan.Manage...
Modifies the man...
about_Arithmetic_Operators HelpFile
Describes the op...
about_Arrays HelpFile
Describes arrays...
about_Debuggers HelpFile
Describes the Wi...
about_Execution_Policies HelpFile
Describes the Wi...
about_ForEach-Parallel HelpFile
Describes the Fo...
about_Foreach HelpFile
Describes a lang...
about_Functions HelpFile
Describes how to...
about_Language_Keywords HelpFile
Describes the ke...
about_Methods HelpFile
Describes how to...
about_Objects HelpFile
Provides essenti...
about_Parallel HelpFile
Describes the Pa...
about_Pipelines HelpFile
Combining comman...
about_Preference_Variables HelpFile
Variables that c...
about_Remote HelpFile
Describes how to...
about_Remote_Output HelpFile
Describes how to...
about_Sequence HelpFile
Describes the Se...
about_Session_Configuration_Files HelpFile
Describes sessio...
about_Variables HelpFile
Describes how va...
about_Windows_PowerShell_5.0 HelpFile
Describes new fe...
about_WQL HelpFile
Describes WMI Qu...
about_WS-Management_Cmdlets HelpFile
Provides an over...
about_ForEach-Parallel HelpFile
Describes the Fo...
about_Parallel HelpFile
Describes the Pa...
about_Sequence HelpFile
Describes the Se...

El uso de Help para buscar process devolvió 10 resultados y su uso para buscar
processes devolvió 68 resultados. Si solo se encuentra un resultado, se mostrará el tema

de ayuda en lugar de una lista de comandos.

PowerShell

get-help *hotfix*

Output

NAME
Get-HotFix
SYNOPSIS
Gets the hotfixes that have been applied to the local and remote
computers.

SYNTAX
Get-HotFix [-ComputerName <String[]>] [-Credential <PSCredential>] [-
Description
<String[]>] [<CommonParameters>]

Get-HotFix [[-Id] <String[]>] [-ComputerName <String[]>] [-Credential


<PSCredential>] [<CommonParameters>]

DESCRIPTION
The Get-Hotfix cmdlet gets hotfixes (also called updates) that have been
installed
on either the local computer (or on specified remote computers) by
Windows Update,
Microsoft Update, or Windows Server Update Services; the cmdlet also
gets hotfixes
or updates that have been installed manually by users.

RELATED LINKS
Online Version: http://go.microsoft.com/fwlink/?LinkId=821586
Win32_QuickFixEngineering http://go.microsoft.com/fwlink/?LinkID=145071
Get-ComputerRestorePoint
Add-Content

REMARKS
To see the examples, type: "get-help Get-HotFix -examples".
For more information, type: "get-help Get-HotFix -detailed".
For technical information, type: "get-help Get-HotFix -full".
For online help, type: "get-help Get-HotFix -online"

Ahora vamos a derribar el mito que Help de PowerShell solo puede encontrar
comandos que tienen temas de ayuda.

PowerShell

help *more*

Output

NAME
more

SYNTAX
more [[-paths] <string[]>]
ALIASES
None

REMARKS
None

Observe en el ejemplo anterior que more no tiene un tema de ayuda, pero el sistema
Help de PowerShell fue capaz de encontrarlo. Solo encontró una coincidencia y devolvió

la información de sintaxis básica que verá cuando un comando no tenga un tema de


ayuda.

PowerShell contiene numerosos temas de ayuda conceptuales (acerca de). El siguiente


comando se puede usar para devolver una lista de todos los temas de ayuda Acerca de
del sistema.

PowerShell

help About_*

Limitar los resultados a un único tema de ayuda Acerca de muestra el tema de ayuda en
lugar de devolver una lista.

PowerShell

help about_Updatable_Help

El sistema de ayuda de PowerShell debe actualizarse para que los temas de ayuda
Acerca de estén presentes. Si, por alguna razón, se produjo un error en la actualización
inicial del sistema de ayuda en el equipo, los archivos no estarán disponibles hasta que
el cmdlet Update-Help se haya ejecutado correctamente.

Get-Command
Get-Command está diseñado para ayudarle a localizar comandos. Al ejecutar Get-Command

sin ningún parámetro, se devuelve una lista de todos los comandos del sistema. En el
ejemplo siguiente se muestra cómo usar el cmdlet Get-Command para determinar qué
comandos existen para trabajar con procesos:

PowerShell

Get-Command -Noun Process


Output

CommandType Name Version


Source
----------- ---- -------
------
Cmdlet Debug-Process 3.1.0.0
Microsof...
Cmdlet Get-Process 3.1.0.0
Microsof...
Cmdlet Start-Process 3.1.0.0
Microsof...
Cmdlet Stop-Process 3.1.0.0
Microsof...
Cmdlet Wait-Process 3.1.0.0
Microsof...

Observe que, en el ejemplo anterior, en el que se ejecutó Get-Command , se usa el


parámetro Noun y se especifica Process como el valor del parámetro Noun. ¿Qué
ocurre si no sabe cómo usar el cmdlet Get-Command ? Puede usar Get-Help para mostrar
el tema de ayuda de Get-Command .

Los parámetros Name, Noun y Verb aceptan caracteres comodín. En el ejemplo


siguiente se muestran los caracteres comodín que se usan con el parámetro Name:

PowerShell

Get-Command -Name *service*

Output

CommandType Name Version


Source
----------- ---- -------
------
Function Get-NetFirewallServiceFilter 2.0.0.0
NetSecurity
Function Set-NetFirewallServiceFilter 2.0.0.0
NetSecurity
Cmdlet Get-Service 3.1.0.0
Microsof...
Cmdlet New-Service 3.1.0.0
Microsof...
Cmdlet New-WebServiceProxy 3.1.0.0
Microsof...
Cmdlet Restart-Service 3.1.0.0
Microsof...
Cmdlet Resume-Service 3.1.0.0
Microsof...
Cmdlet Set-Service 3.1.0.0
Microsof...
Cmdlet Start-Service 3.1.0.0
Microsof...
Cmdlet Stop-Service 3.1.0.0
Microsof...
Cmdlet Suspend-Service 3.1.0.0
Microsof...
Application AgentService.exe
10.0.14... C:\Windo...
Application SensorDataService.exe
10.0.14... C:\Windo...
Application services.exe
10.0.14... C:\Windo...
Application services.msc 0.0.0.0
C:\Windo...
Application TieringEngineService.exe
10.0.14... C:\Windo...

No me gusta mucho usar caracteres comodín con el parámetro Name de Get-Command ,


ya que también devuelve archivos ejecutables que no son comandos nativos de
PowerShell.

Si va a utilizar caracteres comodín con el parámetro Name, recomiendo limitar los


resultados con el parámetro CommandType.

PowerShell

Get-Command -Name *service* -CommandType Cmdlet, Function, Alias

Una opción mejor es usar el parámetro Verb o Noun o ambos, ya que solo los
comandos de PowerShell tienen tanto verbos como sustantivos.

¿Ha encontrado algún problema con un tema de ayuda? La buena noticia es que los
temas de ayuda de PowerShell son de código abierto y están disponibles en el
repositorio PowerShell-Docs de GitHub. Puede compensarlo no solo corrigiendo la
información incorrecta para usted, sino también para todos los demás usuarios. Solo
tiene que bifurcar el repositorio de documentación de PowerShell de GitHub, actualizar
el tema de ayuda y enviar una solicitud de incorporación de cambios. Una vez aceptada
la solicitud de incorporación de cambios, la documentación corregida estará disponible
para todo el mundo.

Actualización de la Ayuda
La actualización anterior de la copia local de los temas de ayuda de PowerShell se
produjo la primera vez que se solicitó ayuda en relación con un comando. Se
recomienda actualizar periódicamente el sistema de ayuda, ya que de vez en cuando
puede haber actualizaciones en el contenido de la ayuda. El cmdlet Update-Help se usa
para actualizar los temas de ayuda. Requiere acceso a Internet de forma predeterminada
y que se ejecute PowerShell con privilegios elevados como administrador.

PowerShell

Update-Help

Output

Update-Help : Failed to update Help for the module(s) 'BitsTransfer' with UI


culture(s)
{en-US} : Unable to retrieve the HelpInfo XML file for UI culture en-US.
Make sure the HelpInfoUri
property in the module manifest is valid or check your network connection
and then try the command again.
At line:1 char:1
+ Update-Help
+
+ CategoryInfo : InvalidOperation: (:) [Update-Help], Exception
+ FullyQualifiedErrorId :
InvalidHelpInfoUri,Microsoft.PowerShell.Commands.UpdateHel
pCommand

Update-Help : Failed to update Help for the module(s)


'NetworkControllerDiagnostics,
StorageReplica' with UI culture(s) {en-US} : Unable to retrieve the HelpInfo
XML file
for UI culture en-US. Make sure the HelpInfoUri property in the module
manifest is valid
or check your network connection and then try the command again.
At line:1 char:1
+ Update-Help
+
+ CategoryInfo : ResourceUnavailable: (:) [Update-Help],
Exception
+ FullyQualifiedErrorId :
UnableToRetrieveHelpInfoXml,Microsoft.PowerShell.Commands.
UpdateHelpCommand

Un par de módulos devolvieron errores, lo que no es raro. Si el equipo no tiene acceso a


Internet, puede usar el cmdlet Save-Help en otro equipo que tenga acceso a Internet
para guardar primero la información de ayuda actualizada en un recurso compartido de
archivos de la red y, a continuación, usar el parámetro SourcePath de Update-Help para
especificar esta ubicación de red para los temas de ayuda.
Considere la posibilidad de configurar una tarea programada o de agregar lógica a su
script de perfil de PowerShell para actualizar periódicamente el contenido de la ayuda
en el equipo. Los scripts de perfil se abordarán en un capítulo disponible próximamente.

Resumen
En este capítulo ha aprendido a buscar comandos con Get-Help y Get-Command . Ha
aprendido a usar el sistema de ayuda para averiguar cómo usar los comandos una vez
que los encuentra. También ha aprendido a actualizar el contenido de los temas de
ayuda cuando hay actualizaciones disponibles.

Le reto a que aprenda un comando de PowerShell cada día.

PowerShell

Get-Command | Get-Random | Get-Help -Full

Revisar
1. ¿El parámetro DisplayName de Get-Service es posicional?
2. ¿Cuántos conjuntos de parámetros tiene el cmdlet Get-Process ?
3. ¿Qué comandos de PowerShell existen para trabajar con registros de eventos?
4. ¿Qué comando de PowerShell se debe usar para devolver una lista de los procesos
de PowerShell que se ejecutan en el equipo?
5. ¿Cómo actualiza el contenido de la ayuda de PowerShell que está almacenado en
el equipo?

Lecturas recomendadas
Si desea obtener más información acerca de los temas que se abordan en este capítulo,
recomiendo leer los siguientes temas de ayuda de PowerShell.

Get-Help
Get-Command
Update-Help
Save-Help
about_Updatable_Help
about_Command_Syntax
En el siguiente capítulo, obtendrá información sobre el cmdlet Get-Member , así como los
objetos, las propiedades y los métodos.
Capítulo 3: Detección de objetos,
propiedades y métodos
Artículo • 13/04/2023

Mi primer contacto con un equipo fue con un Commodore 64, pero el primero moderno
que tuve fue un clon de IBM 286 a 12 MHz con 1 megabyte de memoria, una unidad de
disco duro de 40 megabytes y una unidad de disquete de 5 1/4 pulgadas con un
monitor CGA que ejecutaba Microsoft DOS 3.3.

Muchos profesionales de TI, como yo mismo, no son extraños a la línea de comandos,


pero cuando aparece el asunto de objetos, propiedades y métodos, obtienen el ciervo
en los faros y dicen: "No soy desarrollador". ¿Supongo qué? Resulta que no hace falta
ser desarrollador para usar PowerShell y hacerlo bien. Que nadie se deje confundir por
la terminología. Puede que sea un poco confuso al principio, pero, después de obtener
un poco de experiencia práctica, habrá momentos en los que todo de repente comienza
a tener sentido. "¡Claro! A eso se refería el libro".

Es recomendable probar los ejemplos en el equipo para obtener un poco de esa


experiencia práctica.

Requisitos
Algunos de los ejemplos que se muestran en este capítulo requieren el módulo Active
Directory PowerShell. El módulo forma parte de las Herramientas de administración
remota del servidor (RSAT) para Windows. Para la compilación 1809 (o posterior) de
Windows, las herramientas de RSAT se instalan como una característica de Windows. La
compatibilidad con Active Directory no está disponible en Windows Home.

Para obtener información sobre cómo instalar las herramientas de RSAT, consulte
Módulos de administración de Windows.
Para versiones anteriores de Windows, consulte RSAT para Windows .

Get-Member
Get-Member ayuda a detectar qué objetos, propiedades y métodos están disponibles

para los comandos. Cualquier comando que produzca una salida basada en objetos se
puede canalizar a Get-Member . Una propiedad es una característica de un elemento. Los
permisos de conducir tienen una propiedad, "nombre", cuyos valores podrían ser
Beatriz, Cristina, David o Pedro, por ejemplo. Un método es una acción que se puede
realizar en un elemento. Siguiendo con el ejemplo de los permisos de conducir, uno de
los métodos sería "revocar", ya que hay diferentes entidades gubernamentales que
pueden revocarlos.

Propiedades
En el siguiente ejemplo, voy a recuperar información sobre el servicio de Hora de
Windows que se ejecuta en mi equipo.

PowerShell

Get-Service -Name w32time

Output

Status Name DisplayName


------ ---- -----------
Running w32time Windows Time

Status, Name y DisplayName son ejemplos de propiedades, tal como se muestra en el


conjunto de resultados anterior. El valor de la propiedad Status es Running , el valor de
la propiedad Name es w32time y el valor de DisplayName es Windows Time .

Ahora canalizaré ese comando a Get-Member :

PowerShell

Get-Service -Name w32time | Get-Member

Output

TypeName: System.ServiceProcess.ServiceController

Name MemberType Definition


---- ---------- ----------
Name AliasProperty Name = ServiceName
RequiredServices AliasProperty RequiredServices =
ServicesDependedOn
Disposed Event System.EventHandler
Disposed(System.Object, Sy...
Close Method void Close()
Continue Method void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef
CreateObjRef(ty...
Dispose Method void Dispose(), void
IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object
InitializeLifetimeService()
Pause Method void Pause()
Refresh Method void Refresh()
Start Method void Start(), void Start(string[]
args)
Stop Method void Stop()
WaitForStatus Method void
WaitForStatus(System.ServiceProcess.Servi...
CanPauseAndContinue Property bool CanPauseAndContinue {get;}
CanShutdown Property bool CanShutdown {get;}
CanStop Property bool CanStop {get;}
Container Property System.ComponentModel.IContainer
Container {get;}
DependentServices Property
System.ServiceProcess.ServiceController[] Depe...
DisplayName Property string DisplayName {get;set;}
MachineName Property string MachineName {get;set;}
ServiceHandle Property
System.Runtime.InteropServices.SafeHandle Serv...
ServiceName Property string ServiceName {get;set;}
ServicesDependedOn Property
System.ServiceProcess.ServiceController[] Serv...
ServiceType Property System.ServiceProcess.ServiceType
ServiceType ...
Site Property System.ComponentModel.ISite Site
{get;set;}
StartType Property
System.ServiceProcess.ServiceStartMode StartTy...
Status Property
System.ServiceProcess.ServiceControllerStatus ...
ToString ScriptMethod System.Object ToString();

La primera línea de los resultados en el ejemplo anterior contiene información muy


importante. TypeName indica qué tipo de objeto se devolvió. Se devolvió un objeto
System.ServiceProcess. ServiceController en este ejemplo. Esto a menudo se abrevia
como la parte de TypeName justo después del último punto; en este ejemplo sería
ServiceController.

Una vez que se sepa el tipo de objeto que produce un comando, se puede utilizar esta
información para buscar comandos que acepten ese tipo de objeto como entrada.

PowerShell

Get-Command -ParameterType ServiceController


Output

CommandType Name Version


Source
----------- ---- -------
------
Cmdlet Get-Service 3.1.0.0
Microsof...
Cmdlet Restart-Service 3.1.0.0
Microsof...
Cmdlet Resume-Service 3.1.0.0
Microsof...
Cmdlet Set-Service 3.1.0.0
Microsof...
Cmdlet Start-Service 3.1.0.0
Microsof...
Cmdlet Stop-Service 3.1.0.0
Microsof...
Cmdlet Suspend-Service 3.1.0.0
Microsof...

Todos esos comandos tienen un parámetro que acepta un tipo de objeto


ServiceController por canalización, entrada de parámetro o ambos.

Observe que hay más propiedades que las que se muestran de forma predeterminada.
Aunque estas propiedades adicionales no se muestran de forma predeterminada, se
pueden seleccionar de la canalización canalizando el comando al cmdlet Select-Object
y usando el parámetro Property. En el ejemplo siguiente se seleccionan todas las
propiedades canalizando los resultados de Get-Service a Select-Object y
especificando el carácter comodín * como valor para el parámetro Property.

PowerShell

Get-Service -Name w32time | Select-Object -Property *

Output

Name : w32time
RequiredServices : {}
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
DisplayName : Windows Time
DependentServices : {}
MachineName : .
ServiceName : w32time
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

También se pueden seleccionar propiedades específicas mediante una lista separada por
comas para el valor del parámetro Property.

PowerShell

Get-Service -Name w32time | Select-Object -Property Status, Name,


DisplayName, ServiceType

Output

Status Name DisplayName ServiceType


------ ---- ----------- -----------
Running w32time Windows Time Win32ShareProcess

De forma predeterminada, se devuelven cuatro propiedades en una tabla y se devuelven


cinco o más en una lista. Algunos comandos usan formatos personalizados para
invalidar el número de propiedades que se muestran de forma predeterminada en una
tabla. Hay varios cmdlets Format-* que se pueden usar para invalidar manualmente
estos valores predeterminados. Los más comunes son Format-Table y Format-List , y
ambos se tratarán en un próximo capítulo.

Se pueden usar caracteres comodín cuando se especifican los nombres de propiedad


con Select-Object .

PowerShell

Get-Service -Name w32time | Select-Object -Property Status, DisplayName,


Can*

Output

Status : Running
DisplayName : Windows Time
CanPauseAndContinue : False
CanShutdown : True
CanStop : True

En el ejemplo anterior, se usó Can* como uno de los valores del parámetro Property
para devolver todas las propiedades que comienzan con Can . Entre ellas se incluyen
CanPauseAndContinue, CanShutdown y CanStop.

Métodos
Los métodos son una acción que se puede realizar. Usando el parámetro MemberType
se pueden restringir los resultados de Get-Member para mostrar solo los métodos de
Get-Service .

PowerShell

Get-Service -Name w32time | Get-Member -MemberType Method

Output

TypeName: System.ServiceProcess.ServiceController

Name MemberType Definition


---- ---------- ----------
Close Method void Close()
Continue Method void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef
CreateObjRef(type ...
Dispose Method void Dispose(), void
IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object
InitializeLifetimeService()
Pause Method void Pause()
Refresh Method void Refresh()
Start Method void Start(), void Start(string[] args)
Stop Method void Stop()
WaitForStatus Method void
WaitForStatus(System.ServiceProcess.ServiceC...

Como se puede ver, hay muchos métodos. Se puede usar el método Stop para detener
un servicio de Windows.

PowerShell

(Get-Service -Name w32time).Stop()

Ahora comprobemos si el servicio de Hora de Windows de verdad se ha detenido.


PowerShell

Get-Service -Name w32time

Output

Status Name DisplayName


------ ---- -----------
Stopped w32time Windows Time

No suelo usar métodos, pero son algo que debe tenerse en cuenta. Habrá ocasiones en
las que aparecerá un comando Get-* sin un comando correspondiente para modificar
dicho elemento. A menudo, se puede usar un método para realizar una acción que lo
modifique. El cmdlet Get-SqlAgentJob del módulo SqlServer PowerShell es un buen
ejemplo de esto. El módulo se instala como parte de SQL Server Management Studio
(SSMS). No existe ningún cmdlet Set-* correspondiente, pero se puede usar un método
para completar la misma tarea.

Otro motivo para conocer los métodos es que muchos principiantes dan por hecho que
no se pueden realizar cambios destructivos con comandos Get-* . Pero estos comandos
sí pueden producir problemas graves si se usan de forma incorrecta.

Una opción mejor es usar un cmdlet para realizar la acción si existe uno. Ahora vamos a
iniciar el servicio de Hora de Windows, pero esta vez usaremos el cmdlet para iniciar los
servicios.

PowerShell

Get-Service -Name w32time | Start-Service -PassThru

Output

Status Name DisplayName


------ ---- -----------
Running w32time Windows Time

De forma predeterminada, Start-Service no devuelve ningún resultado, del mismo


modo que el método de inicio de Get-Service . Pero una de las ventajas de usar un
cmdlet es que muchas veces el cmdlet ofrece funcionalidades adicionales que no están
disponibles con un método. En el ejemplo anterior, se usó el parámetro PassThru. Esto
provoca que un cmdlet produzca una salida, aunque normalmente no la produzca.
Hay que tener cuidado de no hacer suposiciones sobre la salida de un cmdlet. Todos
sabemos lo que pasa cuando se presuponen las cosas. Ahora recuperaré información
sobre el proceso de PowerShell que se ejecuta en mi equipo de entorno de laboratorio
con Windows 10.

PowerShell

Get-Process -Name PowerShell

Output

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName


------- ------ ----- ----- ------ -- -- -----------
922 48 107984 140552 2.84 9020 1 powershell

Acto seguido, canalizaré ese mismo comando a Get-Member:

PowerShell

Get-Process -Name PowerShell | Get-Member

Output

TypeName: System.Diagnostics.Process

Name MemberType Definition


---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize64
PM AliasProperty PM = PagedMemorySize64
SI AliasProperty SI = SessionId
VM AliasProperty VM = VirtualMemorySize64
WS AliasProperty WS = WorkingSet64
Disposed Event System.EventHandler
Disposed(System.Object, ...
ErrorDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
Exited Event System.EventHandler
Exited(System.Object, Sy...
OutputDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
BeginErrorReadLine Method void BeginErrorReadLine()
BeginOutputReadLine Method void BeginOutputReadLine()
CancelErrorRead Method void CancelErrorRead()
CancelOutputRead Method void CancelOutputRead()
Close Method void Close()
CloseMainWindow Method bool CloseMainWindow()
CreateObjRef Method System.Runtime.Remoting.ObjRef
CreateObjRef(...
Dispose Method void Dispose(), void
IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object
InitializeLifetimeService()
Kill Method void Kill()
Refresh Method void Refresh()
Start Method bool Start()
ToString Method string ToString()
WaitForExit Method bool WaitForExit(int
milliseconds), void Wai...
WaitForInputIdle Method bool WaitForInputIdle(int
milliseconds), boo...
__NounName NoteProperty string __NounName=Process
BasePriority Property int BasePriority {get;}
Container Property System.ComponentModel.IContainer
Container {...
EnableRaisingEvents Property bool EnableRaisingEvents
{get;set;}
ExitCode Property int ExitCode {get;}
ExitTime Property datetime ExitTime {get;}
Handle Property System.IntPtr Handle {get;}
HandleCount Property int HandleCount {get;}
HasExited Property bool HasExited {get;}
Id Property int Id {get;}
MachineName Property string MachineName {get;}
MainModule Property System.Diagnostics.ProcessModule
MainModule ...
MainWindowHandle Property System.IntPtr MainWindowHandle
{get;}
MainWindowTitle Property string MainWindowTitle {get;}
MaxWorkingSet Property System.IntPtr MaxWorkingSet
{get;set;}
MinWorkingSet Property System.IntPtr MinWorkingSet
{get;set;}
Modules Property
System.Diagnostics.ProcessModuleCollection M...
NonpagedSystemMemorySize Property int NonpagedSystemMemorySize
{get;}
NonpagedSystemMemorySize64 Property long NonpagedSystemMemorySize64
{get;}
PagedMemorySize Property int PagedMemorySize {get;}
PagedMemorySize64 Property long PagedMemorySize64 {get;}
PagedSystemMemorySize Property int PagedSystemMemorySize {get;}
PagedSystemMemorySize64 Property long PagedSystemMemorySize64
{get;}
PeakPagedMemorySize Property int PeakPagedMemorySize {get;}
PeakPagedMemorySize64 Property long PeakPagedMemorySize64 {get;}
PeakVirtualMemorySize Property int PeakVirtualMemorySize {get;}
PeakVirtualMemorySize64 Property long PeakVirtualMemorySize64
{get;}
PeakWorkingSet Property int PeakWorkingSet {get;}
PeakWorkingSet64 Property long PeakWorkingSet64 {get;}
PriorityBoostEnabled Property bool PriorityBoostEnabled
{get;set;}
PriorityClass Property
System.Diagnostics.ProcessPriorityClass Prio...
PrivateMemorySize Property int PrivateMemorySize {get;}
PrivateMemorySize64 Property long PrivateMemorySize64 {get;}
PrivilegedProcessorTime Property timespan PrivilegedProcessorTime
{get;}
ProcessName Property string ProcessName {get;}
ProcessorAffinity Property System.IntPtr ProcessorAffinity
{get;set;}
Responding Property bool Responding {get;}
SafeHandle Property
Microsoft.Win32.SafeHandles.SafeProcessHandl...
SessionId Property int SessionId {get;}
Site Property System.ComponentModel.ISite Site
{get;set;}
StandardError Property System.IO.StreamReader
StandardError {get;}
StandardInput Property System.IO.StreamWriter
StandardInput {get;}
StandardOutput Property System.IO.StreamReader
StandardOutput {get;}
StartInfo Property
System.Diagnostics.ProcessStartInfo StartInf...
StartTime Property datetime StartTime {get;}
SynchronizingObject Property
System.ComponentModel.ISynchronizeInvoke Syn...
Threads Property
System.Diagnostics.ProcessThreadCollection T...
TotalProcessorTime Property timespan TotalProcessorTime {get;}
UserProcessorTime Property timespan UserProcessorTime {get;}
VirtualMemorySize Property int VirtualMemorySize {get;}
VirtualMemorySize64 Property long VirtualMemorySize64 {get;}
WorkingSet Property int WorkingSet {get;}
WorkingSet64 Property long WorkingSet64 {get;}
PSConfiguration PropertySet PSConfiguration {Name, Id,
PriorityClass, Fi...
PSResources PropertySet PSResources {Name, Id,
Handlecount, WorkingS...
Company ScriptProperty System.Object Company
{get=$this.Mainmodule....
CPU ScriptProperty System.Object CPU
{get=$this.TotalProcessorT...
Description ScriptProperty System.Object Description
{get=$this.Mainmod...
FileVersion ScriptProperty System.Object FileVersion
{get=$this.Mainmod...
Path ScriptProperty System.Object Path
{get=$this.Mainmodule.Fil...
Product ScriptProperty System.Object Product
{get=$this.Mainmodule....
ProductVersion ScriptProperty System.Object ProductVersion
{get=$this.Main...

Observe que hay más propiedades enumeradas que las que se muestran de forma
predeterminada. Varias de las propiedades predeterminadas que se muestran no
aparecen como propiedades al consultar los resultados de Get-Member . Esto se debe a
que muchos de los valores mostrados, como NPM(K) , PM(K) , WS(K) y CPU(s) , son
propiedades calculadas. Para determinar los nombres reales de las propiedades, el
comando se debe canalizar a Get-Member .

Si un comando no produce una salida, no se puede canalizar a Get-Member . Dado que


Start-Service no produce ninguna salida de forma predeterminada, genera un error

cuando se intenta canalizar a Get-Member .

PowerShell

Start-Service -Name w32time | Get-Member

Output

Get-Member : You must specify an object for the Get-Member cmdlet.


At line:1 char:31
+ Start-Service -Name w32time | Get-Member
+
+ CategoryInfo : CloseError: (:) [Get-Member],
InvalidOperationException
+ FullyQualifiedErrorId :
NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMembe
rCommand

Se puede especificar el parámetro PassThru con el cmdlet Start-Service para hacer


que produzca la salida, la cual se canalizaría a Get-Member sin errores.

PowerShell

Start-Service -Name w32time -PassThru | Get-Member

Output

TypeName: System.ServiceProcess.ServiceController

Name MemberType Definition


---- ---------- ----------
Name AliasProperty Name = ServiceName
RequiredServices AliasProperty RequiredServices =
ServicesDependedOn
Disposed Event System.EventHandler
Disposed(System.Object, Sy...
Close Method void Close()
Continue Method void Continue()
CreateObjRef Method System.Runtime.Remoting.ObjRef
CreateObjRef(ty...
Dispose Method void Dispose(), void
IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
ExecuteCommand Method void ExecuteCommand(int command)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object
InitializeLifetimeService()
Pause Method void Pause()
Refresh Method void Refresh()
Start Method void Start(), void Start(string[]
args)
Stop Method void Stop()
WaitForStatus Method void
WaitForStatus(System.ServiceProcess.Servi...
CanPauseAndContinue Property bool CanPauseAndContinue {get;}
CanShutdown Property bool CanShutdown {get;}
CanStop Property bool CanStop {get;}
Container Property System.ComponentModel.IContainer
Container {get;}
DependentServices Property
System.ServiceProcess.ServiceController[] Depe...
DisplayName Property string DisplayName {get;set;}
MachineName Property string MachineName {get;set;}
ServiceHandle Property
System.Runtime.InteropServices.SafeHandle Serv...
ServiceName Property string ServiceName {get;set;}
ServicesDependedOn Property
System.ServiceProcess.ServiceController[] Serv...
ServiceType Property System.ServiceProcess.ServiceType
ServiceType ...
Site Property System.ComponentModel.ISite Site
{get;set;}
StartType Property
System.ServiceProcess.ServiceStartMode StartTy...
Status Property
System.ServiceProcess.ServiceControllerStatus ...
ToString ScriptMethod System.Object ToString();

Para que se canalice a Get-Member , un comando debe producir una salida basada en
objetos.

PowerShell

Get-Service -Name w32time | Out-Host | Get-Member


Output

Status Name DisplayName


------ ---- -----------
Running w32time Windows Time

Get-Member : You must specify an object for the Get-Member cmdlet.


At line:1 char:40
+ Get-Service -Name w32time | Out-Host | Get-Member
+
+ CategoryInfo : CloseError: (:) [Get-Member],
InvalidOperationException
+ FullyQualifiedErrorId :
NoObjectInGetMember,Microsoft.PowerShell.Commands.GetMemberCommand

Out-Host escribe directamente en el host de PowerShell, pero no produce una salida

basada en objetos para la canalización. Por lo tanto, no se puede canalizar a Get-Member .

Active Directory

7 Nota

Las Herramientas de administración remota del servidor que aparecen en la sección


de requisitos de este capítulo son necesarias para completar esta sección. Además,
tal y como se mencionó en la introducción de este libro, es necesario que el equipo
de entorno de laboratorio con Windows 10 sea miembro del dominio de entorno
de laboratorio.

Ahora vamos a usar Get-Command con el parámetro Module para determinar qué
comandos se agregaron como parte del módulo ActiveDirectory PowerShell cuando se
instalaron las herramientas de administración remota del servidor.

PowerShell

Get-Command -Module ActiveDirectory

Output

CommandType Name Version


Source
----------- ---- -------
------
Cmdlet Add-ADCentralAccessPolicyMember 1.0.0.0
ActiveDi...
Cmdlet Add-ADComputerServiceAccount 1.0.0.0
ActiveDi...
Cmdlet Add-ADDomainControllerPasswordReplicationPolicy 1.0.0.0
ActiveDi...
Cmdlet Add-ADFineGrainedPasswordPolicySubject 1.0.0.0
ActiveDi...
Cmdlet Add-ADGroupMember 1.0.0.0
ActiveDi...
Cmdlet Add-ADPrincipalGroupMembership 1.0.0.0
ActiveDi...
Cmdlet Add-ADResourcePropertyListMember 1.0.0.0
ActiveDi...
Cmdlet Clear-ADAccountExpiration 1.0.0.0
ActiveDi...
Cmdlet Clear-ADClaimTransformLink 1.0.0.0
ActiveDi...
Cmdlet Disable-ADAccount 1.0.0.0
ActiveDi...
...

Se ha agregado un total de 147 comandos como parte del módulo ActiveDirectory


PowerShell. Algunos comandos de estos comandos solo devuelven una parte de las
propiedades disponibles de forma predeterminada.

¿No ha observado algo distinto en relación con los nombres de los comandos en este
módulo? La parte del nombre de los comandos tiene un prefijo AD. Es habitual ver esto
en los comandos de la mayoría de los módulos. El prefijo está diseñado para evitar
conflictos de nomenclatura.

PowerShell

Get-ADUser -Identity mike | Get-Member

Output

TypeName: Microsoft.ActiveDirectory.Management.ADUser

Name MemberType Definition


---- ---------- ----------
Contains Method bool Contains(string propertyName)
Equals Method bool Equals(System.Object obj)
GetEnumerator Method
System.Collections.IDictionaryEnumerator GetEn...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Item ParameterizedProperty
Microsoft.ActiveDirectory.Management.ADPropert...
DistinguishedName Property System.String DistinguishedName
{get;set;}
Enabled Property System.Boolean Enabled {get;set;}
GivenName Property System.String GivenName {get;set;}
Name Property System.String Name {get;}
ObjectClass Property System.String ObjectClass {get;set;}
ObjectGUID Property System.Nullable`1[[System.Guid,
mscorlib, Vers...
SamAccountName Property System.String SamAccountName
{get;set;}
SID Property
System.Security.Principal.SecurityIdentifier S...
Surname Property System.String Surname {get;set;}
UserPrincipalName Property System.String UserPrincipalName
{get;set;}

Aunque apenas esté familiarizado con Active Directory, podría entender que una cuenta
de usuario tiene más propiedades que las que se muestran en este ejemplo.

El cmdlet Get-ADUser tiene un parámetro Properties que se usa para especificar las
propiedades (no predeterminadas) adicionales que quiera devolver. Todas se devuelven
al especificar el carácter comodín * .

PowerShell

Get-ADUser -Identity mike -Properties * | Get-Member

Output

TypeName: Microsoft.ActiveDirectory.Management.ADUser

Name MemberType Definition


---- ---------- ----------
Contains Method bool
Contains(string proper...
Equals Method bool
Equals(System.Object obj)
GetEnumerator Method
System.Collections.IDiction...
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Item ParameterizedProperty
Microsoft.ActiveDirectory.M...
AccountExpirationDate Property System.DateTime
AccountExpi...
accountExpires Property System.Int64
accountExpires...
AccountLockoutTime Property System.DateTime
AccountLock...
AccountNotDelegated Property System.Boolean
AccountNotDe...
AllowReversiblePasswordEncryption Property System.Boolean
AllowReversi...
AuthenticationPolicy Property
Microsoft.ActiveDirectory.M...
AuthenticationPolicySilo Property
Microsoft.ActiveDirectory.M...
BadLogonCount Property System.Int32
BadLogonCount ...
badPasswordTime Property System.Int64
badPasswordTim...
badPwdCount Property System.Int32
badPwdCount {g...
CannotChangePassword Property System.Boolean
CannotChange...
CanonicalName Property System.String
CanonicalName...
Certificates Property
Microsoft.ActiveDirectory.M...
City Property System.String
City {get;set;}
CN Property System.String CN
{get;}
codePage Property System.Int32
codePage {get;...
Company Property System.String
Company {get;...
CompoundIdentitySupported Property
Microsoft.ActiveDirectory.M...
Country Property System.String
Country {get;...
countryCode Property System.Int32
countryCode {g...
Created Property System.DateTime
Created {get;}
createTimeStamp Property System.DateTime
createTimeS...
Deleted Property System.Boolean
Deleted {get;}
Department Property System.String
Department {g...
Description Property System.String
Description {...
DisplayName Property System.String
DisplayName {...
DistinguishedName Property System.String
Distinguished...
Division Property System.String
Division {get...
DoesNotRequirePreAuth Property System.Boolean
DoesNotRequi...
dSCorePropagationData Property
Microsoft.ActiveDirectory.M...
EmailAddress Property System.String
EmailAddress ...
EmployeeID Property System.String
EmployeeID {g...
EmployeeNumber Property System.String
EmployeeNumbe...
Enabled Property System.Boolean
Enabled {get...
Fax Property System.String Fax
{get;set;}
GivenName Property System.String
GivenName {ge...
HomeDirectory Property System.String
HomeDirectory...
HomedirRequired Property System.Boolean
HomedirRequi...
HomeDrive Property System.String
HomeDrive {ge...
HomePage Property System.String
HomePage {get...
HomePhone Property System.String
HomePhone {ge...
Initials Property System.String
Initials {get...
instanceType Property System.Int32
instanceType {...
isDeleted Property System.Boolean
isDeleted {g...
KerberosEncryptionType Property
Microsoft.ActiveDirectory.M...
LastBadPasswordAttempt Property System.DateTime
LastBadPass...
LastKnownParent Property System.String
LastKnownPare...
lastLogoff Property System.Int64
lastLogoff {ge...
lastLogon Property System.Int64
lastLogon {get...
LastLogonDate Property System.DateTime
LastLogonDa...
lastLogonTimestamp Property System.Int64
lastLogonTimes...
LockedOut Property System.Boolean
LockedOut {g...
logonCount Property System.Int32
logonCount {ge...
LogonWorkstations Property System.String
LogonWorkstat...
Manager Property System.String
Manager {get;...
MemberOf Property
Microsoft.ActiveDirectory.M...
MNSLogonAccount Property System.Boolean
MNSLogonAcco...
MobilePhone Property System.String
MobilePhone {...
Modified Property System.DateTime
Modified {g...
modifyTimeStamp Property System.DateTime
modifyTimeS...
msDS-User-Account-Control-Computed Property System.Int32
msDS-User-Acco...
Name Property System.String
Name {get;}
nTSecurityDescriptor Property
System.DirectoryServices.Ac...
ObjectCategory Property System.String
ObjectCategor...
ObjectClass Property System.String
ObjectClass {...
ObjectGUID Property
System.Nullable`1[[System.G...
objectSid Property
System.Security.Principal.S...
Office Property System.String
Office {get;s...
OfficePhone Property System.String
OfficePhone {...
Organization Property System.String
Organization ...
OtherName Property System.String
OtherName {ge...
PasswordExpired Property System.Boolean
PasswordExpi...
PasswordLastSet Property System.DateTime
PasswordLas...
PasswordNeverExpires Property System.Boolean
PasswordNeve...
PasswordNotRequired Property System.Boolean
PasswordNotR...
POBox Property System.String
POBox {get;set;}
PostalCode Property System.String
PostalCode {g...
PrimaryGroup Property System.String
PrimaryGroup ...
primaryGroupID Property System.Int32
primaryGroupID...
PrincipalsAllowedToDelegateToAccount Property
Microsoft.ActiveDirectory.M...
ProfilePath Property System.String
ProfilePath {...
ProtectedFromAccidentalDeletion Property System.Boolean
ProtectedFro...
pwdAnswer Property System.String
pwdAnswer {ge...
pwdLastSet Property System.Int64
pwdLastSet {ge...
pwdQuestion Property System.String
pwdQuestion {...
SamAccountName Property System.String
SamAccountNam...
sAMAccountType Property System.Int32
sAMAccountType...
ScriptPath Property System.String
ScriptPath {g...
sDRightsEffective Property System.Int32
sDRightsEffect...
ServicePrincipalNames Property
Microsoft.ActiveDirectory.M...
SID Property
System.Security.Principal.S...
SIDHistory Property
Microsoft.ActiveDirectory.M...
SmartcardLogonRequired Property System.Boolean
SmartcardLog...
sn Property System.String sn
{get;set;}
State Property System.String
State {get;set;}
StreetAddress Property System.String
StreetAddress...
Surname Property System.String
Surname {get;...
Title Property System.String
Title {get;set;}
TrustedForDelegation Property System.Boolean
TrustedForDe...
TrustedToAuthForDelegation Property System.Boolean
TrustedToAut...
UseDESKeyOnly Property System.Boolean
UseDESKeyOnl...
userAccountControl Property System.Int32
userAccountCon...
userCertificate Property
Microsoft.ActiveDirectory.M...
UserPrincipalName Property System.String
UserPrincipal...
uSNChanged Property System.Int64
uSNChanged {get;}
uSNCreated Property System.Int64
uSNCreated {get;}
whenChanged Property System.DateTime
whenChanged...
whenCreated Property System.DateTime
whenCreated...

Mucho mejor.

¿Cuál podría ser un motivo por el que las propiedades de una cuenta de usuario de
Active Directory podrían estar tan limitadas de forma predeterminada? Imaginemos qué
pasaría si se devolviera cada propiedad para cada cuenta de usuario en el entorno de
Active Directory de producción. Pensemos en la degradación del rendimiento que
podría provocar, y no solo en los controladores de dominio, sino también en la red. No
está claro que de verdad se necesiten todas las propiedades. Devolver todas las
propiedades a una cuenta de usuario única es perfectamente aceptable cuando se
intenta determinar qué propiedades existen.

No es raro ejecutar un comando muchas veces al crear un prototipo. Si va a realizar una


consulta enorme, es preferible realizarla una vez y almacenar los resultados en una
variable. Hecho esto, se trabajaría con el contenido de la variable, en lugar de usar
repetidamente una consulta costosa.

PowerShell

$Users = Get-ADUser -Identity mike -Properties *

Es mejor usar el contenido de la variable $Users , en lugar de ejecutar el comando


anterior varias veces. Tenga en cuenta que el contenido de la variable no se actualizará
cuando se realicen cambios en el usuario en Active Directory.

Puede canalizarse la variable $Users a Get-Member para detectar las propiedades


disponibles.

PowerShell

$Users | Get-Member

Después, seleccione las propiedades individuales mediante la canalización de $Users a


Select-Object , sin tener que consultar Active Directory más de una vez.

PowerShell

$Users | Select-Object -Property Name, LastLogonDate, LastBadPasswordAttempt

Si va a consultar Active Directory más de una vez, puede usar el parámetro Properties
para especificar las propiedades no predeterminadas que quiera.

PowerShell

Get-ADUser -Identity mike -Properties LastLogonDate, LastBadPasswordAttempt

Output

DistinguishedName : CN=Mike F. Robbins,OU=Sales,DC=mikefrobbins,DC=com


Enabled : True
GivenName : Mike
LastBadPasswordAttempt : 2/4/2017 10:46:15 AM
LastLogonDate : 2/18/2017 12:45:14 AM
Name : Mike F. Robbins
ObjectClass : user
ObjectGUID : a82a8c58-1332-4a57-a6e2-68e0c750ea56
SamAccountName : mike
SID : S-1-5-21-2989741381-570885089-3319121794-1108
Surname : Robbins
UserPrincipalName : miker@mikefrobbins.com

Resumen
En este capítulo hemos aprendido cómo determinar el tipo de objeto que puede
producir un comando, cómo determinar qué propiedades y métodos están disponibles
para un comando y cómo trabajar con comandos que limitan las propiedades que se
devuelven de forma predeterminada.

Revisar
1. ¿Qué tipo de objeto produce el cmdlet Get-Process ?
2. ¿Cómo se determinan las propiedades disponibles para un comando?
3. Si existe un comando para obtener algo, pero no para establecer lo mismo, ¿qué
se debe comprobar?
4. ¿Qué puede hacerse para que determinados comandos que no producen una
salida de forma predeterminada puedan producir una salida?
5. Si se va a trabajar con los resultados de un comando que produce una gran
cantidad de salidas, ¿qué se podría hacer?

Lecturas recomendadas
Get-Member
Ver la estructura del objeto (Get-Member)
about_Objects
about_Properties
about_Methods
¿No hay ningún cmdlet de PowerShell para iniciar o detener algo? No olvide
buscar métodos en los cmdlets Get
Capítulo 4: Comandos únicos de una
línea y canalización
Artículo • 13/04/2023

Cuando empecé a aprender PowerShell, si no podía realizar una tarea mediante un


comando único de una línea de PowerShell, volvía a GUI. Con el tiempo, he mejorado
mis habilidades, y he conseguido escribir scripts, funciones y módulos. No deje que los
ejemplos avanzados que hay en Internet le abrumen. Nadie nace sabiendo utilizar
PowerShell. Todos hemos sido principiantes en algún momento.

Me gustaría dar un pequeño consejo a aquellos que siguen usando GUI para la
administración: que instalen las herramientas de administración en su estación de
trabajo y administren sus servidores de forma remota. De este modo, no importará si el
servidor está ejecutando GUI o la instalación de Server Core del sistema operativo. Le
ayudará a tenerlo todo a punto para administrar los servidores de forma remota con
PowerShell.

Como en capítulos anteriores, asegúrese de seguir los procesos en su equipo del


entorno de laboratorio de Windows 10.

Comandos únicos de una línea


Una línea uno de PowerShell es una canalización continua y no necesariamente un
comando que se encuentra en una línea física. No todos los comandos que se
encuentran en una línea física son comandos únicos de una línea.

Aunque el siguiente comando esté situado en varias líneas físicas, es un comando único
de una línea de PowerShell, ya que es una canalización continua. Podría escribirse en
una línea física, pero he preferido insertar un salto de línea en el símbolo de
canalización. El símbolo de canalización es uno de los caracteres que permiten un salto
de línea natural en PowerShell.

PowerShell

Get-Service |
Where-Object CanPauseAndContinue -eq $true |
Select-Object -Property *

Output
Name : LanmanWorkstation
RequiredServices : {NSI, MRxSmb20, Bowser}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Workstation
DependentServices : {SessionEnv, Netlogon, Browser}
MachineName : .
ServiceName : LanmanWorkstation
ServicesDependedOn : {NSI, MRxSmb20, Bowser}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Automatic
Site :
Container :

Name : Netlogon
RequiredServices : {LanmanWorkstation}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Netlogon
DependentServices : {}
MachineName : .
ServiceName : Netlogon
ServicesDependedOn : {LanmanWorkstation}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Automatic
Site :
Container :

Name : vmicheartbeat
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Heartbeat Service
DependentServices : {}
MachineName : .
ServiceName : vmicheartbeat
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

Name : vmickvpexchange
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Data Exchange Service
DependentServices : {}
MachineName : .
ServiceName : vmickvpexchange
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

Name : vmicrdv
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Remote Desktop Virtualization Service
DependentServices : {}
MachineName : .
ServiceName : vmicrdv
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

Name : vmicshutdown
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Guest Shutdown Service
DependentServices : {}
MachineName : .
ServiceName : vmicshutdown
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

Name : vmictimesync
RequiredServices : {VmGid}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Time Synchronization Service
DependentServices : {}
MachineName : .
ServiceName : vmictimesync
ServicesDependedOn : {VmGid}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

Name : vmicvss
RequiredServices : {}
CanPauseAndContinue : True
CanShutdown : False
CanStop : True
DisplayName : Hyper-V Volume Shadow Copy Requestor
DependentServices : {}
MachineName : .
ServiceName : vmicvss
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

Name : Winmgmt
RequiredServices : {RPCSS}
CanPauseAndContinue : True
CanShutdown : True
CanStop : True
DisplayName : Windows Management Instrumentation
DependentServices : {wscsvc, NcaSvc, iphlpsvc}
MachineName : .
ServiceName : Winmgmt
ServicesDependedOn : {RPCSS}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Automatic
Site :
Container :

Los saltos de línea naturales se pueden producir en caracteres de uso frecuente, como
comas ( , ), corchetes de apertura ( [ ), llaves ( { ) y paréntesis ( ( ). Otros que no son tan
frecuentes son, por ejemplo, el punto y coma ( ; ), el signo igual ( = ), y las comillas de
apertura simples y dobles ( ' , " ).

El uso del acento grave ( ` ) como carácter de continuación de línea es un tema


controvertido. Mi recomendación es tratar de evitarlo en la medida de lo posible. A
menudo veo comandos de PowerShell escritos con un acento grave inmediatamente
después de un carácter de salto de línea natural. No tiene sentido que esté ahí.

PowerShell

Get-Service -Name w32time |


>> Select-Object -Property *

Output

Name : w32time
RequiredServices : {}
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
DisplayName : Windows Time
DependentServices : {}
MachineName : .
ServiceName : w32time
ServicesDependedOn : {}
ServiceHandle : SafeServiceHandle
Status : Running
ServiceType : Win32ShareProcess
StartType : Manual
Site :
Container :

Los comandos que se muestran en los dos ejemplos anteriores funcionan bien en la
consola de PowerShell. Pero, si se intentan ejecutar en el panel de la consola de
PowerShell ISE, generarán un error. El panel de la consola de PowerShell ISE no espera a
que se incluya el resto del comando en la siguiente línea como hace la consola de
PowerShell. Para evitar este problema en el panel de la consola de PowerShell ISE,
presione Mayús + Entrar , en lugar de presionar solo Entrar , cuando vaya a continuar un
comando en otra línea.

El siguiente ejemplo no es un comando único de una línea de PowerShell porque no es


una canalización continua. Se trata de dos comandos independientes situados en una
línea y separados por un punto y coma.

PowerShell

$Service = 'w32time'; Get-Service -Name $Service

Output
Status Name DisplayName
------ ---- -----------
Running w32time Windows Time

En muchos lenguajes de programación y de scripting es necesaria la presencia de un


punto y coma al final de cada línea. Aunque se pueden usar de ese modo en PowerShell,
no es recomendable, ya que no es necesario.

Filtrado a la izquierda
Los resultados de los comandos que se muestran en este capítulo se filtraron para
obtener un subconjunto. Por ejemplo, Get-Service se utilizó con el parámetro Name
para filtrar la lista de servicios que se devolvieron con el fin de obtener solo resultados
para el servicio Hora de Windows.

En la canalización, lo que siempre se quiere es filtrar los resultados para obtener lo que
se está buscando lo antes posible. Esto se logra mediante el uso de parámetros en el
primer comando o en el que está situado en el extremo izquierdo. Esta práctica se
denomina, en ocasiones, filtrado a la izquierda.

En el ejemplo siguiente se usa el parámetro Name de Get-Service para filtrar


inmediatamente solo los resultados para el servicio de Hora de Windows.

PowerShell

Get-Service -Name w32time

Output

Status Name DisplayName


------ ---- -----------
Running w32time Windows Time

Es habitual ver ejemplos en los que el comando se canaliza a Where-Object para realizar
el filtrado.

PowerShell

Get-Service | Where-Object Name -eq w32time

Output
Status Name DisplayName
------ ---- -----------
Running W32Time Windows Time

En el primer ejemplo, el filtro se aplica en el origen y solo se devuelven los resultados


para el servicio de Hora de Windows. En el segundo ejemplo, se devuelven todos los
servicios y, después, se canalizan a otro comando para realizar el filtrado. Aunque no
parezca algo muy útil en este ejemplo, puede serlo en la consulta de una lista de
usuarios de Active Directory. ¿Realmente quiere que se devuelva la información de miles
de cuentas de usuario de Active Directory para después canalizarlas a otro comando
que las filtre en un subconjunto muy pequeño? Mi recomendación es filtrar siempre a la
izquierda, aunque no parezca útil hacerlo. Estará tan acostumbrado a hacerlo que filtrará
a la izquierda de forma automática cuando sea necesario.

Alguien me dijo una vez que el orden en el que se especifican los comandos no es muy
importante. Nada más lejos de la realidad. El orden en el que se especifican los
comandos es muy importante cuando se realiza el filtrado. Por ejemplo, considere el
escenario en el que utiliza Select-Object para seleccionar solo algunas propiedades y
Where-Object para filtrar por propiedades que no estarán en la selección. En ese
escenario, el filtrado debe realizarse primero, ya que, de lo contrario, la propiedad no
existirá en la canalización cuando intente realizar el filtrado.

PowerShell

Get-Service |
Select-Object -Property DisplayName, Running, Status |
Where-Object CanPauseAndContinue

El comando del ejemplo anterior no devuelve ningún resultado porque la propiedad


CanStopAndContinue no existe cuando los resultados de Select-Object se canalizan a
Where-Object . Esa propiedad en concreto no estaba "seleccionada". En resumen, se
había filtrado. Si se invierte el orden de Select-Object y Where-Object , se consiguen los
resultados deseados.

PowerShell

Get-Service |
Where-Object CanPauseAndContinue |
Select-Object -Property DisplayName, Status

Output
DisplayName Status
----------- ------
Workstation Running
Netlogon Running
Hyper-V Heartbeat Service Running
Hyper-V Data Exchange Service Running
Hyper-V Remote Desktop Virtualization Service Running
Hyper-V Guest Shutdown Service Running
Hyper-V Time Synchronization Service Running
Hyper-V Volume Shadow Copy Requestor Running
Windows Management Instrumentation Running

La canalización
Como se ha podido ver en muchos de los ejemplos mostrados hasta ahora en este libro,
muchas veces la salida de un comando se puede usar como entrada para otro. En el
capítulo 3, se usó Get-Member para determinar qué tipo de objeto genera un comando.
En el capítulo 3 también se muestra cómo usar el parámetro ParameterType de Get-
Command para determinar qué comandos aceptaron ese tipo de entrada, aunque no sea
necesariamente por entrada de canalización.

En función de lo exhaustiva que sea la ayuda de un comando, puede incluir una sección
de ENTRADAS y una de SALIDAS.

PowerShell

help Stop-Service -Full

Output

...
INPUTS
System.ServiceProcess.ServiceController, System.String
You can pipe a service object or a string that contains the name of
a service
to this cmdlet.

OUTPUTS
None, System.ServiceProcess.ServiceController
This cmdlet generates a System.ServiceProcess.ServiceController
object that
represents the service, if you use the PassThru parameter.
Otherwise, this
cmdlet does not generate any output.
...
En los resultados anteriores solo se muestra la sección pertinente de la ayuda. Como
puede ver, la sección ENTRADAS indica que se puede canalizar un objeto
ServiceController o String al cmdlet Stop-Service . No indica qué parámetros acepta
ese tipo de entrada. Una de las formas más sencillas de determinar esa información es
examinar los distintos parámetros en la versión completa de la ayuda del cmdlet Stop-
Service .

PowerShell

help Stop-Service -Full

Output

...
-DisplayName <String[]>
Specifies the display names of the services to stop. Wildcard characters
are
permitted.

Required? true
Position? named
Default value None
Accept pipeline input? False
Accept wildcard characters? false

-InputObject <ServiceController[]>
Specifies ServiceController objects that represent the services to stop.
Enter a
variable that contains the objects, or type a command or expression that
gets the
objects.

Required? true
Position? 0
Default value None
Accept pipeline input? True (ByValue)
Accept wildcard characters? false

-Name <String[]>
Specifies the service names of the services to stop. Wildcard characters
are
permitted.

Required? true
Position? 0
Default value None
Accept pipeline input? True (ByPropertyName, ByValue)
Accept wildcard characters? false
...
De nuevo, solo he mostrado la parte pertinente de la ayuda en el conjunto de resultados
anterior. Es importante observar que el parámetro DisplayName no acepta la entrada de
canalización; el parámetro InputObject acepta la entrada de canalización por valor para
objetos ServiceController; y el parámetro Name acepta la entrada de canalización por
valor para objetos string. También acepta la entrada de canalización por nombre de
propiedad.

Cuando un parámetro acepta la entrada de canalización por nombre de propiedad y por


valor, siempre intenta hacerlo primero por valor. Si no lo consigue por valor, entonces
lo intenta por nombre de propiedad. Por valor es un poco engañoso. Prefiero llamarlo
por tipo. Esto significa que, si se canalizan los resultados de un comando que produce
un tipo de objeto ServiceController a Stop-Service , enlaza esa entrada al parámetro
InputObject. Pero si se canalizan los resultados de un comando que genera una salida
de String a Stop-Service , lo enlaza al parámetro Name. Si se canalizan los resultados de
un comando que no genera un objeto ServiceController o String a Stop-Service , pero
que genera una salida que contiene una propiedad denominada Name, entonces enlaza
la propiedad Name de la salida al parámetro Name de Stop-Service .

Determine el tipo de salida que genera el comando Get-Service .

PowerShell

Get-Service -Name w32time | Get-Member

Output

TypeName: System.ServiceProcess.ServiceController

Get-Service genera un tipo de objeto ServiceController.

Como hemos visto anteriormente en la ayuda, el parámetro InputObject de Stop-


Service acepta objetos ServiceController mediante la canalización por valor (por tipo).

Esto significa que cuando los resultados del cmdlet Get-Service se canalizan a Stop-
Service , se enlazan al parámetro InputObject de Stop-Service .

PowerShell

Get-Service -Name w32time | Stop-Service

Ahora, para probar la entrada de cadena, canalizamos w32time a Get-Member solo para
confirmar que es una cadena.
PowerShell

'w32time' | Get-Member

Output

TypeName: System.String

Como se mostró anteriormente en la ayuda, canalizar una cadena a Stop-Service la


enlaza por valor al parámetro Name de Stop-Service . Pruébelo canalizando w32time a
Stop-Service .

PowerShell

'w32time' | Stop-Service

Observe que, en el ejemplo anterior, usé comillas simples alrededor de la cadena


w32time . En PowerShell, las comillas simples deberían utilizarse siempre en lugar de las

dobles. a menos que el contenido de la cadena entrecomillada contenga una variable


que deba expandirse a su valor real. Con las comillas simples, PowerShell no tiene que
analizar el contenido que hay dentro de las comillas, por lo que el código se ejecuta un
poco más rápido.

Cree un objeto personalizado para probar la entrada de la canalización por nombre de


propiedad para el parámetro Name de Stop-Service .

PowerShell

$CustomObject = [pscustomobject]@{
Name = 'w32time'
}

El contenido de la variable CustomObject es un tipo de objeto PSCustomObject y


contiene una propiedad denominada Name.

PowerShell

$CustomObject | Get-Member

Output

TypeName: System.Management.Automation.PSCustomObject
Name MemberType Definition
---- ---------- ----------
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
Name NoteProperty string Name=w32time

Si va a delimitar la variable $CustomObject con comillas, es mejor usar las dobles. De lo


contrario, con las comillas simples, la cadena literal $CustomObject se canaliza a Get-
Member , en lugar del valor que contiene la variable.

Aunque la canalización de los contenidos de $CustomObject al cmdlet Stop-Service


enlaza al parámetro Name, en esta ocasión enlaza por nombre de propiedad, en lugar
de por valor, porque el contenido de $CustomObject es un objeto que tiene una
propiedad denominada Name.

En este ejemplo, creo otro objeto personalizado con un nombre de propiedad diferente,
como Service.

PowerShell

$CustomObject = [pscustomobject]@{
Service = 'w32time'
}

Se genera un error al tratar de canalizar $CustomObject a Stop-Service porque no


produce un objeto ServiceController o String, y no tiene una propiedad denominada
Name.

PowerShell

$CustomObject | Stop-Service

Output

Stop-Service : Cannot find any service with service name


'@{Service=w32time}'.
At line:1 char:17
+ $CustomObject | Stop-Service
+
+ CategoryInfo : ObjectNotFound: (@{Service=w32time}:String)
[Stop-Service]
, ServiceCommandException
+ FullyQualifiedErrorId :
NoServiceFoundForGivenName,Microsoft.PowerShell.Commands.S
topServiceCommand

Si la salida de un comando no está alineada con las opciones de entrada de canalización


de otro comando, se puede usar Select-Object para cambiar el nombre de la
propiedad, de modo que las propiedades se alineen correctamente.

PowerShell

$CustomObject |
Select-Object -Property @{name='Name';expression={$_.Service}} |
Stop-Service

En este ejemplo, se usó Select-Object para cambiar el nombre de la propiedad Service


a una propiedad denominada Name.

La sintaxis de este ejemplo puede parecer un poco complicada al principio. Lo que he


aprendido es que no es posible aprenderse la sintaxis copiando y pegando código. Es
necesario dedicar tiempo a escribir código. Después de hacerlo varias veces, se
convierte en algo natural. Contar con varios monitores es una ventaja enorme porque
puede mostrar el código de ejemplo en una pantalla y escribirlo en la otra.

En ocasiones, puede ser necesario utilizar un parámetro que no acepte la entrada de


canalización. En el siguiente ejemplo se muestra cómo se puede utilizar la salida de un
comando como entrada para otro. En primer lugar, guarde el nombre para mostrar de
un par de servicios de Windows en un archivo de texto.

PowerShell

'Background Intelligent Transfer Service', 'Windows Time' |


Out-File -FilePath $env:TEMP\services.txt

Puede ejecutar el comando que proporciona la salida necesaria entre paréntesis como
valor del parámetro del comando que requiere la entrada.

PowerShell

Stop-Service -DisplayName (Get-Content -Path $env:TEMP\services.txt)

Esto es igual que el orden en el que se tienen que resolver las operaciones de álgebra
(para aquellas personas se acuerdan de cómo funcionan). El comando entre paréntesis
siempre se ejecuta antes que la parte del comando que queda fuera.
PowerShellGet
PowerShellGet es un módulo de PowerShell que contiene comandos para detectar,
instalar, publicar y actualizar módulos de PowerShell (y otros artefactos) en un
repositorio de NuGet o a partir de este. PowerShellGet se incluye con la versión 5.0 de
PowerShell y versiones posteriores. Está disponible como descarga independiente de la
versión 3.0 de PowerShell y posteriores.

Microsoft hospeda un repositorio de NuGet en línea denominado Galería de


PowerShell . Aunque este repositorio está hospedado por Microsoft, Microsoft no es el
autor de la mayoría de los módulos incluidos en él. Cualquier código obtenido de la
Galería de PowerShell debe revisarse minuciosamente en un entorno de prueba aislado
antes de considerarlo adecuado para su uso en uno de producción.

Para la mayoría de las empresas es recomendable hospedar su propio repositorio de


NuGet privado e interno, donde puedan publicar sus módulos de uso interno, así como
los módulos que hayan descargado de otros orígenes, una vez validados como no
maliciosos.

Use el cmdlet Find-Module que forma parte del módulo PowerShellGet para buscar en la
Galería de PowerShell un módulo que escribí y que se llama MrToolkit.

PowerShell

Find-Module -Name MrToolkit

Output

NuGet provider is required to continue


PowerShellGet requires NuGet provider version '2.8.5.201' or newer to
interact with
NuGet-based repositories. The NuGet provider must be available in
'C:\Program
Files\PackageManagement\ProviderAssemblies' or
'C:\Users\MrAdmin\AppData\Local\PackageManagement\ProviderAssemblies'. You
can also
install the NuGet provider by running 'Install-PackageProvider -Name NuGet
-MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to install and
import the
NuGet provider now?
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"):

Version Name Repository


Description
------- ---- ---------- --------
---
1.1 MrToolkit PSGallery Misc
PowerShell Tools

La primera vez que use uno de los comandos del módulo de PowerShellGet, se le pedirá
que instale el proveedor de NuGet.

Para instalar el módulo MrToolkit, canalice el comando anterior a Install-Module .

PowerShell

Find-Module -Name MrToolkit | Install-Module

Output

Untrusted repository
You are installing the modules from an untrusted repository. If you trust
this
repository, change its InstallationPolicy value by running the Set-
PSRepository cmdlet.
Are you sure you want to install the modules from
'https://www.powershellgallery.com/api/v2/'?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "N"): y

Como la Galería de PowerShell es un repositorio que no es de confianza, se le pedirá


que apruebe la instalación del módulo.

Búsqueda de la entrada de canalización de


forma sencilla
El módulo MrToolkit contiene una función denominada Get-MrPipelineInput . Este
cmdlet se puede usar para determinar fácilmente qué parámetros de un comando
aceptan la entrada de canalización, qué tipo de objeto aceptan y si aceptan la entrada
de canalización por valor o por nombre de propiedad.

PowerShell

Get-MrPipelineInput -Name Stop-Service

Output

ParameterName ParameterType ValueFromPipeline


ValueFromPipelineByPropertyName
------------- ------------- ----------------- --
-------------
InputObject System.ServiceProcess.ServiceController[] True
False
Name System.String[] True
True

Como puede ver, la misma información que se determinó anteriormente revisando la


ayuda se puede determinar fácilmente con esta función.

Resumen
En este capítulo ha aprendido muchas cosas sobre los comandos únicos de una línea de
PowerShell. Ha aprendido que el número de líneas físicas de un comando no determina
si es un comando único de una línea de PowerShell o no. También ha aprendido qué son
el filtrado a la izquierda, la canalización y PowerShellGet.

Revisar
1. ¿Qué es un comando único de una línea de PowerShell?
2. ¿Cuáles son algunos de los caracteres en los que se pueden insertar saltos de línea
naturales en PowerShell?
3. ¿Por qué debería usar el filtrado a la izquierda?
4. ¿Cuáles son las dos formas en las que un comando de PowerShell puede aceptar la
entrada de canalización?
5. ¿Por qué no se debe confiar en los comandos que se encuentran en la Galería de
PowerShell?

Lecturas recomendadas
about_pipelines
about_Command_Syntax
about_Parameters
PowerShellGet: The BIG EASY way to discover, install, and update PowerShell
modules (PowerShellGet: la forma más fácil de detectar, instalar y actualizar los
módulos de PowerShell)
Capítulo 5: Formato, alias, proveedores,
comparación
Artículo • 13/04/2023

Requisitos
Algunos de los ejemplos que se muestran en este capítulo necesitan el módulo SQL
Server PowerShell. El módulo se instala como parte de SQL Server Management Studio
(SSMS). También se usa en capítulos posteriores. Descárguelo e instálelo en el equipo
del entorno de laboratorio de Windows 10.

Formato a la derecha
En el capítulo 4 ha aprendido a filtrar lo máximo posible a la izquierda. La regla para
aplicar formato manualmente a la salida de un comando es similar a esa regla, salvo que
se debe producir lo máximo posible a la derecha.

Los comandos de formato más comunes son Format-Table y Format-List . También se


pueden usar Format-Wide y Format-Custom , pero son menos comunes.

Como se ha mencionado en el capítulo 3, un comando que devuelve más de cuatro


propiedades tiene como valor predeterminado una lista, a menos que se use formato
personalizado.

PowerShell

Get-Service -Name w32time | Select-Object -Property Status, DisplayName,


Can*

Output

Status : Running
DisplayName : Windows Time
CanPauseAndContinue : False
CanShutdown : True
CanStop : True

Use el cmdlet Format-Table para invalidar manualmente el formato y mostrar la salida


en una tabla en lugar de una lista.
PowerShell

Get-Service -Name w32time | Select-Object -Property Status, DisplayName,


Can* |
Format-Table

Output

Status DisplayName CanPauseAndContinue CanShutdown CanStop


------ ----------- ------------------- ----------- -------
Running Windows Time False True True

La salida predeterminada de Get-Service es tres propiedades en una tabla.

PowerShell

Get-Service -Name w32time

Output

Status Name DisplayName


------ ---- -----------
Running w32time Windows Time

Use el cmdlet Format-List para invalidar el formato predeterminado y devolver los


resultados en una lista.

PowerShell

Get-Service -Name w32time | Format-List

Output

Name : w32time
DisplayName : Windows Time
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : True
CanStop : True
ServiceType : Win32ShareProcess

Observe que con solo canalizar Get-Service a Format-List , ha devuelto propiedades


adicionales. Esto no ocurre con todos los comandos debido a la manera en que el
formato de ese comando concreto se configura en segundo plano.

Lo primero que se debe tener en cuenta con los cmdlets de formato es que generan
objetos de formato que son diferentes a los objetos normales de PowerShell.

PowerShell

Get-Service -Name w32time | Format-List | Get-Member

Output

TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatStartData

Name MemberType Definition


---- ---------- ----------
Equals Method bool Equals(System.Object
obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
autosizeInfo Property
Microsoft.PowerShell.Commands.Inter...
ClassId2e4f51ef21dd47e99d3c952918aff9cd Property string
ClassId2e4f51ef21dd47e99d3c9...
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...
pageFooterEntry Property
Microsoft.PowerShell.Commands.Inter...
pageHeaderEntry Property
Microsoft.PowerShell.Commands.Inter...
shapeInfo Property
Microsoft.PowerShell.Commands.Inter...

TypeName: Microsoft.PowerShell.Commands.Internal.Format.GroupStartData

Name MemberType Definition


---- ---------- ----------
Equals Method bool Equals(System.Object
obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
ClassId2e4f51ef21dd47e99d3c952918aff9cd Property string
ClassId2e4f51ef21dd47e99d3c9...
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...
shapeInfo Property
Microsoft.PowerShell.Commands.Inter...

TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatEntryData

Name MemberType Definition


---- ---------- ----------
Equals Method bool Equals(System.Object
obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
ClassId2e4f51ef21dd47e99d3c952918aff9cd Property string
ClassId2e4f51ef21dd47e99d3c9...
formatEntryInfo Property
Microsoft.PowerShell.Commands.Inter...
outOfBand Property bool outOfBand {get;set;}
writeStream Property
Microsoft.PowerShell.Commands.Inter...

TypeName: Microsoft.PowerShell.Commands.Internal.Format.GroupEndData

Name MemberType Definition


---- ---------- ----------
Equals Method bool Equals(System.Object
obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
ClassId2e4f51ef21dd47e99d3c952918aff9cd Property string
ClassId2e4f51ef21dd47e99d3c9...
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...

TypeName: Microsoft.PowerShell.Commands.Internal.Format.FormatEndData

Name MemberType Definition


---- ---------- ----------
Equals Method bool Equals(System.Object
obj)
GetHashCode Method int GetHashCode()
GetType Method type GetType()
ToString Method string ToString()
ClassId2e4f51ef21dd47e99d3c952918aff9cd Property string
ClassId2e4f51ef21dd47e99d3c9...
groupingEntry Property
Microsoft.PowerShell.Commands.Inter...

Esto significa que los comandos de formato no se pueden canalizar a la mayoría de los
demás comandos. Se pueden canalizar a algunos de los comandos de Out-* , pero eso
es todo. Por esta razón, se recomienda aplicar cualquier formato al extremo de la línea
(formato a la derecha).

Alias
Un alias de PowerShell es un nombre más corto para un comando. PowerShell incluye
un conjunto de alias integrados y también permite definir alias propios.

Se usa el cmdlet Get-Alias para buscar alias. Si ya conoce el alias de un comando, se


usa el parámetro Name para determinar con qué comando está asociado el alias.

PowerShell

Get-Alias -Name gcm

Output

CommandType Name Version


Source
----------- ---- -------
------
Alias gcm -> Get-Command

Se pueden especificar varios alias para el valor del parámetro Name.

PowerShell

Get-Alias -Name gcm, gm

Output

CommandType Name Version


Source
----------- ---- -------
------
Alias gcm -> Get-Command
Alias gm -> Get-Member

A menudo se ve el parámetro Name omitido, puesto que es un parámetro posicional.

PowerShell

Get-Alias gm

Output

CommandType Name Version


Source
----------- ---- -------
------
Alias gm -> Get-Member
Si quiere buscar alias de un comando, debe usar el parámetro Definition.

PowerShell

Get-Alias -Definition Get-Command, Get-Member

Output

CommandType Name Version


Source
----------- ---- -------
------
Alias gcm -> Get-Command
Alias gm -> Get-Member

El parámetro Definition no se puede usar de forma posicional, así que ha de


especificarse.

Los alias pueden ahorrarle algunas pulsaciones de tecla y están bien cuando se escriben
comandos en la consola. No deben usarse en scripts ni en ningún código que se estén
guardando o compartiendo con otros usuarios. Como se ha mencionado anteriormente
en este libro, los nombres completos de los parámetros y los cmdlets son
autoexplicativos y facilitan las compresión.

Tenga cuidado a la hora de crear sus propios alias, ya que solo existen en la sesión
actual de PowerShell del equipo.

Proveedores
Un proveedor de PowerShell es una interfaz que permite un acceso similar al que ofrece
el sistema de archivos a un almacén de datos. Hay varios proveedores integrados en
PowerShell.

PowerShell

Get-PSProvider

Output

Name Capabilities Drives


---- ------------ ------
Registry ShouldProcess, Transactions {HKLM, HKCU}
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess, Credentials {C, A, D}
Function ShouldProcess {Function}
Variable ShouldProcess {Variable}
Certificate ShouldProcess {Cert}
WSMan Credentials {WSMan}

Como puede ver en los resultados anteriores, hay proveedores integrados para el
registro, los alias, las variables de entorno, el sistema de archivos, las funciones, las
variables, los certificados y WSMan.

Las unidades reales que usan estos proveedores para exponer su almacén de datos se
pueden determinar con el cmdlet Get-PSDrive . El cmdlet Get-PSDrive no solo muestra
las unidades expuestas por los proveedores, sino que también muestra unidades lógicas
de Windows que incluyen unidades asignadas a recursos compartidos de red.

PowerShell

Get-PSDrive

Output

Name Used (GB) Free (GB) Provider Root


---- --------- --------- -------- ----
A FileSystem A:\
Alias Alias
C 14.41 112.10 FileSystem C:\
Cert Certificate \
D FileSystem D:\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Variable Variable
WSMan WSMan

Módulos de terceros como el módulo Active Directory PowerShell y el módulo


SQLServer PowerShell agregan su propio proveedor de PowerShell y PSDrive.

Importe los módulos Active Directory y SQL Server PowerShell.

PowerShell

Import-Module -Name ActiveDirectory, SQLServer

Compruebe si se han agregado otros proveedores de PowerShell.


PowerShell

Get-PSProvider

Output

Name Capabilities Drives


---- ------------ ------
Registry ShouldProcess, Transactions {HKLM, HKCU}
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess, Credentials {C, A, D}
Function ShouldProcess {Function}
Variable ShouldProcess {Variable}
ActiveDirectory Include, Exclude, Filter, Shoul... {AD}
SqlServer Credentials {SQLSERVER}

Observe que, en el conjunto de resultados anterior, ahora hay dos nuevos proveedores
de PowerShell, uno de Active Directory y otro de SQL Server.

También se ha agregado un PSDrive para cada uno de esos módulos.

PowerShell

Get-PSDrive

Output

Name Used (GB) Free (GB) Provider Root


---- --------- --------- -------- ----
A FileSystem A:\
AD ActiveDire... //RootDSE/
Alias Alias
C 19.38 107.13 FileSystem C:\
Cert Certificate \
D FileSystem D:\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
SQLSERVER SqlServer SQLSERVER:\
Variable Variable
WSMan WSMan

Se puede acceder a los PSDrive igual que a un sistema de archivos tradicional.

PowerShell
Get-ChildItem -Path Cert:\LocalMachine\CA

Output

PSParentPath: Microsoft.PowerShell.Security\Certificate::LocalMachine\CA

Thumbprint Subject
---------- -------
FEE449EE0E3965A5246F000E87FDE2A065FD89D4 CN=Root Agency
D559A586669B08F46A30A133F8A9ED3D038E2EA8 OU=www.verisign.com/CPS
Incorporated LIABI...
109F1CAED645BB78B3EA2B94C0697C740733031C CN=Microsoft Windows Hardware
Compatibility,...

Operadores de comparación
PowerShell contiene una serie de operadores de comparación que se usan para
comparar valores o buscar valores que coincidan con determinados patrones. La tabla
5-1 contiene una lista de operadores de comparación de PowerShell.

Operator Definición

-eq Igual a

-ne No es igual a

-gt Mayor que

-ge Mayor o igual que

-lt Menor que

-le Menor o igual que

-Like Busca coincidencias con el carácter comodín *

-NotLike No busca coincidencias con el carácter comodín *

-Match Busca coincidencias con la expresión regular especificada

-NotMatch No busca coincidencias con la expresión regular especificada

-Contains Determina si una colección contiene un valor especificado

-NotContains Determina si una colección no contiene un valor especificado

-In Determina si un valor especificado está en una colección


Operator Definición

-NotIn Determina si un valor especificado no está en una colección

-Replace Reemplaza el valor especificado

Todos los operadores de la tabla 5-1 no distinguen mayúsculas de minúsculas. Coloque


una c delante del operador de la tabla 5-1 para que distinga mayúsculas de minúsculas.
Por ejemplo, -ceq es la versión que distingue mayúsculas de minúsculas del operador
de comparación -eq .

La expresión en mayúsculas "PowerShell" es igual a la expresión en minúsculas


"powershell" con el operador de comparación Igual a.

PowerShell

'PowerShell' -eq 'powershell'

Output

True

No es igual si se usa la versión que distingue mayúsculas de minúsculas del operador de


comparación Igual a.

PowerShell

'PowerShell' -ceq 'powershell'

Output

False

El operador de comparación No es igual a invierte la condición.

PowerShell

'PowerShell' -ne 'powershell'

Output

False
Mayor que, Mayor o igual que, Menor que y Menor o igual que funcionan con valores
de cadena o numéricos.

PowerShell

5 -gt 5

Output

False

Si se usa Mayor o igual que en lugar de Mayor que en el ejemplo anterior, se devuelve
el valor booleano true, ya que cinco es igual a cinco.

PowerShell

5 -ge 5

Output

True

En función de los resultados de los dos ejemplos anteriores, probablemente pueda


adivinar el funcionamiento de Menor que y Menor o igual que.

PowerShell

5 -lt 10

Output

True

Los operadores -Like y -Match pueden ser confusos, incluso para usuarios
experimentados de PowerShell. -Like se usa con los caracteres comodín * y ? para
realizar coincidencias "como".

PowerShell

'PowerShell' -like '*shell'

Output
True

-Match usa una expresión regular para realizar la búsqueda de coincidencias.

PowerShell

'PowerShell' -match '^*.shell$'

Output

True

Use el operador de intervalo para almacenar los números del 1 al 10 en una variable.

PowerShell

$Numbers = 1..10

Output

Determine si la variable $Numbers incluye 15.

PowerShell

$Numbers -contains 15

Output

False

Determine si incluye el número 10.

PowerShell

$Numbers -contains 10

Output

True
-NotContains invierte la lógica para ver si la variable $Numbers no contiene un valor.

PowerShell

$Numbers -notcontains 15

Output

True

En el ejemplo anterior se devuelve el valor booleano true porque es verdad que la


variable $Numbers no contiene 15. Pero contiene el número 10, por lo que es false
cuando se prueba.

PowerShell

$Numbers -notcontains 10

Output

False

El operador de comparación "in" se incorporó por primera vez en la versión 3.0 de


PowerShell. Se usa para determinar si un valor está "en" una matriz. La variable $Numbers
es una matriz, ya que contiene varios valores.

PowerShell

15 -in $Numbers

Output

False

Es decir, -in realiza la misma prueba que el operador de comparación contains, excepto
que la hace desde la dirección opuesta.

PowerShell

10 -in $Numbers

Output
True

15 no está en la matriz $Numbers , por lo que en el ejemplo siguiente se devuelve false.

PowerShell

15 -in $Numbers

Output

False

Al igual que el operador -contains , not invierte la lógica del operador -in .

PowerShell

10 -notin $Numbers

Output

False

En el ejemplo anterior se devuelve false porque la matriz $Numbers incluye 10 y la


condición era probar para determinar si no contenía 10.

15 "no está en" la matriz $Numbers , por lo que devuelve el valor booleano true.

PowerShell

15 -notin $Numbers

Output

True

El operador -replace hace simplemente lo que está pensando. Se usa para reemplazar
algo. Si se especifica un valor, ese valor se reemplaza por nada. En el ejemplo siguiente,
se reemplaza "Shell" por nada.

PowerShell

'PowerShell' -replace 'Shell'


Output

Power

Si quiere reemplazar un valor por otro, especifique el nuevo valor después del patrón
que quiere reemplazar. SQL Saturday en Baton Rouge es un evento en el que intento
hablar cada año. En el ejemplo siguiente, reemplazo la palabra "Saturday" por la
abreviatura "Sat".

PowerShell

'SQL Saturday - Baton Rouge' -Replace 'saturday','Sat'

Output

SQL Sat - Baton Rouge

También hay métodos como Replace() que se pueden usar para reemplazar elementos
de forma similar a como funciona el operador replace. Pero el operador -Replace no
distingue mayúsculas de minúsculas de forma predeterminada y el método Replace() sí.

PowerShell

'SQL Saturday - Baton Rouge'.Replace('saturday','Sat')

Output

SQL Saturday - Baton Rouge

Observe que la palabra "Saturday" no se ha reemplazado en el ejemplo anterior. Esto se


debe a que se ha especificado en un caso diferente al original. Cuando se especifica la
palabra "Saturday" en el mismo caso que el original, el método Replace() la reemplaza
según lo esperado.

PowerShell

'SQL Saturday - Baton Rouge'.Replace('Saturday','Sat')

Output

SQL Sat - Baton Rouge


Tenga cuidado al usar métodos para transformar datos, ya que se pueden producir
problemas imprevistos, por ejemplo errores en la prueba de Turquía. Para obtener un
ejemplo, vea la entrada de blog titulada Uso de Pester para probar código de
PowerShell con otras referencias culturales . Mi recomendación es usar un operador en
lugar de un método siempre que sea posible para evitar estos tipos de problemas.

Aunque los operadores de comparación se pueden usar como se muestra en los


ejemplos anteriores, yo normalmente los uso con el cmdlet Where-Object para realizar
algún tipo de filtrado.

Resumen
En este capítulo ha obtenido información sobre una serie de temas distintos para incluir
formato a la derecha, alias, proveedores y operadores de comparación.

Revisar
1. ¿Por qué es necesario aplicar el formato lo máximo posible a la derecha?
2. ¿Cómo se determina el cmdlet real para el alias % ?
3. ¿Por qué no se deben usar alias en los scripts que se guardan ni en el código que
se comparte con otros usuarios?
4. Realice una lista de directorios en las unidades que están asociadas a uno de los
proveedores del registro.
5. ¿Cuál es una de las principales ventajas del empleo del operador replace en lugar
del método replace?

Lecturas recomendadas
Format-Table
Format-List
Format-Wide
about_Aliases
about_Providers
about_Comparison_Operators
about_Arrays
Capítulo 6: Control de flujo
Artículo • 13/04/2023

Scripting
Pasar de escribir secuencias de una frase de PowerShell a escribir scripts suena mucho
más complicado de lo que realmente es. Un script no es más que los mismos comandos
o comandos similares que ejecutaría de forma interactiva en la consola de PowerShell,
salvo que se guardan como un archivo .PS1 . Hay algunas construcciones de scripting
que puede usar, como un bucle foreach en lugar del cmdlet ForEach-Object . Para los
principiantes, las diferencias pueden ser confusas, especialmente cuando se considera
que foreach es una construcción de scripting y un alias para el cmdlet ForEach-Object .

Bucle
Uno de los grandes aspectos de PowerShell es que, una vez que haya averiguado cómo
hacer algo para un elemento, le será casi tan fácil realizar la misma tarea para cientos de
elementos. Solo tendrá que recorrer en bucle los elementos mediante uno de los
muchos tipos diferentes de bucles de PowerShell.

ForEach-Object
ForEach-Object es un cmdlet para iterar los elementos de una canalización como, por

ejemplo, con las secuencias de una frase de PowerShell. ForEach-Object transmite los
objetos a través de la canalización.

Aunque el parámetro Module de Get-Command acepta varios valores que son cadenas,
solo los acepta a través de la entrada de canalización por nombre de propiedad o a
través de la entrada de parámetros. En el siguiente escenario, si quisiera canalizar dos
cadenas por valor a Get-Command para usarlas con el parámetro Module, tendría que
usar el cmdlet ForEach-Object .

PowerShell

'ActiveDirectory', 'SQLServer' |
ForEach-Object {Get-Command -Module $_} |
Group-Object -Property ModuleName -NoElement |
Sort-Object -Property Count -Descending
Output

Count Name
----- ----
147 ActiveDirectory
82 SqlServer

En el ejemplo anterior, $_ es el objeto actual. A partir de la versión 3.0 de PowerShell, se


puede usar $PSItem en lugar de $_ . Pero veo que los usuarios de PowerShell más
experimentados siguen prefiriendo usar $_ porque es compatible con versiones
anteriores y requiere menos escritura.

Al usar la palabra clave foreach , debe almacenar todos los elementos en la memoria
antes de iterarlos, lo que puede resultar difícil si no sabe con cuántos elementos está
trabajando.

PowerShell

$ComputerName = 'DC01', 'WEB01'


foreach ($Computer in $ComputerName) {
Get-ADComputer -Identity $Computer
}

Output

DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com


DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :

DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :

En numerosas ocasiones, es necesario un bucle como foreach o ForEach-Object . De lo


contrario, recibirá un mensaje de error.
PowerShell

Get-ADComputer -Identity 'DC01', 'WEB01'

Output

Get-ADComputer : Cannot convert 'System.Object[]' to the type


'Microsoft.ActiveDirectory.Management.ADComputer' required by parameter
'Identity'.
Specified method is not supported.
At line:1 char:26
+ Get-ADComputer -Identity 'DC01', 'WEB01'
+ ~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Get-ADComputer],
ParameterBindingExc
eption
+ FullyQualifiedErrorId :
CannotConvertArgument,Microsoft.ActiveDirectory.Management
.Commands.GetADComputer

Otras veces, puede obtener los mismos resultados eliminando el bucle por completo.
Consulte la ayuda del cmdlet para comprender sus opciones.

PowerShell

'DC01', 'WEB01' | Get-ADComputer

Output

DistinguishedName : CN=DC01,OU=Domain Controllers,DC=mikefrobbins,DC=com


DNSHostName : dc01.mikefrobbins.com
Enabled : True
Name : DC01
ObjectClass : computer
ObjectGUID : c38da20c-a484-469d-ba4c-bab3fb71ae8e
SamAccountName : DC01$
SID : S-1-5-21-2989741381-570885089-3319121794-1001
UserPrincipalName :

DistinguishedName : CN=WEB01,CN=Computers,DC=mikefrobbins,DC=com
DNSHostName : web01.mikefrobbins.com
Enabled : True
Name : WEB01
ObjectClass : computer
ObjectGUID : 33aa530e-1e31-40d8-8c78-76a18b673c33
SamAccountName : WEB01$
SID : S-1-5-21-2989741381-570885089-3319121794-1107
UserPrincipalName :
Como puede ver en los ejemplos anteriores, el parámetro Identity de Get-ADComputer
solo acepta un valor único cuando se proporciona a través de la entrada de parámetros,
pero admite varios elementos cuando la entrada se proporciona a través de la entrada
de canalización.

Para
Un bucle for itera si una condición especificada es true. No utilizo el bucle for con
frecuencia, pero tiene sus usos.

PowerShell

for ($i = 1; $i -lt 5; $i++) {


Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
}

Output

Sleeping for 1 seconds


Sleeping for 2 seconds
Sleeping for 3 seconds
Sleeping for 4 seconds

En el ejemplo anterior, el bucle se iterará cuatro veces empezando por el número uno y
continuará siempre y cuando la variable de contador $i sea inferior a 5. Se suspenderá
durante un total de 10 segundos.

Lo que es necesario hacer:


Hay dos bucles do diferentes en PowerShell. Do Until se ejecuta si la condición
especificada es false.

PowerShell

$number = Get-Random -Minimum 1 -Maximum 10


do {
$guess = Read-Host -Prompt "What's your guess?"
if ($guess -lt $number) {
Write-Output 'Too low!'
}
elseif ($guess -gt $number) {
Write-Output 'Too high!'
}
}
until ($guess -eq $number)

Output

What's your guess?: 1


Too low!
What's your guess?: 2
Too low!
What's your guess?: 3

El ejemplo anterior es un juego de números que continúa hasta que el valor que se
estima es igual al número generado por el cmdlet Get-Random .

Do While es justo lo contrario. Se ejecuta siempre que la condición especificada se

evalúe como true.

PowerShell

$number = Get-Random -Minimum 1 -Maximum 10


do {
$guess = Read-Host -Prompt "What's your guess?"
if ($guess -lt $number) {
Write-Output 'Too low!'
} elseif ($guess -gt $number) {
Write-Output 'Too high!'
}
}
while ($guess -ne $number)

Output

What's your guess?: 1


Too low!
What's your guess?: 2
Too low!
What's your guess?: 3
Too low!
What's your guess?: 4

Se logran los mismos resultados con un bucle Do While invirtiendo la condición de


prueba en no es igual a.

Los bucles Do siempre se ejecutan al menos una vez porque la condición se evalúa al
final del bucle.
While
De forma similar al bucle Do While , un bucle While se ejecuta siempre que la condición
especificada sea true. Sin embargo, la diferencia es que un bucle While evalúa la
condición en la parte superior del bucle antes de que se ejecute el código. Por lo tanto,
no se ejecuta si la condición se evalúa como false.

PowerShell

$date = Get-Date -Date 'November 22'


while ($date.DayOfWeek -ne 'Thursday') {
$date = $date.AddDays(1)
}
Write-Output $date

Output

Thursday, November 23, 2017 12:00:00 AM

En el ejemplo anterior se calcula qué día se celebra Acción de Gracias en los Estados
Unidos. Siempre es el cuarto jueves de noviembre. Por lo tanto, el bucle comienza con el
día 22 de noviembre y agrega un día si el día de la semana no es igual a jueves. Si el 22
es un jueves, el bucle no se ejecuta en absoluto.

Break, Continue y Return


Break está diseñado para salir de un bucle. También se suele usar con la instrucción

switch .

PowerShell

for ($i = 1; $i -lt 5; $i++) {


Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
break
}

Output

Sleeping for 1 seconds

La instrucción break que se muestra en el ejemplo anterior hace que el bucle salga de la
primera iteración.
Continue está diseñado para pasar a la siguiente iteración de un bucle.

PowerShell

while ($i -lt 5) {


$i += 1
if ($i -eq 3) {
continue
}
Write-Output $i
}

Output

1
2
4
5

En el ejemplo anterior, generará los números 1, 2, 4 y 5. Omite el número 3 y continúa


con la siguiente iteración del bucle. De forma similar a break , continue sale del bucle,
salvo que solo lo hace en la iteración actual. La ejecución continúa con la siguiente
iteración, en lugar de salir del bucle y detenerse.

Return está diseñado para salir del ámbito existente.

PowerShell

$number = 1..10
foreach ($n in $number) {
if ($n -ge 4) {
Return $n
}
}

Output

Observe que en el ejemplo anterior, devuelve los resultados del primer resultado y, a
continuación, sale del bucle. Puede encontrar una explicación más detallada de la
instrucción de resultado en uno de los artículos del blog: "Palabra clave Return de
PowerShell" .
Resumen
En este capítulo, ha obtenido información acerca de los diferentes tipos de bucles que
existen en PowerShell.

Revisar
1. ¿Cuál es la diferencia entre el cmdlet ForEach-Object y la construcción de scripting
foreach?
2. ¿Cuál es la ventaja principal de utilizar un bucle While en lugar de un bucle Do
while o Do until?
3. ¿En qué se diferencian las instrucciones break y continue?

Lecturas recomendadas
ForEach-Object
about_ForEach
about_For
about_Do
about_While
about_Break
about_Continue
about_Return
Capítulo 7: Trabajo con WMI
Artículo • 13/04/2023

WMI y CIM
PowerShell incluye de forma predeterminada cmdlets para trabajar con otras
tecnologías, como Instrumental de administración de Windows (WMI). Hay varios
cmdlets nativos de WMI que existen en PowerShell sin necesidad de instalar ningún
software ni módulo adicional.

PowerShell ha contado con cmdlets para trabajar con WMI desde el principio. Se puede
usar Get-Command para determinar qué cmdlets de WMI existen en PowerShell. Los
siguientes resultados corresponden a mi equipo del entorno de laboratorio de Windows
10 con la versión 5.1 de PowerShell. Sus resultados pueden diferir en función de la
versión de PowerShell que esté ejecutando.

PowerShell

Get-Command -Noun WMI*

Output

CommandType Name Version


Source
----------- ---- -------
------
Cmdlet Get-WmiObject 3.1.0.0
Microsof...
Cmdlet Invoke-WmiMethod 3.1.0.0
Microsof...
Cmdlet Register-WmiEvent 3.1.0.0
Microsof...
Cmdlet Remove-WmiObject 3.1.0.0
Microsof...
Cmdlet Set-WmiInstance 3.1.0.0
Microsof...

Los cmdlets de Modelo de información común (CIM) se incorporaron en la versión 3.0


de PowerShell. Los cmdlets de CIM están diseñados para usarse en equipos Windows y
no Windows. Los cmdlets de WMI están en desuso, por lo que recomiendo usar los
cmdlets de CIM en lugar de los más antiguos de WMI.
Todos los cmdlets de CIM están incluidos en un módulo. Para obtener una lista de los
cmdlets de CIM, use Get-Command con el parámetro Module, como se muestra en el
ejemplo siguiente.

PowerShell

Get-Command -Module CimCmdlets

Output

CommandType Name Version


Source
----------- ---- -------
------
Cmdlet Export-BinaryMiLog 1.0.0.0
CimCmdlets
Cmdlet Get-CimAssociatedInstance 1.0.0.0
CimCmdlets
Cmdlet Get-CimClass 1.0.0.0
CimCmdlets
Cmdlet Get-CimInstance 1.0.0.0
CimCmdlets
Cmdlet Get-CimSession 1.0.0.0
CimCmdlets
Cmdlet Import-BinaryMiLog 1.0.0.0
CimCmdlets
Cmdlet Invoke-CimMethod 1.0.0.0
CimCmdlets
Cmdlet New-CimInstance 1.0.0.0
CimCmdlets
Cmdlet New-CimSession 1.0.0.0
CimCmdlets
Cmdlet New-CimSessionOption 1.0.0.0
CimCmdlets
Cmdlet Register-CimIndicationEvent 1.0.0.0
CimCmdlets
Cmdlet Remove-CimInstance 1.0.0.0
CimCmdlets
Cmdlet Remove-CimSession 1.0.0.0
CimCmdlets
Cmdlet Set-CimInstance 1.0.0.0
CimCmdlets

Los cmdlets de CIM siguen permitiendo trabajar con WMI, así que no se desconcierte si
alguien afirma "Cuando consulto WMI con los cmdlets de CIM de PowerShell..."

Como he mencionado anteriormente, WMI es una tecnología independiente de


PowerShell y simplemente se están usando los cmdlets de CIM para acceder a WMI.
Puede encontrar un VBScript antiguo que usa lenguaje de consulta de WMI (WQL) para
consultar WMI como en el ejemplo siguiente.

VB

strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
& "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")

Set colBIOS = objWMIService.ExecQuery _


("Select * from Win32_BIOS")

For each objBIOS in colBIOS


Wscript.Echo "Manufacturer: " & objBIOS.Manufacturer
Wscript.Echo "Name: " & objBIOS.Name
Wscript.Echo "Serial Number: " & objBIOS.SerialNumber
Wscript.Echo "SMBIOS Version: " & objBIOS.SMBIOSBIOSVersion
Wscript.Echo "Version: " & objBIOS.Version
Next

Puede tomar la consulta de WQL de ese VBScript y usarla con el cmdlet Get-
CimInstance sin ninguna modificación.

PowerShell

Get-CimInstance -Query 'Select * from Win32_BIOS'

Output

SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 3810-1995-1654-4615-2295-2755-89
Version : VRTUAL - 4001628

Así no es como yo normalmente consulto WMI con PowerShell, pero funciona y permite
migrar fácilmente los VBScript existentes a PowerShell. Al empezar a escribir un
comando único de una línea para consultar WMI, yo uso la sintaxis siguiente.

PowerShell

Get-CimInstance -ClassName Win32_BIOS

Output

SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 3810-1995-1654-4615-2295-2755-89
Version : VRTUAL - 4001628

Si solo quiero el número de serie, puedo canalizar la salida a Select-Object y especificar


únicamente la propiedad SerialNumber.

PowerShell

Get-CimInstance -ClassName Win32_BIOS | Select-Object -Property SerialNumber

Output

SerialNumber
------------
3810-1995-1654-4615-2295-2755-89

De forma predeterminada, hay varias propiedades que se recuperan en segundo plano


que nunca se usan. Es posible que no importe mucho al consultar WMI en el equipo
local. Pero una vez que se empieza a consultar equipos remotos, no solo se trata de
tiempo de procesamiento adicional para devolver esa información, sino también de
información innecesaria adicional que se debe extraer en la red. Get-CimInstance tiene
un parámetro Property que limita la información que se recupera. Esto hace que la
consulta a WMI sea más eficaz.

PowerShell

Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |


Select-Object -Property SerialNumber

Output

SerialNumber
------------
3810-1995-1654-4615-2295-2755-89

Los resultados anteriores han devuelto un objeto. Para devolver una cadena simple, use
el parámetro ExpandProperty.

PowerShell

Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber |


Select-Object -ExpandProperty SerialNumber
Output

3810-1995-1654-4615-2295-2755-89

También puede usar el estilo de puntos de sintaxis para devolver una cadena simple. Así
se elimina la necesidad de canalizar a Select-Object .

PowerShell

(Get-CimInstance -ClassName Win32_BIOS -Property SerialNumber).SerialNumber

Output

3810-1995-1654-4615-2295-2755-89

Consulta a equipos remotos con los cmdlets de


CIM
Sigo ejecutando PowerShell como administrador local que es usuario de dominio. Al
intentar consultar información de un equipo remoto mediante el cmdlet Get-
CimInstance , aparece un mensaje de error de acceso denegado.

PowerShell

Get-CimInstance -ComputerName dc01 -ClassName Win32_BIOS

Output

Get-CimInstance : Access is denied.


At line:1 char:1
+ Get-CimInstance -ComputerName dc01 -ClassName Win32_BIOS
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : PermissionDenied:
(root\cimv2:Win32_BIOS:String) [Get-CimI
nstance], CimException
+ FullyQualifiedErrorId : HRESULT
0x80070005,Microsoft.Management.Infrastructure.Cim
Cmdlets.GetCimInstanceCommand
+ PSComputerName : dc01

Muchas personas tienen problemas de seguridad con PowerShell, pero la verdad es que
se tienen exactamente los mismos permisos en PowerShell que en la GUI. Ni más ni
menos. El problema del ejemplo anterior es que el usuario que ejecuta PowerShell no
tiene derechos para consultar información de WMI desde el servidor DC01. Podría
volver a iniciar PowerShell como administrador de dominio, ya que Get-CimInstance no
tiene un parámetro Credential. Pero, confíe en mí, no es buena idea, porque todo lo que
ejecuto desde PowerShell se estaría ejecutando como administrador de dominio. Eso
podría ser peligroso desde el punto de vista de la seguridad en función de la situación.

Con el principio de privilegios mínimos, elevo a mi cuenta de administrador de dominio


por comando mediante el parámetro Credential, si un comando tiene uno. Get-
CimInstance no tiene un parámetro Credential, por lo que la solución de este escenario

es crear un elemento CimSession primero. Luego uso CimSession en lugar de un


nombre de equipo para consultar WMI en el equipo remoto.

PowerShell

$CimSession = New-CimSession -ComputerName dc01 -Credential (Get-Credential)

Output

cmdlet Get-Credential at command pipeline position 1


Supply values for the following parameters:
Credential

La sesión de CIM se ha almacenado en una variable de nombre $CimSession . Observe


que también he especificado el cmdlet Get-Credential entre paréntesis para que se
ejecute primero y me pida credenciales alternativas antes de crear la nueva sesión. Más
adelante en este capítulo muestro otra forma más eficaz de especificar credenciales
alternativas, pero es importante entender este concepto básico antes de complicarlo
más.

La sesión de CIM creada en el ejemplo anterior se puede usar ahora con el cmdlet Get-
CimInstance para consultar la información de BIOS desde WMI en el equipo remoto.

PowerShell

Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS

Output

SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 0986-6980-3916-0512-6608-8243-13
Version : VRTUAL - 4001628
PSComputerName : dc01
El uso de sesiones de CIM en lugar de simplemente especificar un nombre de equipo
ofrece varias ventajas adicionales. Al ejecutar varias consultas en el mismo equipo, el
uso de una sesión de CIM es más eficaz que el uso del nombre de equipo para cada
consulta. Al crear una sesión de CIM, solo se configura la conexión una vez. Luego,
varias consultas usan esa misma sesión para recuperar información. El uso del nombre
de equipo requiere los cmdlets para configurar y desmantelar la conexión con cada
consulta individual.

El cmdlet Get-CimInstance usa el protocolo WSMan de forma predeterminada, lo que


significa que el equipo remoto necesita la versión 3.0 o superior de PowerShell para
conectarse. En realidad, no es la versión de PowerShell lo que importa, sino la versión de
la pila. La versión de la pila se puede determinar mediante el cmdlet Test-WSMan . Debe
ser la versión 3.0. Esa es la versión que se encuentra con PowerShell versión 3.0 y
superior.

PowerShell

Test-WSMan -ComputerName dc01

Output

wsmid :
http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd
ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd
ProductVendor : Microsoft Corporation
ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0

Los cmdlets de WMI anteriores usan el protocolo DCOM, que es compatible con
versiones anteriores de Windows. Pero DCOM normalmente resulta bloqueado por el
firewall en las versiones más recientes de Windows. El cmdlet New-CimSessionOption
permite crear una conexión de protocolo DCOM para su uso con New-CimSession . Esto
permite usar el cmdlet Get-CimInstance para comunicarse con versiones de Windows
anteriores a Windows Server 2000. Esto también significa que no se necesita PowerShell
en el equipo remoto cuando se usa el cmdlet Get-CimInstance con un elemento
CimSession configurado para usar el protocolo DCOM.

Cree la opción del protocolo DCOM con el cmdlet New-CimSessionOption y almacénela


en una variable.

PowerShell

$DCOM = New-CimSessionOption -Protocol Dcom


Por eficacia, puede almacenar el administrador de dominio o las credenciales con
privilegios elevados en una variable, de modo que no tenga que escribirlos
constantemente para cada comando.

PowerShell

$Cred = Get-Credential

Output

cmdlet Get-Credential at command pipeline position 1


Supply values for the following parameters:
Credential

Yo tengo un servidor denominado SQL03 que ejecuta Windows Server 2008 (no R2). Es
el sistema operativo Windows Server más reciente sin PowerShell instalado de forma
predeterminada.

Cree un elemento CimSession para SQL03 mediante el protocolo DCOM.

PowerShell

$CimSession = New-CimSession -ComputerName sql03 -SessionOption $DCOM -


Credential $Cred

En el comando anterior, observe que esta vez he especificado la variable denominada


$Cred como valor del parámetro Credential en lugar de volver a escribirlos
manualmente.

La salida de la consulta es la misma independientemente del protocolo subyacente que


se use.

PowerShell

Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS

Output

SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 7237-7483-8873-8926-7271-5004-86
Version : VRTUAL - 4001628
PSComputerName : sql03
El cmdlet Get-CimSession se usa para ver qué elementos CimSession hay conectados
actualmente y qué protocolos están usando.

PowerShell

Get-CimSession

Output

Id : 1
Name : CimSession1
InstanceId : 80742787-e38e-41b1-a7d7-fa1369cf1402
ComputerName : dc01
Protocol : WSMAN

Id : 2
Name : CimSession2
InstanceId : 8fcabd81-43cf-4682-bd53-ccce1e24aecb
ComputerName : sql03
Protocol : DCOM

Recupere y almacene los dos elementos CimSession creados previamente en una


variable denominada $CimSession .

PowerShell

$CimSession = Get-CimSession

Consulte ambos equipos con un comando, uno con el protocolo WSMan y el otro con
DCOM.

PowerShell

Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS

Output

SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 0986-6980-3916-0512-6608-8243-13
Version : VRTUAL - 4001628
PSComputerName : dc01

SMBIOSBIOSVersion : 090006
Manufacturer : American Megatrends Inc.
Name : Intel(R) Xeon(R) CPU E3-1505M v5 @ 2.80GHz
SerialNumber : 7237-7483-8873-8926-7271-5004-86
Version : VRTUAL - 4001628
PSComputerName : sql03

He escrito muchas entradas de blog sobre los cmdlets de WMI y CIM. Una de las más
útiles trata de una función que he creado para determinar automáticamente si se debe
usar WSMan o DCOM y configurar la sesión de CIM automáticamente sin tener que
averiguar cuál de ellos de forma manual. Esa entrada de blog se titula Función de
PowerShell para crear CimSessions en equipos remotos con reserva para DCOM .

Cuando haya terminado con las sesiones de CIM, debe quitarlas con el cmdlet Remove-
CimSession . Para quitar todas las sesiones de CIM, simplemente canalice Get-CimSession

a Remove-CimSession .

PowerShell

Get-CimSession | Remove-CimSession

Resumen
En este capítulo ha aprendido a usar PowerShell para trabajar con WMI en equipos
locales y remotos. También ha aprendido a usar los cmdlets de CIM para trabajar con
equipos remotos con el protocolo WSMan o DCOM.

Revisar
1. ¿Cuál es la diferencia entre los cmdlets de WMI y CIM?
2. De forma predeterminada, ¿qué protocolo usa el cmdlet Get-CimInstance ?
3. ¿Cuáles son algunas de las ventajas que aporta el uso de una sesión de CIM en
lugar de especificar un nombre de equipo con Get-CimInstance ?
4. ¿Cómo se especifica un protocolo alternativo distinto al predeterminado para su
uso con Get-CimInstance ?
5. ¿Cómo se cierran o quitan las sesiones de CIM?

Lecturas recomendadas
about_WMI
about_WMI_Cmdlets
about_WQL
Módulo CimCmdlets
Vídeo: Uso de cmdlets de CIM y sesiones de CIM
Capítulo 8: Comunicación remota de
PowerShell
Artículo • 13/04/2023

PowerShell tiene muchas maneras diferentes de ejecutar comandos en equipos remotos.


En el capítulo anterior, vio cómo consultar WMI de forma remota mediante los cmdlets
CIM. PowerShell también incluye varios cmdlets que tienen un parámetro
ComputerName integrado.

Como se muestra en el ejemplo siguiente, Get-Command se puede usar con el parámetro


ParameterName para determinar qué comandos tienen un parámetro ComputerName.

PowerShell

Get-Command -ParameterName ComputerName

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Add-Computer 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Clear-EventLog 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Connect-PSSession 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Enter-PSSession 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Get-EventLog 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Get-HotFix 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Get-Process 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Get-PSSession 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Get-Service 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Get-WmiObject 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Invoke-Command 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Invoke-WmiMethod 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Limit-EventLog 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet New-EventLog 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet New-PSSession 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Receive-Job 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Receive-PSSession 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Register-WmiEvent 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Remove-Computer 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Remove-EventLog 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Remove-PSSession 3.0.0.0
Microsoft.PowerShell.Core
Cmdlet Remove-WmiObject 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Rename-Computer 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Restart-Computer 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Send-MailMessage 3.1.0.0
Microsoft.PowerShell.Utility
Cmdlet Set-Service 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Set-WmiInstance 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Show-EventLog 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Stop-Computer 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Test-Connection 3.1.0.0
Microsoft.PowerShell.Management
Cmdlet Write-EventLog 3.1.0.0
Microsoft.PowerShell.Management

Los comandos como Get-Process y Get-Hotfix tienen un parámetro ComputerName.


Esta no es la opción a largo plazo de Microsoft para ejecutar comandos en equipos
remotos. Incluso si encuentra un comando con un parámetro ComputerName, lo más
probable es que tenga que especificar credenciales alternativas y que el comando no
tenga un parámetro Credential. Y, si decidió ejecutar PowerShell desde una cuenta con
privilegios elevados, un firewall entre usted y el equipo remoto puede bloquear la
solicitud.

Para usar los comandos de comunicación remota de PowerShell que se muestran en


este capítulo, la comunicación remota de PowerShell debe estar habilitada en el equipo
remoto. Use el cmdlet Enable-PSRemoting para habilitar la comunicación remota de
PowerShell.

PowerShell
Enable-PSRemoting

Output

WinRM has been updated to receive requests.


WinRM service type changed successfully.
WinRM service started.

WinRM has been updated for remote management.


WinRM firewall exception enabled.

Comunicación remota uno a uno


Si desea que la sesión remota sea interactiva, necesita una comunicación remota uno a
uno. Este tipo de comunicación remota se proporciona mediante el cmdlet Enter-
PSSession .

En el capítulo anterior, almacené mis credenciales de administrador de dominio en una


variable denominada $Cred . Si todavía no lo ha hecho, almacene sus credenciales de
administrador de dominio en la variable $Cred .

Esto le permitirá escribir las credenciales una vez y usarlas en cada comando, siempre y
cuando la sesión actual de PowerShell esté activa.

PowerShell

$Cred = Get-Credential

Cree una sesión de comunicación remota uno a uno de PowerShell en el controlador de


dominio denominado dc01.

PowerShell

Enter-PSSession -ComputerName dc01 -Credential $Cred

Output

[dc01]: PS C:\Users\Administrator\Documents>

Observe que en el ejemplo anterior el símbolo del sistema de PowerShell está precedido
por [dc01] . Esto significa que se encuentra en una sesión interactiva de PowerShell en
el equipo remoto denominado dc01. Los comandos que ejecute se ejecutan en dc01, no
en el equipo local. Además, tenga en cuenta que solo tiene acceso a los comandos de
PowerShell que existen en el equipo remoto y no a los que existen en el equipo local. En
otras palabras, si ha instalado módulos adicionales en el equipo, no puede acceder a
ellos en el equipo remoto.

Cuando se conecta a un equipo remoto a través de una sesión de comunicación remota


uno a uno de PowerShell interactiva, se encuentra en el equipo remoto. Los objetos son
objetos normales, al igual que los que ha estado usando en todo el libro.

PowerShell

[dc01]: Get-Process | Get-Member

Output

TypeName: System.Diagnostics.Process

Name MemberType Definition


---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize64
PM AliasProperty PM = PagedMemorySize64
SI AliasProperty SI = SessionId
VM AliasProperty VM = VirtualMemorySize64
WS AliasProperty WS = WorkingSet64
Disposed Event System.EventHandler
Disposed(System.Object, ...
ErrorDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
Exited Event System.EventHandler
Exited(System.Object, Sy...
OutputDataReceived Event
System.Diagnostics.DataReceivedEventHandler ...
BeginErrorReadLine Method void BeginErrorReadLine()
BeginOutputReadLine Method void BeginOutputReadLine()
CancelErrorRead Method void CancelErrorRead()
CancelOutputRead Method void CancelOutputRead()
Close Method void Close()
CloseMainWindow Method bool CloseMainWindow()
CreateObjRef Method System.Runtime.Remoting.ObjRef
CreateObjRef(...
Dispose Method void Dispose(), void
IDisposable.Dispose()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object
InitializeLifetimeService()
Kill Method void Kill()
Refresh Method void Refresh()
Start Method bool Start()
ToString Method string ToString()
WaitForExit Method bool WaitForExit(int
milliseconds), void Wai...
WaitForInputIdle Method bool WaitForInputIdle(int
milliseconds), boo...
__NounName NoteProperty string __NounName=Process
BasePriority Property int BasePriority {get;}
Container Property System.ComponentModel.IContainer
Container {...
EnableRaisingEvents Property bool EnableRaisingEvents
{get;set;}
ExitCode Property int ExitCode {get;}
ExitTime Property datetime ExitTime {get;}
Handle Property System.IntPtr Handle {get;}
HandleCount Property int HandleCount {get;}
HasExited Property bool HasExited {get;}
Id Property int Id {get;}
MachineName Property string MachineName {get;}
MainModule Property System.Diagnostics.ProcessModule
MainModule ...
MainWindowHandle Property System.IntPtr MainWindowHandle
{get;}
MainWindowTitle Property string MainWindowTitle {get;}
MaxWorkingSet Property System.IntPtr MaxWorkingSet
{get;set;}
MinWorkingSet Property System.IntPtr MinWorkingSet
{get;set;}
Modules Property
System.Diagnostics.ProcessModuleCollection M...
NonpagedSystemMemorySize Property int NonpagedSystemMemorySize
{get;}
NonpagedSystemMemorySize64 Property long NonpagedSystemMemorySize64
{get;}
PagedMemorySize Property int PagedMemorySize {get;}
PagedMemorySize64 Property long PagedMemorySize64 {get;}
PagedSystemMemorySize Property int PagedSystemMemorySize {get;}
PagedSystemMemorySize64 Property long PagedSystemMemorySize64
{get;}
PeakPagedMemorySize Property int PeakPagedMemorySize {get;}
PeakPagedMemorySize64 Property long PeakPagedMemorySize64 {get;}
PeakVirtualMemorySize Property int PeakVirtualMemorySize {get;}
PeakVirtualMemorySize64 Property long PeakVirtualMemorySize64
{get;}
PeakWorkingSet Property int PeakWorkingSet {get;}
PeakWorkingSet64 Property long PeakWorkingSet64 {get;}
PriorityBoostEnabled Property bool PriorityBoostEnabled
{get;set;}
PriorityClass Property
System.Diagnostics.ProcessPriorityClass Prio...
PrivateMemorySize Property int PrivateMemorySize {get;}
PrivateMemorySize64 Property long PrivateMemorySize64 {get;}
PrivilegedProcessorTime Property timespan PrivilegedProcessorTime
{get;}
ProcessName Property string ProcessName {get;}
ProcessorAffinity Property System.IntPtr ProcessorAffinity
{get;set;}
Responding Property bool Responding {get;}
SafeHandle Property
Microsoft.Win32.SafeHandles.SafeProcessHandl...
SessionId Property int SessionId {get;}
Site Property System.ComponentModel.ISite Site
{get;set;}
StandardError Property System.IO.StreamReader
StandardError {get;}
StandardInput Property System.IO.StreamWriter
StandardInput {get;}
StandardOutput Property System.IO.StreamReader
StandardOutput {get;}
StartInfo Property
System.Diagnostics.ProcessStartInfo StartInf...
StartTime Property datetime StartTime {get;}
SynchronizingObject Property
System.ComponentModel.ISynchronizeInvoke Syn...
Threads Property
System.Diagnostics.ProcessThreadCollection T...
TotalProcessorTime Property timespan TotalProcessorTime {get;}
UserProcessorTime Property timespan UserProcessorTime {get;}
VirtualMemorySize Property int VirtualMemorySize {get;}
VirtualMemorySize64 Property long VirtualMemorySize64 {get;}
WorkingSet Property int WorkingSet {get;}
WorkingSet64 Property long WorkingSet64 {get;}
PSConfiguration PropertySet PSConfiguration {Name, Id,
PriorityClass, Fi...
PSResources PropertySet PSResources {Name, Id,
Handlecount, WorkingS...
Company ScriptProperty System.Object Company
{get=$this.Mainmodule....
CPU ScriptProperty System.Object CPU
{get=$this.TotalProcessorT...
Description ScriptProperty System.Object Description
{get=$this.Mainmod...
FileVersion ScriptProperty System.Object FileVersion
{get=$this.Mainmod...
Path ScriptProperty System.Object Path
{get=$this.Mainmodule.Fil...
Product ScriptProperty System.Object Product
{get=$this.Mainmodule....
ProductVersion ScriptProperty System.Object ProductVersion
{get=$this.Main...
[dc01]:

Cuando haya terminado de trabajar con el equipo remoto, salga de la sesión de


comunicación remota uno a uno mediante el cmdlet Exit-PSSession .

PowerShell
[dc01]: Exit-PSSession

Comunicación remota uno a varios


En algunas ocasiones, es posible que tenga que realizar una tarea de forma interactiva
en un equipo remoto. Pero la comunicación remota es mucho más eficaz cuando se
realiza una tarea en varios equipos remotos al mismo tiempo. Use el cmdlet Invoke-
Command para ejecutar un comando en uno o varios equipos remotos al mismo tiempo.

PowerShell

Invoke-Command -ComputerName dc01, sql02, web01 {Get-Service -Name W32time}


-Credential $Cred

Output

Status Name DisplayName PSComputerName


------ ---- ----------- --------------
Running W32time Windows Time web01
Start... W32time Windows Time dc01
Running W32time Windows Time sql02

En el ejemplo anterior, se consultó el estado del servicio Hora de Windows en tres


servidores. El cmdlet Get-Service se colocó dentro del bloque de script de Invoke-
Command . En realidad, Get-Service se ejecuta en el equipo remoto y los resultados se

devuelven al equipo local como objetos deserializados.

Canalizar el comando anterior a Get-Member muestra que los resultados son, en efecto,
objetos deserializados.

PowerShell

Invoke-Command -ComputerName dc01, sql02, web01 {Get-Service -Name W32time}


-Credential $Cred | Get-Member

Output

TypeName: Deserialized.System.ServiceProcess.ServiceController

Name MemberType Definition


---- ---------- ----------
GetType Method type GetType()
ToString Method string ToString(), string ToString(string
format, Sys...
Name NoteProperty string Name=W32time
PSComputerName NoteProperty string PSComputerName=sql02
PSShowComputerName NoteProperty bool PSShowComputerName=True
RequiredServices NoteProperty
Deserialized.System.ServiceProcess.ServiceController[...
RunspaceId NoteProperty guid RunspaceId=570313c4-ac84-4109-bf67-
c6b33236af0a
CanPauseAndContinue Property System.Boolean {get;set;}
CanShutdown Property System.Boolean {get;set;}
CanStop Property System.Boolean {get;set;}
Container Property {get;set;}
DependentServices Property
Deserialized.System.ServiceProcess.ServiceController[...
DisplayName Property System.String {get;set;}
MachineName Property System.String {get;set;}
ServiceHandle Property System.String {get;set;}
ServiceName Property System.String {get;set;}
ServicesDependedOn Property
Deserialized.System.ServiceProcess.ServiceController[...
ServiceType Property System.String {get;set;}
Site Property {get;set;}
StartType Property System.String {get;set;}
Status Property System.String {get;set;}

Observe que la mayoría de los métodos no se encuentran en los objetos deserializados.


Esto significa que no son objetos activos; son inertes. No puede iniciar o detener un
servicio mediante un objeto deserializado porque es una instantánea del estado de ese
objeto en el momento en el que se ejecutó el comando en el equipo remoto.

Sin embargo, esto no significa que no pueda iniciar o detener un servicio mediante un
método con Invoke-Command . Simplemente significa que se debe llamar al método en la
sesión remota.

Para demostrarlo, voy a detener el servicio Hora de Windows en los tres servidores
remotos mediante el método Stop() .

PowerShell

Invoke-Command -ComputerName dc01, sql02, web01 {(Get-Service -Name


W32time).Stop()} -Credential $Cred
Invoke-Command -ComputerName dc01, sql02, web01 {Get-Service -Name W32time}
-Credential $Cred

Output

Status Name DisplayName PSComputerName


------ ---- ----------- --------------
Stopped W32time Windows Time web01
Stopped W32time Windows Time dc01
Stopped W32time Windows Time sql02

Como se mencionó en un capítulo anterior, si existe un cmdlet para llevar a cabo una
tarea, recomiendo usar el cmdlet en lugar de usar un método. En el escenario anterior,
recomiendo usar el cmdlet Stop-Service en lugar del método STOP. Decidí usar el
método Stop() para realizar una demostración, ya que muchas personas creen
erróneamente que no se puede llamar a métodos cuando se usa la comunicación
remota de PowerShell. No se pueden llamar en el objeto que se devuelve porque está
deserializado, pero sí se pueden llamar en la propia sesión remota.

Sesiones de PowerShell
En el último ejemplo de la sección anterior, ejecuté dos comandos con el cmdlet
Invoke-Command . Esto significa que hubo que configurar y desactivar dos sesiones

independientes para ejecutar esos dos comandos.

De forma similar a las sesiones CIM que se describen en el capítulo 7, se puede usar una
sesión de PowerShell en un equipo remoto para ejecutar varios comandos en el equipo
remoto sin la sobrecarga de una nueva sesión para cada comando individual.

Cree una sesión de PowerShell para cada uno de los tres equipos con los que hemos
trabajado en este capítulo: dc01, SQL02 y WEB01.

PowerShell

$Session = New-PSSession -ComputerName dc01, sql02, web01 -Credential $Cred

Ahora, use la variable denominada $Session para iniciar el servicio Hora de Windows
mediante un método y compruebe el estado del servicio.

PowerShell

Invoke-Command -Session $Session {(Get-Service -Name W32time).Start()}


Invoke-Command -Session $Session {Get-Service -Name W32time}

Output

Status Name DisplayName PSComputerName


------ ---- ----------- --------------
Running W32time Windows Time web01
Start... W32time Windows Time dc01
Running W32time Windows Time sql02
Una vez creada la sesión con credenciales alternativas, ya no es necesario especificar las
credenciales cada vez que se ejecuta un comando.

Cuando haya terminado de usar las sesiones, asegúrese de quitarlas.

PowerShell

Get-PSSession | Remove-PSSession

Resumen
En este capítulo, ha obtenido información sobre la comunicación remota de PowerShell,
cómo ejecutar comandos en una sesión interactiva con un equipo remoto y cómo
ejecutar comandos en varios equipos mediante la comunicación remota uno a varios.
También ha aprendido las ventajas de usar una sesión de PowerShell al ejecutar varios
comandos en el mismo equipo remoto.

Revisar
1. ¿Cómo puede habilitar la comunicación remota de PowerShell?
2. ¿Cuál es el comando de PowerShell para iniciar una sesión interactiva con un
equipo remoto?
3. ¿Cuál es la ventaja de usar una sesión de comunicación remota de PowerShell en
lugar de especificar el nombre de equipo con cada comando?
4. ¿Se puede usar una sesión de comunicación remota de PowerShell con una sesión
de comunicación remota uno a uno?
5. ¿Cuál es la diferencia en el tipo de objetos que devuelven los cmdlets frente a los
que se devuelven cuando se ejecutan los mismos cmdlets en equipos remotos con
Invoke-Command ?

Lecturas recomendadas
about_Remote
about_Remote_Output
about_Remote_Requirements
about_Remote_Troubleshooting
about_Remote_Variables
Preguntas más frecuentes sobre la comunicación remota de PowerShell
Capítulo 9: Funciones
Artículo • 13/04/2023

Si escribe scripts o comandos únicos de una línea de PowerShell y se encuentra que a


menudo tiene que modificarlos para distintos escenarios, es bastante probable que sean
buenos candidatos para convertirlos en una función que se pueda volver a usar.

Siempre que sea posible, prefiero escribir funciones porque están más orientadas a las
herramientas. Puedo colocar las funciones en un módulo de script, colocar ese módulo
en $env:PSModulePath y llamar a las funciones sin necesidad de buscar físicamente
dónde se guardan. Con el módulo PowerShellGet, es fácil compartir esos módulos en un
repositorio de NuGet. PowerShellGet se incluye en la versión 5.0 de PowerShell y en
versiones posteriores. Está disponible como descarga independiente de la versión 3.0 de
PowerShell y de versiones posteriores.

No se complique. Elija la manera más directa de hacer una tarea y simplifique los
procesos. Evite los alias y los parámetros posicionales en todo código que reutilice. Dé
formato al código para facilitar la lectura. No codifique los valores; use parámetros y
variables. No escriba código innecesario, aunque no perjudique a nada. Agrega una
complejidad innecesaria. La atención al detalle ayuda mucho a la hora de escribir código
de PowerShell.

Nomenclatura
Al asignar nombres a las funciones de PowerShell, use un nombre en Pascal case con un
verbo aprobado y un sustantivo en singular. También recomiendo agregar un prefijo al
nombre. Por ejemplo: <ApprovedVerb>-<Prefix><SingularNoun> .

En PowerShell hay una lista específica de verbos aprobados que se pueden obtener
mediante la ejecución de Get-Verb .

PowerShell

Get-Verb | Sort-Object -Property Verb

Output

Verb Group
---- -----
Add Common
Approve Lifecycle
Assert Lifecycle
Backup Data
Block Security
Checkpoint Data
Clear Common
Close Common
Compare Data
Complete Lifecycle
Compress Data
Confirm Lifecycle
Connect Communications
Convert Data
ConvertFrom Data
ConvertTo Data
Copy Common
Debug Diagnostic
Deny Lifecycle
Disable Lifecycle
Disconnect Communications
Dismount Data
Edit Data
Enable Lifecycle
Enter Common
Exit Common
Expand Data
Export Data
Find Common
Format Common
Get Common
Grant Security
Group Data
Hide Common
Import Data
Initialize Data
Install Lifecycle
Invoke Lifecycle
Join Common
Limit Data
Lock Common
Measure Diagnostic
Merge Data
Mount Data
Move Common
New Common
Open Common
Optimize Common
Out Data
Ping Diagnostic
Pop Common
Protect Security
Publish Data
Push Common
Read Communications
Receive Communications
Redo Common
Register Lifecycle
Remove Common
Rename Common
Repair Diagnostic
Request Lifecycle
Reset Common
Resize Common
Resolve Diagnostic
Restart Lifecycle
Restore Data
Resume Lifecycle
Revoke Security
Save Data
Search Common
Select Common
Send Communications
Set Common
Show Common
Skip Common
Split Common
Start Lifecycle
Step Common
Stop Lifecycle
Submit Lifecycle
Suspend Lifecycle
Switch Common
Sync Data
Test Diagnostic
Trace Diagnostic
Unblock Security
Undo Common
Uninstall Lifecycle
Unlock Common
Unprotect Security
Unpublish Data
Unregister Lifecycle
Update Data
Use Other
Wait Lifecycle
Watch Common
Write Communications

En el ejemplo anterior, he ordenado los resultados por la columna Verbo. La columna


Grupo le da una idea de cómo se usan estos verbos. Es importante elegir un verbo
aprobado en PowerShell al agregar funciones a un módulo. Si elige un verbo no
aprobado, el módulo generará un mensaje de advertencia en el momento de la carga.
Ese mensaje de advertencia hará que las funciones no parezcan profesionales. Los
verbos no aprobados también limitan la detectabilidad de las funciones.

Una función simple


Una función de PowerShell se declara con la palabra clave de la función, seguida del
nombre de dicha función y, a continuación, una llave de apertura y otra de cierre. El
código que ejecutará la función se encuentra dentro de esas llaves.

PowerShell

function Get-Version {
$PSVersionTable.PSVersion
}

La función que se muestra es un ejemplo sencillo que devuelve la versión de PowerShell.

PowerShell

Get-Version

Output

Major Minor Build Revision


----- ----- ----- --------
5 1 14393 693

Es bastante probable que se produzcan conflictos en los nombres de las funciones con
un nombre como Get-Version y los comandos predeterminados de PowerShell o los
comandos que otros usuarios puedan escribir. Esta es la razón por la que recomiendo
prefijar la parte del sustantivo de las funciones, para ayudar a evitar conflictos en los
nombres. En el ejemplo siguiente, usaré el prefijo "PS".

PowerShell

function Get-PSVersion {
$PSVersionTable.PSVersion
}

Más allá del nombre, esta función es idéntica a la anterior.

PowerShell

Get-PSVersion

Output

Major Minor Build Revision


----- ----- ----- --------
5 1 14393 693

Incluso al prefijar el nombre con algo parecido a PS, todavía es bastante probable que
se produzca un conflicto de nombres. Normalmente, prefijo los nombres de mis
funciones con mis iniciales. Desarrolle un estándar y cúmplalo.

PowerShell

function Get-MrPSVersion {
$PSVersionTable.PSVersion
}

Esta función no es diferente de las dos anteriores, a excepción del uso de un nombre
más sensible para intentar evitar conflictos de nomenclatura con otros comandos de
PowerShell.

PowerShell

Get-MrPSVersion

Output

Major Minor Build Revision


----- ----- ----- --------
5 1 14393 693

Una vez cargadas en la memoria, puede ver las funciones en el PSDrive Función.

PowerShell

Get-ChildItem -Path Function:\Get-*Version

Output

CommandType Name Version


Source
----------- ---- -------
------
Function Get-Version
Function Get-PSVersion
Function Get-MrPSVersion

Si quiere quitar estas funciones de la sesión actual, tendrá que quitarlas del PSDrive
Función o cerrar PowerShell y volver a abrirlo.
PowerShell

Get-ChildItem -Path Function:\Get-*Version | Remove-Item

Compruebe que las funciones se hayan quitado bien.

PowerShell

Get-ChildItem -Path Function:\Get-*Version

Si las funciones se cargaron como parte de un módulo, se puede descargar dicho


módulo para quitarlas.

PowerShell

Remove-Module -Name <ModuleName>

El cmdlet Remove-Module permite quitar los módulos de la memoria de la sesión actual


de PowerShell, pero tenga en cuenta que no los quita del sistema ni del disco.

Parámetros
No asigne valores de forma estática. En su lugar, use parámetros y variables. En cuanto a
la asignación de nombres a los parámetros, utilice el mismo nombre que los cmdlets
predeterminados para los nombres de los parámetros siempre que sea posible.

PowerShell

function Test-MrParameter {

param (
$ComputerName
)

Write-Output $ComputerName

¿Por qué uso ComputerName y no Computer, ServerName o Host para el nombre del
parámetro? Porque quería que mi función estuviera estandarizada como los cmdlets
predeterminados.

Crearé una función para consultar todos los comandos de un sistema y devolver el
número de estos que tienen nombres de parámetros específicos.
PowerShell

function Get-MrParameterCount {
param (
[string[]]$ParameterName
)

foreach ($Parameter in $ParameterName) {


$Results = Get-Command -ParameterName $Parameter -ErrorAction
SilentlyContinue

[pscustomobject]@{
ParameterName = $Parameter
NumberOfCmdlets = $Results.Count
}
}
}

Como puede ver en los resultados que se muestran a continuación, hay 39 comandos
que tienen un parámetro ComputerName. No hay ningún cmdlet que tenga parámetros
como Computer, ServerName, Host o Machine.

PowerShell

Get-MrParameterCount -ParameterName ComputerName, Computer, ServerName,


Host, Machine

Output

ParameterName NumberOfCmdlets
------------- ---------------
ComputerName 39
Computer 0
ServerName 0
Host 0
Machine 0

También recomiendo usar las mismas mayúsculas y minúsculas para los nombres de
parámetros que los cmdlets predeterminados. Use ComputerName , no computername . Esto
hace que las funciones tengan un aspecto similar al de los cmdlets predeterminados.
Los usuarios que ya estén familiarizados con PowerShell se sentirán como en casa.

La param instrucción permite definir uno o varios parámetros. Las definiciones de


parámetros están separadas por una coma ( , ). Para obtener más información, consulte
about_Functions_Advanced_Parameters.
Funciones avanzadas
Convertir una función de PowerShell en una avanzada es realmente sencillo. Una de las
diferencias entre una función y una función avanzada es que las avanzadas tienen una
serie de parámetros comunes que se agregan a la función automáticamente. En estos
parámetros comunes se incluyen parámetros como Verbose y Debug.

Comenzaré con la función Test-MrParameter , que se usó en la sección anterior.

PowerShell

function Test-MrParameter {

param (
$ComputerName
)

Write-Output $ComputerName

Lo que quiero que observe es que la función Test-MrParameter no tiene ningún


parámetro común. Hay un par de maneras diferentes de ver los parámetros comunes.
Una consiste en ver la sintaxis mediante Get-Command .

PowerShell

Get-Command -Name Test-MrParameter -Syntax

Output

Test-MrParameter [[-ComputerName] <Object>]

Otra es explorar en profundidad los parámetros con Get-Command .

PowerShell

(Get-Command -Name Test-MrParameter).Parameters.Keys

Output

ComputerName

Agregue CmdletBinding para convertir la función en una avanzada.


PowerShell

function Test-MrCmdletBinding {

[CmdletBinding()] #<<-- This turns a regular function into an advanced


function
param (
$ComputerName
)

Write-Output $ComputerName

El hecho de agregar CmdletBinding agrega también los parámetros comunes


automáticamente. CmdletBinding requiere un bloque param , pero el bloque param
puede estar vacío.

PowerShell

Get-Command -Name Test-MrCmdletBinding -Syntax

Output

Test-MrCmdletBinding [[-ComputerName] <Object>] [<CommonParameters>]

Al explorar en profundidad los parámetros con Get-Command , se muestran los nombres


de los parámetros reales, incluidos los comunes.

PowerShell

(Get-Command -Name Test-MrCmdletBinding).Parameters.Keys

Output

ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
SupportsShouldProcess
SupportsShouldProcess agrega parámetros WhatIf y Confirm. Solo son necesarios para

los comandos que hacen cambios.

PowerShell

function Test-MrSupportsShouldProcess {

[CmdletBinding(SupportsShouldProcess)]
param (
$ComputerName
)

Write-Output $ComputerName

Observe que ahora hay parámetros WhatIf y Confirm.

PowerShell

Get-Command -Name Test-MrSupportsShouldProcess -Syntax

Output

Test-MrSupportsShouldProcess [[-ComputerName] <Object>] [-WhatIf] [-Confirm]


[<CommonParameters>]

Una vez más, también puede usar Get-Command para devolver una lista de los nombres
de los parámetros reales, incluidos los habituales, junto con WhatIf y Confirm.

PowerShell

(Get-Command -Name Test-MrSupportsShouldProcess).Parameters.Keys

Output

ComputerName
Verbose
Debug
ErrorAction
WarningAction
InformationAction
ErrorVariable
WarningVariable
InformationVariable
OutVariable
OutBuffer
PipelineVariable
WhatIf
Confirm

Validación de parámetros
Valide la entrada bien al principio. ¿Por qué permitir que el código siga en una ruta de
acceso si no es posible ejecutarlo sin una entrada válida?

Escriba siempre las variables que se usan para los parámetros (especifique un tipo de
datos).

PowerShell

function Test-MrParameterValidation {

[CmdletBinding()]
param (
[string]$ComputerName
)

Write-Output $ComputerName

En el ejemplo anterior, he especificado String como tipo de datos para el parámetro


ComputerName. Esto hace que solo se permita especificar un único nombre de equipo.
Si se especifica más de un nombre de equipo mediante una lista separada por comas, se
generará un error.

PowerShell

Test-MrParameterValidation -ComputerName Server01, Server02

Output

Test-MrParameterValidation : Cannot process argument transformation on


parameter
'ComputerName'. Cannot convert value to type System.String.
At line:1 char:42
+ Test-MrParameterValidation -ComputerName Server01, Server02
+
+ CategoryInfo : InvalidData: (:) [Test-MrParameterValidation],
ParameterBindingArg
umentTransformationException
+ FullyQualifiedErrorId : ParameterArgumentTransformationError,Test-
MrParameterValidation

El problema con la definición actual es que es válido omitir el valor del parámetro
ComputerName, pero se requiere un valor para que la función se complete
correctamente. Aquí es donde el atributo de parámetro Mandatory resulta útil.

PowerShell

function Test-MrParameterValidation {

[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string]$ComputerName
)

Write-Output $ComputerName

La sintaxis usada en el ejemplo anterior es la versión 3.0 de PowerShell y es compatible


con versiones posteriores. Podría especificarse [Parameter(Mandatory=$true)] en su
lugar, para que la función sea compatible con la versión 2.0 de PowerShell y posteriores.
Ahora que se requiere el parámetro ComputerName, si no se especifica ninguno, la
función solicitará uno.

PowerShell

Test-MrParameterValidation

Output

cmdlet Test-MrParameterValidation at command pipeline position 1


Supply values for the following parameters:
ComputerName:

Si quiere permitir más de un valor para el parámetro ComputerName, utilice el tipo de


datos String, pero agregue corchetes de apertura y de cierre al tipo de datos para
permitir una matriz de cadenas.

PowerShell
function Test-MrParameterValidation {

[CmdletBinding()]
param (
[Parameter(Mandatory)]
[string[]]$ComputerName
)

Write-Output $ComputerName

Es posible que quiera especificar un valor predeterminado para el parámetro


ComputerName, si no se especifica uno. El problema es que los valores
predeterminados no se pueden usar con parámetros obligatorios. En su lugar, deberá
usar el atributo de validación de parámetros ValidateNotNullOrEmpty con un valor
predeterminado.

PowerShell

function Test-MrParameterValidation {

[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
)

Write-Output $ComputerName

Intente no usar valores estáticos, ni siquiera cuando establezca un valor


predeterminado. En el ejemplo anterior, se usa $env:COMPUTERNAME como valor
predeterminado, que se traduce automáticamente en el nombre del equipo local si no
se proporciona un valor.

Resultado detallado
Aunque los comentarios insertados son útiles, especialmente si está escribiendo código
complejo, los usuarios no los ven nunca, a menos que examinen el propio código.

La función que se muestra en el siguiente ejemplo tiene un comentario insertado en el


bucle foreach . Aunque es posible que este comentario concreto no sea tan difícil de
encontrar, imagínese que la función incluyese cientos de líneas de código.
PowerShell

function Test-MrVerboseOutput {

[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
)

foreach ($Computer in $ComputerName) {


#Attempting to perform some action on $Computer <<-- Don't use
#inline comments like this, use write verbose instead.
Write-Output $Computer
}

Una opción mejor es usar Write-Verbose en lugar de comentarios insertados.

PowerShell

function Test-MrVerboseOutput {

[CmdletBinding()]
param (
[ValidateNotNullOrEmpty()]
[string[]]$ComputerName = $env:COMPUTERNAME
)

foreach ($Computer in $ComputerName) {


Write-Verbose -Message "Attempting to perform some action on
$Computer"
Write-Output $Computer
}

Cuando se llama a la función sin el parámetro Verbose, no se muestra el resultado


detallado.

PowerShell

Test-MrVerboseOutput -ComputerName Server01, Server02

Si se llama con el parámetro Verbose, sí que se mostrará el resultado detallado.

PowerShell
Test-MrVerboseOutput -ComputerName Server01, Server02 -Verbose

Entrada de la canalización
Si quiere que la función acepte entradas de canalización, se necesitará cierta
codificación adicional. Como se ha mencionado anteriormente en este libro, los
comandos pueden aceptar la entrada de canalización por valor (por tipo) o por nombre
de propiedad. Puede escribir las funciones de la misma manera que los comandos
nativos, para que acepten uno o ambos tipos de entrada.

Para aceptar la entrada de canalización por valor, especifique el atributo de parámetro


ValueFromPipeline para ese parámetro concreto. Tenga en cuenta que solo puede

aceptar la entrada de canalización por valor de uno de cada tipo de datos. Por ejemplo,
si tiene dos parámetros que aceptan la entrada de cadena, solo uno de ellos puede
aceptar la entrada de canalización por valor, porque, si lo especificó para ambos
parámetros de cadena, la entrada de canalización no sabrá con cuál se debe enlazar.
Este es otro motivo por el que se llama a este tipo de entrada de canalización por tipo,
en lugar de por valor.

La entrada de canalización se incluye en un elemento cada vez, de manera similar a la


forma en la que se administran los elementos en un bucle foreach . Como mínimo, se
requiere un bloque process para procesar cada uno de estos elementos si se va a
aceptar una matriz como entrada. Si solo va a aceptar un valor único como entrada, no
es necesario un bloque process , pero sigue siendo recomendable especificarlo para que
sea coherente.

PowerShell

function Test-MrPipelineInput {

[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline)]
[string[]]$ComputerName
)

PROCESS {
Write-Output $ComputerName
}

}
Aceptar la entrada de canalización por nombre de propiedad es similar, salvo que se
especifica con el atributo de parámetro ValueFromPipelineByPropertyName y se puede
especificar para cualquier número de parámetros, independientemente del tipo de
datos. La clave es que la salida del comando que se está canalizando tiene que tener un
nombre de propiedad que coincida con el nombre del parámetro o un alias de
parámetro de la función.

PowerShell

function Test-MrPipelineInput {

[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
)

PROCESS {
Write-Output $ComputerName
}

Los bloques BEGIN y END son opcionales. Se especificaría BEGIN antes que el bloque
PROCESS y se usaría para realizar cualquier trabajo inicial antes de recibir los elementos

de la canalización. Es importante entender esto. Los valores que se canalizan no son


accesibles en el bloque BEGIN . El bloque END se especificaría después del bloque
PROCESS y se utilizaría para la limpieza una vez que se hubieran procesado todos los
elementos canalizados.

Tratamiento de errores
La función que se muestra en el siguiente ejemplo genera una excepción no controlada
cuando no se puede establecer contacto con un equipo.

PowerShell

function Test-MrErrorHandling {

[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
)

PROCESS {
foreach ($Computer in $ComputerName) {
Test-WSMan -ComputerName $Computer
}
}

Hay un par de formas de controlar los errores en PowerShell. Try/Catch es la forma más
moderna de controlar los errores.

PowerShell

function Test-MrErrorHandling {

[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
)

PROCESS {
foreach ($Computer in $ComputerName) {
try {
Test-WSMan -ComputerName $Computer
}
catch {
Write-Warning -Message "Unable to connect to Computer:
$Computer"
}
}
}

Aunque la función que se muestra en el ejemplo anterior usa el control de errores,


también genera una excepción no controlada porque el comando no genera un error de
terminación. También es importante entender esto. Solo se detectan los errores de
terminación. Especifique el parámetro ErrorAction con Stop como valor para convertir
un error de no terminación en uno de terminación.

PowerShell

function Test-MrErrorHandling {

[CmdletBinding()]
param (
[Parameter(Mandatory,
ValueFromPipeline,
ValueFromPipelineByPropertyName)]
[string[]]$ComputerName
)

PROCESS {
foreach ($Computer in $ComputerName) {
try {
Test-WSMan -ComputerName $Computer -ErrorAction Stop
}
catch {
Write-Warning -Message "Unable to connect to Computer:
$Computer"
}
}
}

No modifique la variable global $ErrorActionPreference a menos que sea


absolutamente necesario. Si usa algo parecido a .NET directamente desde la función de
PowerShell, no puede especificar ErrorAction en el propio comando. En ese caso, es
posible que tenga que cambiar la variable global $ErrorActionPreference , pero, si la
cambia, vuelva a cambiarla inmediatamente después de probar el comando.

Ayuda basada en comentarios


Se recomienda agregar a las funciones ayuda basada en comentarios, de modo que las
personas con las que se compartan sepan cómo usarlas.

PowerShell

function Get-MrAutoStoppedService {

<#
.SYNOPSIS
Returns a list of services that are set to start automatically, are not
currently running, excluding the services that are set to delayed start.

.DESCRIPTION
Get-MrAutoStoppedService is a function that returns a list of services
from
the specified remote computer(s) that are set to start automatically,
are not
currently running, and it excludes the services that are set to start
automatically
with a delayed startup.
.PARAMETER ComputerName
The remote computer(s) to check the status of the services on.

.PARAMETER Credential
Specifies a user account that has permission to perform this action. The
default
is the current user.

.EXAMPLE
Get-MrAutoStoppedService -ComputerName 'Server1', 'Server2'

.EXAMPLE
'Server1', 'Server2' | Get-MrAutoStoppedService

.EXAMPLE
Get-MrAutoStoppedService -ComputerName 'Server1' -Credential (Get-
Credential)

.INPUTS
String

.OUTPUTS
PSCustomObject

.NOTES
Author: Mike F Robbins
Website: http://mikefrobbins.com
Twitter: @mikefrobbins
#>

[CmdletBinding()]
param (

#Function Body

Al agregar a las funciones ayuda basada en comentarios, dicha ayuda se puede


recuperar, al igual que los comandos integrados predeterminados.

Toda la sintaxis para escribir una función en PowerShell puede parecer abrumadora,
especialmente para alguien que se acaba de iniciar en ella. A menudo, si no recuerdo la
sintaxis de algo, abro una segunda copia del ISE en un monitor independiente y veo el
fragmento de código "Cmdlet (función avanzada): completado" mientras escribo el
código de la función. Se puede acceder a los fragmentos de código en el ISE de
PowerShell mediante la combinación de teclas Ctrl + J .
Resumen
En este capítulo ha aprendido los conceptos básicos de la escritura de funciones en
PowerShell, lo que también incluye cómo convertir una función en avanzada y algunos
de los elementos más importantes que debe tener en cuenta al escribir funciones de
PowerShell, como la validación de parámetros, la salida detallada, la entrada de
canalización, el control de errores y la ayuda basada en comentarios.

Revisar
1. ¿Cómo se obtiene una lista de verbos aprobados en PowerShell?
2. ¿Cómo se convierte una función de PowerShell en avanzada?
3. ¿Cuándo deben agregarse los parámetros WhatIf y Confirm a las funciones de
PowerShell?
4. ¿Cómo se puede convertir un error de no terminación en uno de terminación?
5. ¿Por qué debe agregar ayuda basada en comentarios a las funciones?

Lecturas recomendadas
about_Functions
about_Functions_Advanced_Parameters
about_CommonParameters
about_Functions_CmdletBindingAttribute
about_Functions_Advanced
about_Try_Catch_Finally
about_Comment_Based_Help
Vídeo: Creación de herramientas de PowerShell con funciones avanzadas y
módulos de script
Capítulo 10: Módulos de script
Artículo • 13/04/2023

Convertir los scripts y las secuencias de comandos de una frase de PowerShell en


herramientas reutilizables es incluso más importante si los va a usar con frecuencia. El
empaquetado de las funciones en un módulo de script hace que tengan un aspecto más
profesional y sean más fáciles de compartir.

Funciones prefijadas por puntos


En el capítulo anterior no se abordaron las funciones prefijadas por puntos. Cuando una
función de un script no forma parte de un módulo, la única manera de cargarla en la
memoria es usar scripts prefijados por puntos en el archivo .PS1 en el que se guarda.

La siguiente función se ha guardado como Get-MrPSVersion.ps1 .

PowerShell

function Get-MrPSVersion {
$PSVersionTable
}

Al ejecutar el script, no sucede nada.

PowerShell

.\Get-MrPSVersion.ps1

Si intenta llamar a la función, se genera un mensaje de error.

PowerShell

Get-MrPSVersion

Output

Get-MrPSVersion : The term 'Get-MrPSVersion' is not recognized as the name


of a cmdlet,
function, script file, or operable program. Check the spelling of the name,
or if a path
was included, verify that the path is correct and try again.
At line:1 char:1
+ Get-MrPSVersion
+ CategoryInfo : ObjectNotFound: (Get-MrPSVersion:String) [],
CommandNotFou
ndException
+ FullyQualifiedErrorId : CommandNotFoundException

Para determinar si las funciones se cargan en la memoria, compruebe si existen en el


PSDrive Function.

PowerShell

Get-ChildItem -Path Function:\Get-MrPSVersion

Output

Get-ChildItem : Cannot find path 'Get-MrPSVersion' because it does not


exist.
At line:1 char:1
+ Get-ChildItem -Path Function:\Get-MrPSVersion
+ CategoryInfo : ObjectNotFound: (Get-MrPSVersion:String) [Get-
ChildItem],
ItemNotFoundException
+ FullyQualifiedErrorId :
PathNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

El problema al llamar al script que contiene la función es que las funciones se cargan en
el ámbito Script. Cuando el script se completa, se quita ese ámbito y también la función.

La función debe cargarse en el ámbito Global. Esto puede lograrse prefijando por
puntos el script que contiene la función. Se puede usar la ruta de acceso relativa.

PowerShell

. .\Get-MrPSVersion.ps1

Y también la ruta de acceso absoluta.

PowerShell

. C:\Demo\Get-MrPSVersion.ps1

Si una parte de la ruta de acceso se almacena en una variable, se puede combinar con el
resto de la ruta de acceso. No hay ninguna razón para usar la concatenación de cadenas
para combinar la variable junto con el resto de la ruta de acceso.
PowerShell

$Path = 'C:\'
. $Path\Get-MrPSVersion.ps1

Ahora, al comprobar el PSDrive Function, se ve como la función Get-MrPSVersion existe.

PowerShell

Get-ChildItem -Path Function:\Get-MrPSVersion

Output

CommandType Name Version


Source
----------- ---- -------
------
Function Get-MrPSVersion

Módulos de script
Un módulo de script de PowerShell es simplemente un archivo que contiene una o más
funciones que se guardan como un archivo .PSM1 en lugar de un archivo .PS1 .

¿Cómo se crea un módulo de script? Quizás piense que se hace mediante un comando
con un nombre parecido a New-Module . No es así. Si bien hay un comando en
PowerShell denominado New-Module , ese comando crea un módulo dinámico, no un
módulo de script. Asegúrese siempre de leer la ayuda de un comando, incluso cuando
crea que ha encontrado el comando que necesita.

PowerShell

help New-Module

Output

NAME
New-Module

SYNOPSIS
Creates a new dynamic module that exists only in memory.

SYNTAX
New-Module [-Name] <String> [-ScriptBlock] <ScriptBlock> [-ArgumentList
<Object[]>]
[-AsCustomObject] [-Cmdlet <String[]>] [-Function <String[]>] [-
ReturnResult]
[<CommonParameters>]

DESCRIPTION
The New-Module cmdlet creates a dynamic module from a script block. The
members of
the dynamic module, such as functions and variables, are immediately
available in
the session and remain available until you close the session.

Like static modules, by default, the cmdlets and functions in a dynamic


module are
exported and the variables and aliases are not. However, you can use the
Export-ModuleMember cmdlet and the parameters of New-Module to override
the defaults.

You can also use the AsCustomObject parameter of New-Module to return


the dynamic
module as a custom object. The members of the modules, such as
functions, are
implemented as script methods of the custom object instead of being
imported into
the session.

Dynamic modules exist only in memory, not on disk. Like all modules, the
members of
dynamic modules run in a private module scope that is a child of the
global scope.
Get-Module cannot get a dynamic module, but Get-Command can get the
exported members.

To make a dynamic module available to Get-Module , pipe a New-Module


command to
Import-Module, or pipe the module object that New-Module returns to
Import-Module .
This action adds the dynamic module to the Get-Module list, but it does
not save the
module to disk or make it persistent.

RELATED LINKS
Online Version: http://go.microsoft.com/fwlink/?LinkId=821495
Export-ModuleMember
Get-Module
Import-Module
Remove-Module

REMARKS
To see the examples, type: "get-help New-Module -examples".
For more information, type: "get-help New-Module -detailed".
For technical information, type: "get-help New-Module -full".
For online help, type: "get-help New-Module -online"
En el capítulo anterior, mencioné que las funciones deben usar verbos aprobados; de lo
contrario, generarán un mensaje de advertencia cuando se importe el módulo. En el
código siguiente se usa el cmdlet New-Module para crear un módulo dinámico en la
memoria. Este módulo muestra la advertencia de verbo no aprobado.

PowerShell

New-Module -Name MyModule -ScriptBlock {

function Return-MrOsVersion {
Get-CimInstance -ClassName Win32_OperatingSystem |
Select-Object -Property @{label='OperatingSystem';expression=
{$_.Caption}}
}

Export-ModuleMember -Function Return-MrOsVersion

} | Import-Module

Output

WARNING: The names of some imported commands from the module 'MyModule'
include
unapproved verbs that might make them less discoverable. To find the
commands with
unapproved verbs, run the Import-Module command again with the Verbose
parameter. For a
list of approved verbs, type Get-Verb.

Me gustaría reiterar que, si bien el cmdlet New-Module se usó en el ejemplo anterior, ese
no es el comando para crear módulos de script en PowerShell.

Guarde las dos funciones siguientes en un archivo denominado MyScriptModule.psm1 .

PowerShell

function Get-MrPSVersion {
$PSVersionTable
}

function Get-MrComputerName {
$env:COMPUTERNAME
}

Intente llamar a una de las funciones.

PowerShell
Get-MrComputerName

Output

Get-MrComputerName : The term 'Get-MrComputerName' is not recognized as the


name of a
cmdlet, function, script file, or operable program. Check the spelling of
the name, or
if a path was included, verify that the path is correct and try again.
At line:1 char:1
+ Get-MrComputerName
+ CategoryInfo : ObjectNotFound: (Get-MrComputerName:String)
[], CommandNot
FoundException
+ FullyQualifiedErrorId : CommandNotFoundException

Se genera un mensaje de error que indica que no se encuentra la función. También


puede comprobar el PSDrive Function como hizo antes y verá que tampoco existe allí.

Podría importar manualmente el archivo con el cmdlet Import-Module .

PowerShell

Import-Module C:\MyScriptModule.psm1

La característica de carga automática de módulos se introdujo en la versión 3 de


PowerShell. Para aprovechar las ventajas de la carga automática de módulos, un módulo
de script debe guardarse en una carpeta con el mismo nombre base que el archivo
.PSM1 y en una ubicación especificada en $env:PSModulePath .

PowerShell

$env:PSModulePath

Output

C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules;C:\Program
Files\WindowsPowerShell\
Modules;C:\Windows\system32\WindowsPowerShell\v1.0\Modules;C:\Program Files
(x86)\Microsof
t SQL Server\130\Tools\PowerShell\Modules\

Los resultados son difíciles de leer. Puesto que las rutas de acceso están separadas por
un punto y coma, puede dividir los resultados para que cada ruta de acceso se muestre
en una línea independiente. De esta forma, serán más fáciles de leer.

PowerShell

$env:PSModulePath -split ';'

Output

C:\Users\mike-ladm\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules
C:\Program Files (x86)\Microsoft SQL Server\130\Tools\PowerShell\Modules\

Las tres primeras rutas de acceso de la lista son las predeterminadas. Al instalar SQL
Server Management Studio, se agregó la última ruta de acceso. Para que el módulo de
carga automática funcione, el archivo MyScriptModule.psm1 debe encontrarse en una
carpeta denominada MyScriptModule directamente dentro de una de esas rutas de
acceso.

Pero no es tan sencillo. Para mí, la ruta de acceso del usuario actual no es la primera de
la lista. Casi nunca uso esa ruta de acceso, ya que inicio sesión en Windows con un
usuario diferente del que utilizo para ejecutar PowerShell. Esto significa que no se
encuentra en la carpeta Mis documentos normal.

La segunda ruta de acceso es la ruta de acceso AllUsers. Esta es la ubicación donde


almaceno todos los módulos.

La tercera ruta de acceso se encuentra bajo C:\Windows\System32 . Solo Microsoft debe


almacenar módulos en esa ubicación, ya que reside en la carpeta de sistemas
operativos.

Una vez que el archivo .PSM1 se encuentra en la ruta de acceso correcta, el módulo se
cargará automáticamente cuando se llame a uno de sus comandos.

Manifiestos de módulo
Todos los módulos deben tener un manifiesto de módulo. Un manifiesto de módulo
contiene metadatos sobre el módulo. La extensión de archivo de un archivo de
manifiesto de módulo es .PSD1 . No todos los archivos con la extensión .PSD1 son
manifiestos de módulo. También se pueden usar para cosas como el almacenamiento de
la parte de entorno de una configuración de DSC. New-ModuleManifest se usa para crear
un manifiesto de módulo. El único valor necesario es Path. Sin embargo, el módulo no
funcionará si no se especifica RootModule. Es aconsejable especificar Author y
Description en caso de que decida cargar el módulo en un repositorio de NuGet con
PowerShellGet, ya que esos valores son necesarios en ese escenario.

La versión de un módulo sin manifiesto es 0.0. Se trata de una señal inequívoca de que
el módulo no tiene un manifiesto.

PowerShell

Get-Module -Name MyScriptModule

Output

ModuleType Version Name ExportedCommands


---------- ------- ---- ----------------
Script 0.0 myscriptmodule {Get-
MrComputerName, Get-MrP...

El manifiesto de módulo se puede crear con toda la información recomendada.

PowerShell

New-ModuleManifest -Path
$env:ProgramFiles\WindowsPowerShell\Modules\MyScriptModule\MyScriptModule.ps
d1 -RootModule MyScriptModule -Author 'Mike F Robbins' -Description
'MyScriptModule' -CompanyName 'mikefrobbins.com'

Si falta alguna parte de esta información en el momento en que se crea el manifiesto de


módulo, se puede agregar o actualizar más adelante mediante Update-ModuleManifest .
No vuelva a crear el manifiesto mediante New-ModuleManifest una vez que se haya
creado porque el GUID cambiará.

Definir las funciones públicas y privadas


Es posible que tenga funciones auxiliares que desee que sean privadas y accesibles solo
para las demás funciones del módulo. No están diseñadas para ser accesibles para los
usuarios de su módulo. Hay dos formas diferentes de lograrlo.

Si no sigue los procedimientos recomendados y solo tiene un archivo .PSM1 , la única


opción es usar el cmdlet Export-ModuleMember .

PowerShell
function Get-MrPSVersion {
$PSVersionTable
}

function Get-MrComputerName {
$env:COMPUTERNAME
}

Export-ModuleMember -Function Get-MrPSVersion

En el ejemplo anterior, solo la función Get-MrPSVersion está disponible para los usuarios
del módulo, pero la función Get-MrComputerName está disponible para otras funciones
del módulo.

PowerShell

Get-Command -Module MyScriptModule

Output

CommandType Name Version


Source
----------- ---- ------- -
-----
Function Get-MrPSVersion 1.0
MyScriptModule

Si ha agregado un manifiesto de módulo al módulo (que es lo que debería hacer), le


recomiendo que especifique las funciones individuales que desea exportar en la sección
FunctionsToExport del manifiesto del módulo.

PowerShell

FunctionsToExport = 'Get-MrPSVersion'

No es necesario usar tanto Export-ModuleMember en el archivo .PSM1 como la sección


FunctionsToExport del manifiesto del módulo. Basta con usar una de las opciones.

Resumen
En este capítulo, ha aprendido a convertir sus funciones en un módulo de script de
PowerShell. También ha aprendido algunos de los procedimientos recomendados para
crear módulos de script, como crear un manifiesto de módulo para el módulo de script.
Revisar
1. ¿Cómo se crea un módulo de script en PowerShell?
2. ¿Por qué es importante que las funciones usen un verbo aprobado?
3. ¿Cómo se crea un manifiesto de módulo en PowerShell?
4. ¿Cuáles son las dos opciones para exportar solo determinadas funciones del
módulo?
5. ¿Qué se necesita para que los módulos se carguen automáticamente cuando se
llama a un comando?

Lecturas recomendadas
Cómo crear módulos de script de PowerShell y manifiestos de módulo
about_Modules
New-ModuleManifest
Export-ModuleMember
Apéndice A: Sintaxis de la ayuda
Artículo • 13/04/2023

En el siguiente ejemplo se muestra la sección SYNTAX de la ayuda del cmdlet Get-


EventLog .

PowerShell

help Get-EventLog

Output

NAME
Get-EventLog

SYNOPSIS
Gets the events in an event log, or a list of the event logs, on the
local or remote
computers.

SYNTAX
Get-EventLog [-LogName] <String> [[-InstanceId] <Int64[]>] [-After
<DateTime>]
[-AsBaseObject] [-Before <DateTime>] [-ComputerName <String[]>] [-
EntryType {Error |
Information | FailureAudit | SuccessAudit | Warning}] [-Index <Int32[]>]
[-Message
<String>] [-Newest <Int32>] [-Source <String[]>] [-UserName <String[]>]
[<CommonParameters>]

Get-EventLog [-AsString] [-ComputerName <String[]>] [-List]


[<CommonParameters>]

En este ejemplo solo se muestra la parte relevante de la ayuda.

La sintaxis consta fundamentalmente de varios conjuntos de corchetes de apertura y


cierre ( [] ). Estos tienen dos significados diferentes en función de cómo se usen.
Cualquier elemento incluido entre corchetes es opcional, a menos que se trate de un
conjunto de corchetes vacío [] . Los corchetes vacíos solo aparecen después de un tipo
de datos como <string[]> . Esto significa que ese parámetro concreto puede aceptar
más de un valor de ese tipo.

El primer parámetro del primer conjunto de parámetros de Get-EventLog es LogName.


LogName está incluido entre corchetes, lo que significa que es un parámetro posicional.
Es decir, especificar el nombre del parámetro en sí es opcional siempre que se
especifique en la posición correcta. La información de los corchetes angulares ( <> )
después del nombre de parámetro indica que necesita un solo valor string. El nombre
de parámetro completo y el tipo de datos no están incluidos entre corchetes, por lo que
se requiere el parámetro LogName al usar este conjunto de parámetros.

PowerShell

Get-EventLog [-LogName] <String>

El segundo parámetro es InstanceId. Observe que el nombre de parámetro y el tipo de


datos están incluidos entre corchetes en su totalidad. Esto significa que el parámetro
InstanceId es opcional, no obligatorio. Observe también que InstanceId está incluido
entre su propio conjunto de corchetes. Al igual que con el parámetro LogName, esto
significa que el parámetro es posicional. Hay un último conjunto de corchetes después
del tipo de datos. Esto significa que puede aceptar más de un valor en forma de matriz
o lista separada por comas.

[[-InstanceId] <Int64[]>]

El segundo conjunto de parámetros tiene un parámetro List. Es un parámetro de


modificador, porque no hay ningún tipo de datos tras el nombre de parámetro. Cuando
se especifica el parámetro List, el valor es True. Cuando no se especifica, el valor es
False.

[-List]

La información de sintaxis de un comando también se puede recuperar mediante Get-


Command con el parámetro Syntax. Se trata de un acceso directo útil que yo uso todo el

tiempo. Me permite aprender rápidamente a usar un comando sin tener que leer varias
páginas de información de ayuda. Si al final necesito más información, vuelvo a usar el
contenido de la ayuda real.

PowerShell

Get-Command -Name Get-EventLog -Syntax

Output
Get-EventLog [-LogName] <string> [[-InstanceId] <long[]>] [-ComputerName
<string[]>] [-Newest <int>]
[-After <datetime>] [-Before <datetime>] [-UserName <string[]>] [-Index
<int[]> ]
[-EntryType <string[]>] [-Source <string[]>] [-Message <string>] [-
AsBaseObject]
[<CommonParameters>]

Get-EventLog [-ComputerName <string[]>] [-List] [-AsString]


[<CommonParameters>]

Cuanto más se usa el sistema de ayuda de PowerShell, más fácil resulta recordar todos
los distintos matices. Antes de darse cuenta, su uso se convierte en una segunda
naturaleza.
Optimización de la experiencia del shell
Artículo • 13/04/2023

PowerShell es un shell de línea de comandos y un lenguaje de scripting, todo en uno.

En Wikipedia se incluye la siguiente descripción de un shell:

Un shell administra la interacción del sistema de usuario mediante la solicitud de


entrada a los usuarios, su interpretación y, después, el control de la salida desde el
sistema operativo subyacente (como un bucle de lectura, evaluación e impresión, o
REPL ).

De forma similar a otros shells como bash o cmd.exe , PowerShell le permite ejecutar
cualquier comando disponible en el sistema, no solo los de PowerShell.

Los comandos de PowerShell se conocen como cmdlets. Los cmdlets son comandos de
PowerShell, no ejecutables independientes. Los comandos de PowerShell no se pueden
ejecutar en otros shells sin ejecutar primero PowerShell.

Características de la interfaz de la línea de


comandos de PowerShell
PowerShell es un shell de comandos moderno que incluye las mejores características de
otros shells populares. A diferencia de la mayoría de los shells que solo aceptan y
devuelven texto, PowerShell acepta y devuelve objetos .NET. El shell tiene varias
características que puede usar para optimizar la experiencia interactiva del usuario.

Un historial de línea de comandos sólido.


Finalización con tabulación y predicción de comandos
Admite alias de comando y parámetro.
Canalización para encadenar comandos.
Sistema de ayuda en la consola, similar a las páginas man de UNIX.

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Ejecución de comandos en el Shell
Artículo • 13/04/2023

PowerShell es un shell de línea de comandos y un lenguaje de scripting, todo en uno.


De forma similar a otros shells, como bash en Linux o el shell de comandos de Windows
( cmd.exe ), PowerShell le permite ejecutar cualquier comando disponible en el sistema,
no solo los de PowerShell.

Tipos de comandos
Para cualquier shell de cualquier sistema operativo existen tres tipos de comandos:

Las palabras clave del lenguaje del shell forman parte del lenguaje de scripting
del shell.
Algunos ejemplos de palabras clave de bash son los siguientes: if , then , else ,
elif y fi .

Algunos ejemplos de palabras clave de cmd.exe son los siguientes: dir , copy ,
move , if y echo .

Algunos ejemplos de palabras clave de PowerShell son los siguientes: for ,


foreach , try , catch y trap .

Las palabras clave del lenguaje del shell solo se pueden usar en el entorno de
tiempo de ejecución del shell. No hay ningún archivo ejecutable externo al shell
que proporcione la función de la palabra clave.

Los comandos nativos del sistema operativo son archivos ejecutables instalados
en el sistema operativo. Los archivos ejecutables se pueden ejecutar desde
cualquier shell de línea de comandos, como PowerShell. Esto incluye archivos de
script que pueden requerir que otros shells funcionen correctamente. Por ejemplo,
si ejecuta un script por lotes de Windows (archivo .cmd ) en PowerShell, este
ejecuta cmd.exe y pasa el archivo por lotes para su ejecución.

Los comandos específicos del entorno del shell son comandos definidos en
archivos externos que solo se pueden usar en el entorno de tiempo de ejecución
del shell. Estos incluyen scripts y funciones, o pueden ser módulos especialmente
compilados que agregan comandos al entorno de ejecución del shell. En
PowerShell, estos comandos se conocen como cmdlets (pronunciado "command-
lets").
Ejecución de comandos nativos
Cualquier comando nativo se puede ejecutar desde la línea de comandos de PowerShell.
Normalmente, el comando se ejecuta exactamente igual que se haría en bash o
cmd.exe . En el ejemplo siguiente se muestra cómo ejecutar el comando grep en bash
en Ubuntu Linux.

Bash

sdwheeler@circumflex:~$ grep sdwheeler /etc/passwd


sdwheeler:x:1000:1000:,,,:/home/sdwheeler:/bin/bash
sdwheeler@circumflex:~$ pwsh
PowerShell 7.2.6
Copyright (c) Microsoft Corporation.

https://aka.ms/powershell
Type 'help' to get help.

Después de iniciar PowerShell en Ubuntu, puede ejecutar el mismo comando desde la


línea de comandos de PowerShell:

PowerShell

PS /home/sdwheeler> grep sdwheeler /etc/passwd


sdwheeler:x:1000:1000:,,,:/home/sdwheeler:/bin/bash

Paso de argumentos a comandos nativos


La mayoría de los shells incluyen características para usar variables, evaluar expresiones
y controlar cadenas. Pero cada shell hace estas cosas de manera distinta. En PowerShell,
todos los parámetros comienzan con un carácter de guion ( - ). En cmd.exe , la mayoría
de los parámetros usan un carácter de barra diagonal ( / ). Es posible que otras
herramientas de línea de comandos no tengan un carácter especial para los parámetros.

Cada shell tiene su propia manera de controlar y evaluar cadenas en la línea de


comandos. Al ejecutar comandos nativos en PowerShell que esperan que las cadenas
estén entrecomilladas de forma específica, es posible que necesite ajustar cómo se
pasan esas cadenas.

Para más información, consulte los siguientes artículos.

about_Parsing
about_Quoting_Rules
PowerShell 7.2 ha introducido una nueva característica PSnativeCommandArgumentPassing
experimental que ha mejorado el control de comandos nativos. Para obtener más
información, vea PSnativeCommandArgumentPassing.

Control de la salida y los errores


PowerShell también tiene varios flujos de salida más que otros shells. Los shells bash y
cmd.exe tienen stdout y stderr. PowerShell tiene seis flujos de salida. Para obtener más

información, vea about_Redirection y about_Output_Streams.

Por lo general, la salida que envía a stdout un comando nativo se envía al flujo Success
en PowerShell. La salida que envía a stderr un comando nativo se envía al flujo Error en
PowerShell.

Cuando un comando nativo tiene un código de salida distinto de cero, $? se establece


en $false . Si el código de salida es cero, $? se establece en $true .

Pero esto ha cambiado en PowerShell 7.2. Los registros de error redirigidos desde
comandos nativos, igual que cuando se usan operadores de redireccionamiento ( 2>&1 ),
no se escriben en la variable $Error de PowerShell y la variable de preferencia
$ErrorActionPreference no afecta a la salida redirigida.

Muchos comandos nativos escriben en stderr a modo de flujo alternativo para obtener
información adicional. Este comportamiento puede llevar a confusión en PowerShell
cuando se examinan los errores; también, se puede perder la información de salida
adicional si $ErrorActionPreference se establece en un estado que silencia la salida.

PowerShell 7.3 ha agregado una nueva característica


PSnativeCommandErrorActionPreference experimental que le permite controlar si la salida
a stderr se trata como un error. Para obtener más información, vea
PSnativeCommandErrorActionPreference.

Ejecución de comandos de PowerShell


Tal como se ha indicado anteriormente, los comandos de PowerShell se conocen como
cmdlets. Los cmdlets se recopilan en módulos de PowerShell que se pueden cargar a
petición. Los cmdlets se pueden escribir en cualquier lenguaje .NET compilado o con el
mismo lenguaje de scripting de PowerShell.

Comandos de PowerShell que ejecutan otros comandos


El operador de llamada de PowerShell ( & ) permite ejecutar comandos almacenados en
variables y que representan cadenas o bloques de script. Puede usarlo para ejecutar
cualquier comando nativo o de PowerShell. Esto resulta útil en un script cuando es
necesario construir dinámicamente los parámetros de la línea de comandos para un
comando nativo. Para obtener más información, vea el operador de llamada.

El cmdlet Start-Process se puede usar para ejecutar comandos nativos, pero solo debe
usarse cuando necesite controlar cómo se ejecuta el comando. El cmdlet tiene
parámetros para admitir los escenarios siguientes:

Ejecución de un comando con credenciales diferentes


Ocultación de la ventana de consola que ha creado el proceso nuevo
Redirección de los flujos stdin, stdout y stderr
Uso de otro directorio de trabajo para el comando

En el ejemplo siguiente se ejecuta el comando nativo sort.exe con flujos de entrada y


salida redirigidos.

PowerShell

$processOptions = @{
FilePath = "sort.exe"
RedirectStandardInput = "TestSort.txt"
RedirectStandardOutput = "Sorted.txt"
RedirectStandardError = "SortError.txt"
UseNewEnvironment = $true
}
Start-Process @processOptions

Para obtener más información, vea Start-Process.

En Windows, el cmdlet Invoke-Item realiza la acción predeterminada para el elemento


especificado. Por ejemplo, ejecuta un archivo ejecutable o abre un archivo de
documento con la aplicación asociada al tipo de archivo del documento. La acción
predeterminada depende del tipo de elemento y la resuelve el proveedor de PowerShell
que proporciona acceso al elemento.

En el ejemplo siguiente se abre el repositorio de código fuente de PowerShell en el


explorador web predeterminado.

PowerShell

Invoke-Item https://github.com/PowerShell/PowerShell

Para obtener más información, vea Invoke-Item.


Uso de la finalización con tabulación en
el shell
Artículo • 13/04/2023

PowerShell proporciona finalizaciones en la entrada para proporcionar sugerencias,


habilitar la detección y acelerar la entrada. Los nombres de comandos y parámetros, los
valores de argumento y las rutas de acceso de archivo se pueden completar al presionar
la tecla Tab .

La tecla Tab es el enlace de teclado predeterminado en Windows. PSReadLine también


proporciona una función MenuComplete que está enlazada a Ctrl + Espacio . La función
MenuComplete muestra una lista de finalizaciones coincidentes debajo de la línea de

comandos.

Estos enlaces de teclado se pueden cambiar mediante cmdlets de PSReadLine o la


aplicación en la que se hospeda PowerShell. Los enlaces de teclado pueden ser
diferentes en plataformas que no son de Windows. Para más información, vea Acerca de
las funciones de PSReadLine.

Características integradas de la finalización con


tabulación
PowerShell ha habilitado la finalización con tabulación para muchos aspectos de la
experiencia de la línea de comandos.

Finalización de nombres
Para rellenar automáticamente un nombre de archivo o una ruta de acceso desde las
opciones disponibles, escriba parte del nombre y presione la tecla Tab . PowerShell
expandirá automáticamente el nombre a la primera coincidencia que encuentre. Al
volver a presionar la tecla Tab , se recorren todas las opciones disponibles con cada
pulsación de tecla.

Finalización de nombres de comando y parámetro


La expansión de pestañas de nombres de cmdlet es ligeramente diferente. Para usar la
expansión de pestañas en un nombre de cmdlet, escriba la primera parte completa del
nombre (verbo) y el guion que aparece detrás. Puede seguir rellenando el nombre para
obtener una coincidencia parcial. Por ejemplo, si escribe get-co y, después, presiona la
tecla Tab , PowerShell lo expandirá automáticamente al cmdlet Get-Command (tenga en
cuenta que también se cambiarán las letras mayúsculas y minúsculas a su formato
estándar). Si vuelve a presionar la tecla de tabulación , PowerShell lo reemplazará por el
otro único nombre de cmdlet coincidente, Get-Content . La finalización con tabulación
también funciona para resolver alias de PowerShell y ejecutables nativos.

En el gráfico siguiente se muestran ejemplos de finalización de pestañas y menús.

Otras mejoras de la finalización con tabulación


Cada versión nueva de PowerShell incluye mejoras en la finalización con tabulación que
corrigen errores y mejoran la facilidad de uso.

PowerShell 7.0

La finalización con tabulación resuelve las asignaciones de variables que son


enumeraciones o están restringidas por tipos
La finalización con tabulación expande cmdlets y funciones abreviados. Por
ejemplo, i-psdf<tab> devuelve Import-PowerShellDataFile

PowerShell 7.2

Se ha corregido la finalización con tabulación para temas about* no localizados


Se ha corregido la plataforma que se trata como parámetro posicional en las
finalizaciones
Se han agregado finalizaciones para palabras clave de ayuda basadas en
comentarios
Se ha agregado finalización para las instrucciones #requires
Se ha agregado finalización con tabulación para el parámetro View de los cmdlets
Format-*

Se ha agregado compatibilidad con los completadores de argumentos basados en


clases

PowerShell 7.3

Se ha corregido la finalización con tabulación dentro del bloque de script


especificado para ValidateScriptAttribute
Se ha agregado finalización con tabulación para las etiquetas de bucle después de
break y continue
Se ha mejorado la finalización de la tabla hash en varios escenarios
Expansión de parámetros
Parámetro Arguments para Invoke-CimMethod
Parámetro FilterHashtable para Get-WinEvent
Parámetro Property para los cmdlets CIM
Quita los duplicados de los escenarios de finalización de miembros.
Compatibilidad con las barras diagonales en la finalización del recurso compartido
de red (ruta de acceso UNC)
Se ha mejorado la finalización automática de miembros
Clasificación por orden de prioridad de las finalizaciones ValidateSet en las
enumeraciones de los parámetros
Se ha agregado compatibilidad con la inferencia de tipos para métodos genéricos
con parámetros de tipo
Se ha mejorado la inferencia de tipos y finalizaciones
Permite que los métodos se muestren en los resultados de finalización de
ForEach-Object -MemberName .

Impide la finalización en expresiones que devuelven void como ( [void]("") )


Permite que los constructores de clase no predeterminados se muestren cuando
la finalización de la clase se basa en AST.

Otras formas de mejorar la finalización con


tabulación de los parámetros de comando
La función interna TabExpansion o TabExpansion2 controla la expansión con tabulación
integrada. Es posible crear funciones o módulos que reemplacen el comportamiento
predeterminado de estas funciones. Para encontrar ejemplos en la Galería de
PowerShell, busque la palabra clave TabExpansion .

Uso de los atributos ValidateSet o ArgumentCompletions


con parámetros
El atributo ArgumentCompletions permite agregar valores de finalización con tabulación a
un parámetro específico. El atributo ArgumentCompletions es similar a ValidateSet . Los
dos atributos toman una lista de valores que se presentan cuando el usuario presiona
Tab después del nombre del parámetro. Pero a diferencia de ValidateSet , los valores
no se validan.

Para más información, consulte:

ArgumentCompletions
ValidateSet

Uso del atributo ArgumentCompleter o Register-


ArgumentCompleter con parámetros

Un completador de argumentos es un bloque de script o una función que proporciona


finalización con tabulación dinámica para los valores de parámetro.

El atributo ArgumentCompleter permite registrar una función que proporciona valores de


finalización con tabulación para el parámetro. La función de completador de argumento
debe estar disponible para la función que contiene el parámetro con el atributo
ArgumentCompleter . Normalmente, la función se define en el mismo script o módulo.

Para más información, vea ArgumentCompleter.

El cmdlet Register-ArgumentCompleter registra un bloque de script como una función de


completador de argumentos en tiempo de ejecución para cualquier comando que
especifique. Esto le permite definir completadores de argumentos fuera del script o
módulo, o bien para comandos nativos. Para más información, vea Register-
ArgumentCompleter.

IntelliSense predictivo en
En PSReadLine 2.1.0 se ha presentado la característica IntelliSense predictivo.
IntelliSense predictivo proporciona sugerencias para comandos completos basados en
elementos del historial de PSReadLine.
PSReadLine 2.2.2 amplía la eficacia de IntelliSense predictivo mediante la adición de
compatibilidad con módulos de complemento que usan lógica avanzada a fin de
proporcionar sugerencias para comandos completos. El módulo Az.Tools.Predictor fue
el primer complemento para IntelliSense predictivo. Usa el aprendizaje automático para
predecir qué comando de Azure PowerShell se quiere ejecutar y qué parámetros se
quieren usar.

Para más información, vea Uso de predictores.


Uso de predictores en PSReadLine
Artículo • 13/04/2023

En PSReadLine 2.1.0 se ha presentado la característica IntelliSense predictivo.


IntelliSense predictivo proporciona sugerencias para comandos completos basados en
elementos del historial de PSReadLine. PSReadLine 2.2.2 amplía la eficacia de
IntelliSense predictivo mediante la adición de compatibilidad con módulos de
complemento que usan lógica avanzada a fin de proporcionar sugerencias para
comandos completos. La versión más reciente, PSReadLine 2.2.6, habilita las
predicciones de forma predeterminada.

Uso de IntelliSense predictivo


Cuando IntelliSense predictivo está habilitado, la sugerencia de predicción aparece
como texto coloreado después del cursor del usuario. Las sugerencias de IntelliSense
predictivo ayudan a los usuarios nuevos y experimentados de PowerShell a detectar,
editar y ejecutar comandos completos basados en predicciones coincidentes. Las
sugerencias pueden proceder del historial del usuario y de complementos específicos
del dominio adicionales.

En las imágenes anteriores se muestra el valor predeterminado InlineView de la


sugerencia. Al presionar la tecla Flecha Derecha se acepta una sugerencia insertada.
Después de aceptar la sugerencia, puede editar la línea de comandos antes de presionar
Entrar para ejecutar el comando.

PSReadLine también ofrece una presentación ListView de las sugerencias.


Cuando se encuentra en la vista de lista, puede usar las teclas de dirección para
desplazarse por las sugerencias disponibles. En la vista de lista también se muestra el
origen de la predicción.

PSReadLine tiene como valor predeterminado InlineView . Puede cambiar entre


InlineView y ListView si presiona la tecla F2 . También puede usar el parámetro

PredictionViewStyle de Set-PSReadLineOption para cambiar la vista.

Administración de IntelliSense predictivo


Para usar IntelliSense predictivo debe tener instalada una versión más reciente de
PSReadLine. Para obtener los mejores resultados, instale la versión más reciente del
módulo.

Para instalar PSReadLine mediante PowerShellGet:

PowerShell

Install-Module -Name PSReadLine

O bien, realice la instalación con el nuevo módulo PowerShellGet v3 :

PowerShell

Install-PSResource -Name PSReadLine

PSReadLine se puede instalar en Windows PowerShell 5.1 o en PowerShell 7 o versiones


posteriores. Para usar complementos de predicción, debe ejecutar PowerShell 7.2 o
superior. Window PowerShell 5.1 puede usar el predictor basado en el historial.

En PSReadLine 2.2.6, IntelliSense predictivo está habilitado de forma predeterminada en


función de las condiciones siguientes:
Si se admite Terminal virtual (VT) y PSReadLine se ejecuta en PowerShell 7.2 o
posterior, PredictionSource se establece en HistoryAndPlugin
Si se admite VT y PSReadLine se ejecuta en otra versión distinta de PowerShell 7.2,
PredictionSource se establece en History
Si no se admite VT, PredictionSource se establece en None .

Use el comando siguiente para ver la configuración actual:

PowerShell

Get-PSReadLineOption | Select-Object -Property PredictionSource

Puede cambiar el origen de predicción mediante el cmdlet Set-PSReadLineOption con el


parámetro PredictionSource. PredictionSource se puede establecer en lo siguiente:

None
History

Plugin

HistoryAndPlugin

7 Nota

Las predicciones basadas en el historial proceden del historial mantenido por


PSReadLine. Ese historial es más completo que el historial basado en la sesión que
puede ver mediante Get-History . Para más información, vea la sección Historial de
comandos de about_PSReadLine.

Establecimiento del color de predicción


De forma predeterminada, las predicciones aparecen en texto gris claro en la misma
línea en la que escribe el usuario. Para admitir las necesidades de accesibilidad, puede
personalizar el color de predicción. Los colores se definen mediante secuencias de
escape ANSI. Puede usar $PSStyle para crear secuencias de escape ANSI.

PowerShell

Set-PSReadLineOption -Colors @{ InlinePrediction = $PSStyle.Background.Blue


}

O bien, puede crear secuencias propias. El color gris claro predeterminado del de texto
de predicción se puede restaurar mediante la siguiente secuencia de escape ANSI.
PowerShell

Set-PSReadLineOption -Colors @{ InlinePrediction = "`e[38;5;238m" }

Para más información sobre cómo establecer el color de predicción y otros valores de
PSReadLine, vea Set-PSReadLineOption.

Cambio de los enlaces de teclado


PSReadLine contiene funciones para navegar y aceptar predicciones. Por ejemplo:

AcceptSuggestion : aceptar la sugerencia insertada actual


AcceptNextSuggestionWord : aceptar la palabra siguiente de la sugerencia insertada

AcceptSuggestion se crea dentro de ForwardChar , que está enlazado a RightArrow


de forma predeterminada
AcceptNextSuggestionWord se crea dentro de la función ForwardWord , que se puede

enlazar a Ctrl + f

Puede usar el cmdlet Set-PSReadLineKeyHandler para cambiar los enlaces de teclado.

PowerShell

Set-PSReadLineKeyHandler -Chord "Ctrl+f" -Function ForwardWord

Con este enlace, al presionar Ctrl + f se acepta la siguiente palabra de una sugerencia
insertada cuando el cursor está al final de la línea de edición actual. Puede enlazar otras
teclas a AcceptSuggestion y AcceptNextSuggestionWord para funcionalidades similares.
Por ejemplo, es posible que quiera que RightArrow acepte la palabra siguiente de la
sugerencia insertada, en lugar de toda la línea de sugerencia.

PowerShell

Set-PSReadLineKeyHandler -Chord "RightArrow" -Function ForwardWord

Uso de otros complementos de predicción


El módulo Az.Tools.Predictor fue el primer complemento para IntelliSense predictivo.
Usa el aprendizaje automático para predecir qué comando de Azure PowerShell se
quiere ejecutar y qué parámetros se quieren usar. Para más información e instrucciones
de instalación, vea Anuncio de la disponibilidad general de Az.Tools.Predictor .
El módulo CompletionPredictor agrega una experiencia de IntelliSense para todo lo que
se pueda completar mediante tabulaciones en PowerShell. Con PSReadLine establecido
en InlineView , obtendrá la experiencia de finalización de tabulación normal. Al cambiar
a ListView , obtendrá la experiencia de IntelliSense. Puede instalar el módulo
CompletionPredictor desde la Galería de PowerShell.

Como se ha indicado antes, ListView muestra el origen de la predicción. Si tiene varios


complementos instalados, las predicciones se agrupan por origen y primero se enumera
Historial, seguido de cada complemento en el orden en que se hayan cargado.

Creación de un módulo de predicción propio


Puede escribir un predictor propio mediante C# para crear un módulo de PowerShell
compilado. El módulo debe implementar la interfaz
System.Management.Automation.Subsystem.Prediction.ICommandPredictor. Esta
interfaz declara los métodos usados para consultar los resultados de la predicción y
proporcionar comentarios.

Para más información, vea Procedimiento para crear un predictor de línea de comandos.
Uso de la ayuda dinámica
Artículo • 29/03/2023

La ayuda dinámica proporciona ayuda Just-In-Time que le permite centrarse en el


trabajo sin perder la posición mientras escribe en la línea de comandos.

Obtención de ayuda de cmdlets


La ayuda dinámica proporciona una vista de la ayuda completa del cmdlet que se
muestra en un búfer de pantalla alternativo. PSReadLine asigna la función
ShowCommandHelp a la tecla F1 .

Cuando el cursor se encuentra al final de un nombre de cmdlet totalmente


expandido, al presionar F1 se muestra la ayuda de ese cmdlet.
Cuando el cursor se encuentra al final de un nombre de parámetro totalmente
expandido, al presionar F1 se muestra la ayuda del cmdlet comenzando en el
parámetro.

El control de paginación de PSReadLine permite desplazar la ayuda mostrada mediante


las teclas de dirección Flecha arriba y Flecha abajo. Al presionar Q se cierra el búfer de
pantalla alternativo y se vuelve a la posición actual del cursor en la línea de comandos
de la pantalla principal.

Obtención de ayuda de parámetros prioritaria


Al presionar Alt + h se proporciona ayuda dinámica para los parámetros. La ayuda se
muestra debajo de la línea de comandos actual, de forma similar a MenuComplete. El
cursor debe estar al final del nombre del parámetro totalmente expandido al presionar
Alt + h .

Selección de argumentos en la línea de


comandos
Permite seleccionar y editar rápidamente los argumentos de un cmdlet sin alterar la
sintaxis mediante Alt + a . En función de la posición del cursor, busca desde la posición
actual y se detiene cuando encuentra cualquier argumento en la línea de comandos.

Elección de enlaces de teclado


No todos los enlaces de teclado funcionan para todos los sistemas operativos y las
aplicaciones de terminal. Por ejemplo, los enlaces de teclado para la tecla Alt no
funcionan en macOS de forma predeterminada. En Linux, Ctrl + [ tiene la misma
función que Escape .Y Ctrl + Barra espaciadora genera una secuencia de teclas Control +
2 en lugar de la secuencia Control + Barra espaciadora esperada.

Para solucionar estas peculiaridades, asigne la función PSReadLine a una combinación


de teclas disponible. Por ejemplo:

PowerShell

Set-PSReadLineKeyHandler -chord 'Ctrl+l' -Function ShowParameterHelp


Set-PSReadLineKeyHandler -Chord 'Ctrl+k' -Function SelectCommandArgument

Para obtener más información sobre los enlaces de teclado y las soluciones alternativas,
consulte Uso de los controladores de claves de PSReadLine.
Uso de alias
Artículo • 13/04/2023

Un alias es un nombre alternativo o un nombre abreviado para un cmdlet o para un


elemento de comando, como una función, un script, un archivo o un archivo ejecutable.
Puede ejecutar el comando con el alias en lugar del nombre ejecutable.

Administración de alias de comandos


PowerShell proporciona cmdlets para administrar alias de comandos.

PowerShell

Get-Command -Noun Alias

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Export-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Get-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Import-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet New-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Remove-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Set-Alias 7.0.0.0 Microsoft.PowerShell.Utility

Para más información, vea about_Aliases.

Use el cmdlet Get-Alias para enumerar los alias disponibles en el entorno. Para
enumerar los alias de un único cmdlet, use el parámetro Definition y especifique el
nombre ejecutable.

PowerShell

Get-Alias -Definition Get-ChildItem

Output

CommandType Name
----------- ----
Alias dir -> Get-ChildItem
Alias gci -> Get-ChildItem
Alias ls -> Get-ChildItem
Para obtener la definición de un único alias, use el parámetro Name.

PowerShell

Get-Alias -Name gci

Output

CommandType Name
----------- ----
Alias gci -> Get-ChildItem

Alias de compatibilidad en Windows


PowerShell tiene varios alias que permiten a los usuarios de UNIX y cmd.exe utilizar
comandos familiares en Windows. En la tabla siguiente se muestran comandos
comunes, el cmdlet de PowerShell relacionado y el alias de PowerShell:

Comando Comando de Cmdlet de Alias de PowerShell


cmd.exe UNIX PowerShell

cd, chdir cd Set-Location sl , cd , chdir

cls eliminar Clear-Host cls clear

copy cp Copy-Item cpi , cp , copy

del, erase, rd, rm Remove-Item ri , del , erase , rd , rm ,


rmdir rmdir

dir ls Get-ChildItem gci , dir , ls

echo echo Write-Output write echo

md mkdir New-Item ni

move mv Move-Item mi , move , mi

popd popd Pop-Location popd

pwd Get-Location gl , pwd

pushd pushd Push-Location pushd

ren mv Rename-Item rni , ren

type cat Get-Content gc , cat , type


7 Nota

Los alias de esta tabla son específicos de Windows. Algunos alias no están
disponibles en otras plataformas. Esto es así para permitir que el comando nativo
funcione en una sesión de PowerShell. Por ejemplo, ls no se define como un alias
de PowerShell en macOS ni Linux, por lo que en lugar de Get-ChildItem se ejecuta
el comando nativo.

Creación de nombres alternativos para


comandos con parámetros
Puede asignar un alias a un cmdlet, script, función o archivo ejecutable. A diferencia de
algunos shells de Unix, no se puede asignar un alias a un comando con parámetros. Por
ejemplo, puede asignar un alias al cmdlet Get-Eventlog , pero no al comando Get-
Eventlog -LogName System . Tendrá que crear una función que contenga el comando con

parámetros.

Para más información, vea about_Aliases.

Alias de parámetro y nombres abreviados


PowerShell también proporciona maneras de crear nombres abreviados para
parámetros. Los alias de parámetro se definen mediante el atributo Alias al declarar el
parámetro. No se pueden definir mediante los cmdlets *-Alias .

Para más información, vea la documentación del atributo de alias.

Además de los alias de parámetro, PowerShell permite especificar el nombre del


parámetro con la menor cantidad de caracteres necesarios para identificar de forma
única el parámetro. Por ejemplo, el cmdlet Get-ChildItem tiene los parámetros Recurse
y ReadOnly. Para identificar de forma única el parámetro Recurse, solo debe
proporcionar -rec . Si lo combina con el alias de comando, Get-ChildItem -Recurse se
puede abreviar como dir -rec .

No usar alias en scripts


Los alias son una característica de conveniencia para usar de forma interactiva en el
shell. Siempre debe usar los nombres de parámetros y comandos completos en los
scripts.

Los alias se pueden eliminar o redefinir en un script de perfil


Es posible que los alias que defina no estén disponibles para el usuario de los
scripts
Los alias hacen que el código sea más difícil de leer y mantener

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Personalización del entorno de shell
Artículo • 13/04/2023

Un perfil de PowerShell es un script que se ejecuta cuando se inicia PowerShell. Puede


usar el perfil para personalizar el entorno. Puede:

agregar alias, funciones y variables


cargar módulos
crear unidades de PowerShell
ejecutar comandos arbitrarios
y cambiar la configuración de preferencias

Aplicar esta configuración en el perfil garantiza que esté disponible cada vez que inicie
PowerShell en el sistema.

7 Nota

Para ejecutar scripts en Windows, la directiva de ejecución de PowerShell tiene que


establecerse en RemoteSigned como mínimo. Las directivas de ejecución no se
aplican a macOS ni Linux. Para obtener más información, consulte
about_Execution_Policy.

Variable $PROFILE
La variable automática $PROFILE almacena las rutas de acceso a los perfiles de
PowerShell que están disponibles en la sesión actual.

Hay cuatro perfiles posibles disponibles para admitir distintos ámbitos de usuario y
diferentes hosts de PowerShell. Las rutas de acceso completas de cada script de perfil se
almacenan en las propiedades de miembro de $PROFILE que se indican a continuación.

AllUsersAllHosts
AllUsersCurrentHost
CurrentUserAllHosts
CurrentUserCurrentHost

Puede crear scripts de perfil que se ejecuten para todos los usuarios o solo uno, el
CurrentUser. Los perfiles CurrentUser se almacenan en el directorio principal del
usuario.
También hay perfiles que se ejecutan para todos los hosts de PowerShell o hosts
específicos. El script de perfil para cada host de PowerShell tiene un nombre único para
ese host. Por ejemplo, el nombre de archivo del host de consola estándar en Windows o
la aplicación de terminal predeterminada en otras plataformas es
Microsoft.PowerShell_profile.ps1 . En el caso de Visual Studio Code (VS Code), el

nombre de archivo es Microsoft.VSCode_profile.ps1 .

Para obtener más información, consulte about_Profiles.

De manera predeterminada, al hacer referencia a la variable $PROFILE , se devuelve la


ruta de acceso al perfil "Current User, Current Host". Se puede acceder a la ruta de otros
perfiles a través de las propiedades de la variable $PROFILE . Por ejemplo:

PowerShell

PS> $PROFILE
C:\Users\user1\Documents\PowerShell\Microsoft.PowerShell_profile.ps1
PS> $PROFILE.AllUsersAllHosts
C:\Program Files\PowerShell\7\profile.ps1

Cómo crear su perfil personal


Al instalar PowerShell por primera vez en un sistema, los archivos de script de perfil y los
directorios a los que pertenecen no existen. El comando que se indica a continuación
crea el archivo de script de perfil "Current User, Current Current Host" si no existe.

PowerShell

if (!(Test-Path -Path $PROFILE)) {


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

El parámetro Force del cmdlet New-Item crea las carpetas necesarias si no existen. Una
vez creado el archivo de script, puede usar su editor favorito para personalizar el
entorno de shell.

Adición de personalizaciones al perfil


En los artículos anteriores se ha hablado sobre el uso de la finalización con tabulación,
los predictores de comandos y los alias. En estos artículos se mostraban los comandos
utilizados para cargar los módulos requeridos, crear completadores personalizados,
definir enlaces de teclado y otras opciones de configuración. Estos son los tipos de
personalizaciones que desea tener disponibles en cada sesión interactiva de PowerShell.
El script de perfil es el lugar para esta configuración.

La forma más sencilla de editar el script de perfil es abrir el archivo en el editor de


código que prefiera. Por ejemplo, el comando a continuación abre el perfil en
VS Code .

PowerShell

code $PROFILE

También puede usar notepad.exe en Windows, vi en Linux o cualquier otro editor de


texto.

El script de perfil a continuación tiene ejemplos de muchas de las personalizaciones


mencionadas en los artículos anteriores. Puede usar cualquiera de estas opciones de
configuración en su propio perfil.

PowerShell

## Map PSDrives to other registry hives


if (!(Test-Path HKCR:)) {
$null = New-PSDrive -Name HKCR -PSProvider Registry -Root
HKEY_CLASSES_ROOT
$null = New-PSDrive -Name HKU -PSProvider Registry -Root HKEY_USERS
}

## Customize the prompt


function prompt {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = [Security.Principal.WindowsPrincipal] $identity
$adminRole = [Security.Principal.WindowsBuiltInRole]::Administrator

$prefix = $(if (Test-Path variable:/PSDebugContext) { '[DBG]: ' }


elseif ($principal.IsInRole($adminRole)) { "[ADMIN]: " }
else { '' })
$body = 'PS ' + $(Get-Location)
$suffix = $(if ($NestedPromptLevel -ge 1) { '>>' }) + '> '
$prefix + $body + $suffix
}

## Create $PSStyle if running on a version older than 7.2


## - Add other ANSI color definitions as needed

if ($PSVersionTable.PSVersion.ToString() -lt '7.2.0') {


# define escape char since "`e" may not be supported
$esc = [char]0x1b
$PSStyle = [pscustomobject]@{
Foreground = @{
Magenta = "${esc}[35m"
BrightYellow = "${esc}[93m"
}
Background = @{
BrightBlack = "${esc}[100m"
}
}
}

## Set PSReadLine options and keybindings


$PSROptions = @{
ContinuationPrompt = ' '
Colors = @{
Operator = $PSStyle.Foreground.Magenta
Parameter = $PSStyle.Foreground.Magenta
Selection = $PSStyle.Background.BrightBlack
InLinePrediction = $PSStyle.Foreground.BrightYellow +
$PSStyle.Background.BrightBlack
}
}
Set-PSReadLineOption @PSROptions
Set-PSReadLineKeyHandler -Chord 'Ctrl+f' -Function ForwardWord
Set-PSReadLineKeyHandler -Chord 'Enter' -Function ValidateAndAcceptLine

## Add argument completer for the dotnet CLI tool


$scriptblock = {
param($wordToComplete, $commandAst, $cursorPosition)
dotnet complete --position $cursorPosition $commandAst.ToString() |
ForEach-Object {
[System.Management.Automation.CompletionResult]::new($_, $_,
'ParameterValue', $_)
}
}
Register-ArgumentCompleter -Native -CommandName dotnet -ScriptBlock
$scriptblock

En este script de perfil se dan ejemplos de la personalización siguiente:

Agrega dos nuevos PSDrive para los otros subárboles del Registro raíz.
Crea una indicación personalizada que cambia si se ejecuta en una sesión con
privilegios elevados.
Configura PSReadLine y agrega el enlace de teclado. La configuración de color usa
la característica $PSStyle para definir la configuración de color ANSI.
Agrega la finalización con tabulación para la herramienta de la CLI de dotnet. La
herramienta proporciona parámetros para ayudar a resolver los argumentos de la
línea de comandos. El bloque de script de Register-ArgumentCompleter usa esa
característica para proporcionar la finalización con tabulación.
Uso de los controladores de teclas de
PSReadLine
Artículo • 29/03/2023

El módulo PSReadLine proporciona controladores de teclas que asignan funciones de


PSReadLine a acordes de teclado. Los acordes de teclado son una secuencia de una o
varias pulsaciones de teclas que se presionan al mismo tiempo. Por ejemplo, el acorde
Ctrl + Barra espaciadora es la combinación de las teclas Ctrl y Barra espaciadora

presionadas al mismo tiempo. Una función de PSReadLine es una acción predefinida


que se puede realizar en una línea de comandos. Por ejemplo, la función MenuComplete
permite elegir entre una lista de opciones de un menú que completa la entrada en la
línea de comandos.

PSReadLine tiene varios controladores de teclas predefinidos que están enlazados de


forma predeterminada. También puede definir sus propios controladores de teclas
personalizados. Ejecute el siguiente comando para enumerar los controladores de teclas
que están definidos actualmente.

PowerShell

Get-PSReadLineKeyHandler

También puede obtener una lista de todas las funciones de PSReadLine que están
disponibles para enlazarlas a un acorde de teclas.

PowerShell

Get-PSReadLineKeyHandler -Unbound

Puede usar el cmdlet Set-PSReadLineKeyHandler para enlazar una función a un


controlador de teclas. El siguiente comando enlaza la función MenuComplete al acorde
Ctrl + Barra espaciadora .

PowerShell

Set-PSReadLineKeyHandler -Chord 'Ctrl+Spacebar' -Function MenuComplete

Búsqueda de nombres de teclas y enlaces de


acordes
Los nombres de las teclas del acorde se definen mediante la enumeración
[System.ConsoleKey] . Para obtener más información, consulte la documentación de
System.ConsoleKey. Por ejemplo, el nombre de la tecla 2 de [System.ConsoleKey] es
D2 , mientras que el nombre de la tecla 2 en el teclado numérico es NumPad2 . Puede
usar el método [System.Console]::ReadKey() para buscar el nombre de la tecla que ha
presionado.

PowerShell

[System.Console]::ReadKey()

En la salida siguiente se muestra la información devuelta por el método ReadKey() para


el acorde de teclas Ctrl + 2 .

Output

KeyChar Key Modifiers


------- --- ---------
D2 Control

Para los cmdlets del controlador de teclas de PSReadLine, este acorde se representa
como Ctrl+D2 . En el ejemplo siguiente se enlaza este acorde a una función.

PowerShell

Set-PSReadLineKeyHandler -Chord 'Ctrl+D2' -Function MenuComplete

Puede enlazar varios acordes a una sola función. De forma predeterminada, la función
BackwardDeleteChar está enlazada a dos acordes.

PowerShell

Get-PSReadLineKeyHandler -Chord Backspace, Ctrl+h

Output

Key Function Description


--- -------- -----------
Backspace BackwardDeleteChar Delete the character before the cursor
Ctrl+h BackwardDeleteChar Delete the character before the cursor

7 Nota
El parámetro Chorddistingue mayúsculas de minúsculas. Esto significa que puede
crear enlaces diferentes para Ctrl + X y Ctrl + x .

En Windows, también puede usar el acorde de teclas Alt + ? para mostrar la función
enlazada al siguiente acorde de teclas que escriba. Al escribir Alt + ? , verá el siguiente
aviso:

Output

what-is-key:

Al presionar la tecla Retroceso , obtendrá la siguiente respuesta:

Output

Backspace: BackwardDeleteChar - Delete the character before the cursor

Controladores de teclas en equipos que no son


Windows
Los códigos de teclas generados por el teclado pueden ser diferentes en función del
sistema operativo y la aplicación de terminal que use.

macOS
El teclado Macintosh no tiene una tecla Alt como los sistemas Windows y Linux. En su
lugar, tiene la tecla ⌥ Opción . macOS usa esta tecla de forma diferente a la tecla Alt en
otros sistemas. Sin embargo, puede configurar las aplicaciones de terminal e iTerm2 en
macOS para tratarlas como una tecla Alt .

Configuración de la aplicación de terminal


Abra la ventana Configuración desde la barra de aplicaciones en Terminal.app.
Seleccione Perfiles y elija el perfil que desea configurar. Seleccione la pestaña Teclado
en las opciones de configuración. Debajo de la lista de teclas, seleccione la
configuración Usar Opción como tecla modificadora. Esta configuración permite que la
tecla ⌥ Opción actúe como Alt en la aplicación de terminal.
Configuración de la aplicación iTerm2
Abra la ventana Configuración desde la barra de aplicaciones en iTerm.app. Seleccione
Perfiles y elija el perfil que desea configurar. Seleccione la pestaña Teclas en las
opciones de configuración. Seleccione la opción Esc+ para la configuración Tecla
Opción izquierda y Tecla Opción derecha. Esta configuración permite que la tecla
⌥ Opción actúe como Alt en la aplicación iTerm.
7 Nota

Los pasos exactos pueden variar en función de las versiones de macOS y las
aplicaciones de terminal. Estos ejemplos se capturaron en macOS Ventura 13.2.1 e
iTerm2 v3.4.16.

Linux
En las plataformas Linux, el código de teclas generado puede ser diferente de otros
sistemas. Por ejemplo:

Ctrl + [ tiene la misma función que Escape .

Ctrl + Barra espaciadora genera los códigos de teclas para Ctrl + D2 . Si desea
asignar una función Ctrl + Barra espaciadora , debe usar el acorde Ctrl+D2 .

PowerShell

Set-PSReadLineKeyHandler -Chord 'Ctrl+D2' -Function MenuComplete

Use el método ReadKey() para comprobar los códigos de teclas generados por el
teclado.

Controladores de teclas usados habitualmente


Estos son algunos controladores de teclas usados habitualmente que están enlazados
de forma predeterminada en Windows. Tenga en cuenta que el enlace de teclas puede
ser diferente en plataformas que no son de Windows.

MenuComplete
Complete la entrada seleccionando una opción en un menú de posibles valores de
finalización.

Acorde predeterminado: Ctrl+Spacebar

En el ejemplo siguiente se muestra el menú de posibles finalizaciones para comandos


que comienzan por select .

Output

PS C:\> select<Ctrl+Spacebar>
select Select-Object Select-PSFPropertyValue
Select-Xml
Select-AzContext Select-PSFConfig Select-PSMDBuildProject
Select-AzSubscription Select-PSFObject Select-String

Select-Object

Use las teclas de dirección para seleccionar la finalización que desee. Presione la tecla
ENTRAR para completar la entrada. A medida que avanza por las selecciones, la ayuda
del comando seleccionado se muestra debajo del menú.

ClearScreen
Esta función borra la pantalla de forma similar a los comandos cls o clear .

Acorde predeterminado: Ctrl+l

SelectCommandArgument
Selecciona el siguiente argumento en la línea de comandos.

Acorde predeterminado: Alt+a

Es posible que tenga el comando en el historial que desea volver a ejecutar con valores
de parámetros diferentes. Puede usar el acorde para recorrer cada parámetro y cambiar
el valor según sea necesario.
New-AzVM -ResourceGroupName myRGName -Location eastus -Name myVM

Al presionar Alt + a , se selecciona sucesivamente el siguiente argumento de


parámetro: myRGName , eastus , myVM .

GotoBrace
Mueve el cursor a la llave coincidente.

Acorde predeterminado: Ctrl+]

Esta función mueve el cursor a la llave de cierre que coincide con la llave en la posición
actual del cursor en la línea de comandos. La función funciona para corchetes ( [] ),
llaves ( {} ) y paréntesis ( () ).

DigitArgument
Inicie o acumule un argumento numérico para repetir una pulsación de teclas el número
de veces especificado.

Acorde predeterminado: Alt+0 a través de Alt+9

Por ejemplo, al escribir Alt + 4 + # , se escribe #### en la línea de comandos.

Consulte también
Get-PSReadLineKeyHandler
Set-PSReadLineKeyHandler
Configuración de un tema de color claro
Artículo • 13/04/2023

Los colores predeterminados para PowerShell y PSReadLine se seleccionan para un


terminal de fondo oscuro. Sin embargo, algunos usuarios pueden optar por usar un
fondo claro con texto oscuro. Dado que la mayoría de los colores predeterminados no
establecen el fondo, el uso de colores de primer plano claros en un fondo claro genera
texto ilegible.

PSReadLine permite definir colores para 18 elementos de sintaxis diferentes. Puede ver
la configuración actual con el cmdlet Get-PSReadLineOption .

Output

EditMode : Windows
AddToHistoryHandler :
System.Func`2[System.String,System.Object]
HistoryNoDuplicates : True
HistorySavePath :
C:\Users\user1\AppData\Roaming\Microsoft\Wind...
HistorySaveStyle : SaveIncrementally
HistorySearchCaseSensitive : False
HistorySearchCursorMovesToEnd : False
MaximumHistoryCount : 4096
ContinuationPrompt : >>
ExtraPromptLineCount : 0
PromptText : {> }
BellStyle : Audible
DingDuration : 50
DingTone : 1221
CommandsToValidateScriptBlockArguments : {ForEach-Object, %, Invoke-Command,
icm...}
CommandValidationHandler :
CompletionQueryItems : 100
MaximumKillRingCount : 10
ShowToolTips : True
ViModeIndicator : None
WordDelimiters : ;:,.[]{}()/\|^&*-=+'"-—―
AnsiEscapeTimeout : 100
PredictionSource : HistoryAndPlugin
PredictionViewStyle : InlineView
CommandColor : "`e[93m"
CommentColor : "`e[32m"
ContinuationPromptColor : "`e[37m"
DefaultTokenColor : "`e[37m"
EmphasisColor : "`e[96m"
ErrorColor : "`e[91m"
InlinePredictionColor : "`e[38;5;238m"
KeywordColor : "`e[92m"
ListPredictionColor : "`e[33m"
ListPredictionSelectedColor : "`e[48;5;238m"
MemberColor : "`e[97m"
NumberColor : "`e[97m"
OperatorColor : "`e[90m"
ParameterColor : "`e[90m"
SelectionColor : "`e[30;47m"
StringColor : "`e[36m"
TypeColor : "`e[37m"
VariableColor : "`e[92m"

La configuración de color se almacena como cadenas que contienen secuencias de


escape ANSI que cambian el color en el terminal. Con el cmdlet Set-PSReadLineOption
puede cambiar los colores a valores que funcionan mejor para un fondo de color claro.

Definición de colores para un tema claro


El ISE de PowerShell se puede configurar para usar un tema claro para los paneles de
editor y consola. También puede ver y cambiar los colores que usa el ISE para diversos
tipos de sintaxis y salida. Puede usar estas opciones de color para definir un tema similar
para PSReadLine.

La siguiente tabla hash define colores para PSReadLine que imitan los colores del ISE de
PowerShell.

PowerShell

$ISETheme = @{
Command = $PSStyle.Foreground.FromRGB(0x0000FF)
Comment = $PSStyle.Foreground.FromRGB(0x006400)
ContinuationPrompt = $PSStyle.Foreground.FromRGB(0x0000FF)
Default = $PSStyle.Foreground.FromRGB(0x0000FF)
Emphasis = $PSStyle.Foreground.FromRGB(0x287BF0)
Error = $PSStyle.Foreground.FromRGB(0xE50000)
InlinePrediction = $PSStyle.Foreground.FromRGB(0x93A1A1)
Keyword = $PSStyle.Foreground.FromRGB(0x00008b)
ListPrediction = $PSStyle.Foreground.FromRGB(0x06DE00)
Member = $PSStyle.Foreground.FromRGB(0x000000)
Number = $PSStyle.Foreground.FromRGB(0x800080)
Operator = $PSStyle.Foreground.FromRGB(0x757575)
Parameter = $PSStyle.Foreground.FromRGB(0x000080)
String = $PSStyle.Foreground.FromRGB(0x8b0000)
Type = $PSStyle.Foreground.FromRGB(0x008080)
Variable = $PSStyle.Foreground.FromRGB(0xff4500)
ListPredictionSelected = $PSStyle.Background.FromRGB(0x93A1A1)
Selection = $PSStyle.Background.FromRGB(0x00BFFF)
}
7 Nota

En PowerShell 7.2 y versiones posteriores, puede usar el método FromRGB() de


$PSStyle para crear las secuencias de escape ANSI para los colores que desee.

Para más información sobre $PSStyle , consulte Acerca de los terminales ANSI.

Para obtener más información sobre las secuencias de escape ANSI, consulte el
artículo sobre el código de escape ANSI en Wikipedia.

Establecimiento del tema de color en el perfil


Para tener la configuración de color que desee en cada sesión de PowerShell, debe
agregar las opciones de configuración al script de perfil de PowerShell. Para obtener un
ejemplo, consulte Personalización del entorno de shell.

Agregue la variable $ISETheme y el siguiente comando Set-PSReadLineOption al perfil.

PowerShell

Set-PSReadLineOption -Colors $ISETheme

A partir de PowerShell 7.2, PowerShell agrega una representación con colores a la


experiencia de consola predeterminada. Los colores empleados se definen en la variable
$PSStyle y están diseñados para un fondo oscuro. La siguiente configuración se ajusta
mejor a un terminal con fondo claro.

PowerShell

$PSStyle.Formatting.FormatAccent = "`e[32m"
$PSStyle.Formatting.TableHeader = "`e[32m"
$PSStyle.Formatting.ErrorAccent = "`e[36m"
$PSStyle.Formatting.Error = "`e[31m"
$PSStyle.Formatting.Warning = "`e[33m"
$PSStyle.Formatting.Verbose = "`e[33m"
$PSStyle.Formatting.Debug = "`e[33m"
$PSStyle.Progress.Style = "`e[33m"
$PSStyle.FileInfo.Directory =
$PSStyle.Background.FromRgb(0x2f6aff) +
$PSStyle.Foreground.BrightWhite
$PSStyle.FileInfo.SymbolicLink = "`e[36m"
$PSStyle.FileInfo.Executable = "`e[95m"
$PSStyle.FileInfo.Extension['.ps1'] = "`e[36m"
$PSStyle.FileInfo.Extension['.ps1xml'] = "`e[36m"
$PSStyle.FileInfo.Extension['.psd1'] = "`e[36m"
$PSStyle.FileInfo.Extension['.psm1'] = "`e[36m"

Elección de colores para accesibilidad


Es posible que el tema de color de ISE no funcione para los usuarios con daltonismo u
otras condiciones que limiten su capacidad de ver los colores.

World Wide Web Consortium (W3C) tiene recomendaciones para usar colores para la
accesibilidad. Las directrices de accesibilidad de contenido web (WCAG) 2.1
recomiendan que "la presentación visual de texto e imágenes de texto tenga una
relación de contraste de al menos 4.5:1". Para obtener más información, vea Criterio de
éxito 1.4.3 Contraste (mínimo) .

El sitio web Relación de contraste proporciona una herramienta que le permite elegir
colores de primer plano y de fondo y medir el contraste. Puede usar esta herramienta
para buscar combinaciones de colores que funcionen mejor en su caso.
Artículos de profundización
Artículo • 13/04/2023

Los artículos de esta sección están diseñados para profundizar en los temas de
PowerShell. Estos artículos no reemplazan a los artículos de referencia, pero
proporcionan diversos ejemplos, ilustran casos perimetrales y avisan de dificultades y
errores comunes.

En esta colección también se presentan las contribuciones de la comunidad. El conjunto


de artículos inaugurales proceden de @KevinMarquette y se publicaron originalmente
en PowerShellExplained.com .

Modo de contribuir al contenido


Si le interesa contribuir al contenido de esta colección, lea la guía del colaborador .
Cuando esté preparado para proponer una contribución, envíe una incidencia en el
repositorio de GitHub con la plantilla Document Idea e incluya un vínculo al
contenido existente que desee compartir.
Todo lo que le interesa sobre las
matrices
Artículo • 13/04/2023

Las matrices son una característica de lenguaje fundamental de la mayoría de los


lenguajes de programación. Son una colección de valores u objetos que son difíciles de
evitar. Vamos a profundizar en las matrices y en todo lo que tienen que ofrecer.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

¿Qué es una matriz?


Voy a empezar con una descripción técnica básica sobre qué son las matrices y cómo se
usan en la mayoría de los lenguajes de programación antes de pasar a las otras formas
en que PowerShell las usa.

Una matriz es una estructura de datos que actúa como una colección de varios
elementos. Puede iterar por la matriz o acceder a elementos individuales mediante un
índice. La matriz se crea como un fragmento secuencial de memoria donde cada valor
se almacena justo al lado del otro.

Hablaré sobre cada uno de los detalles a medida que avanzamos.

Uso básico
Dado que las matrices son una característica básica de PowerShell, existe una sintaxis
sencilla para trabajar con ellas en PowerShell.

Creación de una matriz


Se puede crear una matriz vacía mediante @() .

PowerShell
PS> $data = @()
PS> $data.count
0

Podemos crear una matriz e inicializarla con valores, con tan solo colocarlos dentro del
paréntesis @() .

PowerShell

PS> $data = @('Zero','One','Two','Three')


PS> $data.count
4

PS> $data
Zero
One
Two
Three

Esta matriz tiene cuatro elementos. Cuando llamamos a la variable $data , vemos la lista
de nuestros elementos. Si es una matriz de cadenas, obtenemos una línea por cadena.

Se puede declarar una matriz en varias líneas. En este caso, la coma es opcional y, en
general, se excluye.

PowerShell

$data = @(
'Zero'
'One'
'Two'
'Three'
)

Prefiero declarar mis matrices en varias líneas de esa forma. No solo es más fácil de leer
cuando tiene varios elementos, sino que también facilita la comparación con versiones
anteriores cuando se usa el control de código fuente.

Otra sintaxis

Normalmente, se entiende que @() es la sintaxis para crear una matriz, pero las listas
separadas por comas funcionan en la mayoría de las ocasiones.

PowerShell
$data = 'Zero','One','Two','Three'

Write-Output para crear matrices


Un pequeño truco que merece la pena mencionar es que puede usar Write-Output para
crear cadenas en la consola rápidamente.

PowerShell

$data = Write-Output Zero One Two Three

Esto resulta útil porque no es necesario colocar comillas alrededor de las cadenas
cuando el parámetro acepta cadenas. Nunca haría esto en un script, pero se puede
hacer en la consola.

Acceso a elementos
Ahora que tiene una matriz con elementos, puede acceder a ellos y actualizarlos.

Offset
Para acceder a elementos individuales, usamos los corchetes [] con un valor de
desplazamiento que comienza en 0. Así es como obtenemos el primer elemento de la
matriz:

PowerShell

PS> $data = 'Zero','One','Two','Three'


PS> $data[0]
Zero

El motivo por el que usamos cero aquí es porque el primer elemento está al principio de
la lista, por lo que usamos un desplazamiento de 0 elementos para acceder a él. Para
llegar al segundo elemento, es necesario usar un desplazamiento de 1 para omitir el
primer elemento.

PowerShell

PS> $data[1]
One
Esto significa que el último elemento está en el desplazamiento 3.

PowerShell

PS> $data[3]
Three

Índice
Ahora puede ver por qué seleccioné esos valores para este ejemplo. He presentado esto
como un desplazamiento porque eso es lo que realmente es, pero a este
desplazamiento se le conoce de forma más común como un índice. Un índice que
comienza en 0 . En el resto de este artículo, utilizaremos el término índice para hacer
referencia al desplazamiento.

Trucos especiales sobre índices


En la mayoría de los lenguajes, solo puede especificar un único número como el índice,
y se obtendrá un solo elemento. PowerShell es mucho más flexible. Puede usar varios
índices a la vez. Al proporcionar una lista de índices, podemos seleccionar varios
elementos.

PowerShell

PS> $data[0,2,3]
Zero
Two
Three

Los elementos se devuelven según el orden de los índices proporcionados. Si duplica un


índice, obtendrá ese elemento las dos veces.

PowerShell

PS> $data[3,0,3]
Three
Zero
Three

Podemos especificar una secuencia de números con el operador .. integrado.

PowerShell
PS> $data[1..3]
One
Two
Three

Esto también funciona en orden inverso.

PowerShell

PS> $data[3..1]
Three
Two
One

Puede usar valores de índice negativos para desplazarse desde el final. Por lo tanto, si
necesita el último elemento de la lista, puede usar -1 .

PowerShell

PS> $data[-1]
Three

Hay que tener cuidado aquí con el operador .. . Las secuencias 0..-1 y -1..0 dan
como resultado los valores 0,-1 y -1,0 . Es fácil ver $data[0..-1] y pensar que
enumeraría todos los elementos si olvida este detalle. $data[0..-1] proporciona el
mismo valor que $data[0,-1] al proporcionar el primer y último elemento de la matriz,
y ninguno de los demás valores. Este es un ejemplo más grande:

PowerShell

PS> $a = 1,2,3,4,5,6,7,8
PS> $a[2..-1]
3
2
1
8

Esto es igual que:

PowerShell

PS> $a[2,1,0,-1]
3
2
1
8

Fuera de los límites


En la mayoría de los lenguajes, si intenta acceder a un índice de un elemento que va
más allá del final de la matriz, obtendría algún tipo de error o una excepción. PowerShell
no devuelve nada de forma silenciosa.

PowerShell

PS> $null -eq $data[9000]


True

No se puede indexar en una matriz NULL

Si la variable es $null e intenta indexarla como una matriz, obtendrá una excepción
System.Management.Automation.RuntimeException con el mensaje Cannot index into a

null array .

PowerShell

PS> $empty = $null


PS> $empty[0]
Error: Cannot index into a null array.

Por lo tanto, asegúrese de que las matrices no son $null antes de intentar acceder a los
elementos que contienen.

Count
Las matrices y otras colecciones tienen una propiedad Count que indica cuántos
elementos hay en la matriz.

PowerShell

PS> $data.count
4

PowerShell 3.0 agregó una propiedad Count a la mayoría de los objetos. Puede tener un
solo objeto y debe proporcionar un recuento de 1 .
PowerShell

PS> $date = Get-Date


PS> $date.count
1

Incluso $null tiene una propiedad Count, salvo que devuelve 0 .

PowerShell

PS> $null.count
0

Hay algunas excepciones aquí que revisaré cuando trate la búsqueda de $null o
matrices vacías más adelante en este artículo.

Errores puntuales

Se crea un error de programación común porque las matrices empiezan en el índice 0.


Los errores puntuales pueden introducirse de dos maneras.

Lo primero sería pensar que desea el segundo elemento y usa un índice de 2 y obtiene
realmente el tercer elemento. O bien, piense que tiene cuatro elementos y desea el
último elemento, por lo que usa el recuento para acceder al último elemento.

PowerShell

$data[ $data.count ]

PowerShell puede permitirle hacer eso y proporcionar exactamente el elemento que


existe en el índice 4: $null . Debe usar $data.count - 1 o -1 , dos parámetros sobre los
que hemos obtenido información anteriormente.

PowerShell

PS> $data[ $data.count - 1 ]


Three

Aquí es donde puede usar el índice -1 para obtener el último elemento.

PowerShell

PS> $data[ -1 ]
Three
Lee Dailey también me dijo que podemos usar $data.GetUpperBound(0) para obtener el
número de índice máximo.

PowerShell

PS> $data.GetUpperBound(0)
3
PS> $data[ $data.GetUpperBound(0) ]
Three

La segunda forma más común es al iterar la lista y no detenerse en el momento


adecuado. Lo revisaré cuando hablemos sobre el uso del bucle for .

Actualización de elementos
Podemos usar el mismo índice para actualizar los elementos existentes en la matriz. Esto
nos proporciona acceso directo para actualizar elementos individuales.

PowerShell

$data[2] = 'dos'
$data[3] = 'tres'

Si se intenta actualizar un elemento que está más allá del último elemento, se obtiene
un error Index was outside the bounds of the array. .

PowerShell

PS> $data[4] = 'four'


Index was outside the bounds of the array.
At line:1 char:1
+ $data[4] = 'four'
+ ~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], IndexOutOfRangeException
+ FullyQualifiedErrorId : System.IndexOutOfRangeException

Revisaré esto más adelante cuando hable sobre cómo aumentar una matriz.

Iteración
En el algún momento, puede que necesite recorrer la lista completa o iterar por ella
para realizar alguna acción en cada elemento de la matriz.
Canalización
Las matrices y la canalización de PowerShell están diseñadas para complementarse. Esta
es una de las formas más sencillas de procesar dichos valores. Al pasar una matriz a una
canalización, cada elemento contenido en la matriz se procesa individualmente.

PowerShell

PS> $data = 'Zero','One','Two','Three'


PS> $data | ForEach-Object {"Item: [$PSItem]"}
Item: [Zero]
Item: [One]
Item: [Two]
Item: [Three]

Si no ha visto $PSItem antes, solo tiene que saber que es lo mismo que $_ . Puede usar
cualquiera de ellos, ya que ambos representan el objeto actual de la canalización.

Bucle forEach

El bucle ForEach funciona bien con las colecciones. Uso de la sintaxis: foreach (
<variable> in <collection> )

PowerShell

foreach ( $node in $data )


{
"Item: [$node]"
}

Método forEach
Tiendo a olvidarme de él, pero funciona bien con operaciones sencillas. PowerShell le
permite llamar a .ForEach() en una colección.

PowerShell

PS> $data.foreach({"Item [$PSItem]"})


Item [Zero]
Item [One]
Item [Two]
Item [Three]
.foreach() adopta un parámetro que es un bloque de script. Puede quitar los

paréntesis y simplemente proporcionar el bloque de script.

PowerShell

$data.foreach{"Item [$PSItem]"}

Se trata de una sintaxis menos conocida, pero funciona exactamente igual. Este método
foreach se agregó en PowerShell 4.0.

Bucle For

El bucle for se usa mucho en muchos de los otros lenguajes, pero no se ve con
frecuencia en PowerShell. Cuando lo vea, suele ser en el contexto de recorrer una matriz.

PowerShell

for ( $index = 0; $index -lt $data.count; $index++)


{
"Item: [{0}]" -f $data[$index]
}

Lo primero que hacemos es inicializar $index en 0 . A continuación, agregamos la


condición de que $index debe ser inferior a $data.count . Por último, se especifica que
cada vez que se cree un bucle, el índice se debe aumentar en 1 . En este caso, $index++
es la forma abreviada de $index = $index + 1 . El operador de formato ( -f ) se usa para
insertar el valor de $data[$index] en la cadena de salida.

Siempre que use un bucle for , preste especial atención a la condición. He usado $index
-lt $data.count aquí. Es fácil obtener una condición algo incorrecta para obtener un
error puntual en la lógica. El uso de $index -le $data.count o $index -lt ($data.count
- 1) siempre suele generar algún error. Esto haría que el resultado procesara
demasiados o muy pocos elementos. Este es el típico error puntual.

Bucle switch
Es fácil pasarlo por alto. Si proporciona una matriz a una instrucción switch, esta
comprueba cada elemento de la matriz.

PowerShell
$data = 'Zero','One','Two','Three'
switch( $data )
{
'One'
{
'Tock'
}
'Three'
{
'Tock'
}
Default
{
'Tick'
}
}

Output

Tick
Tock
Tick
Tock

Hay muchas cosas interesantes que podemos hacer con la instrucción switch. Tengo
otro artículo dedicado a esto.

Todo lo que le interesa sobre la instrucción switch

Actualización de valores

Cuando la matriz es una colección de cadenas o enteros (tipos de valor), puede que a
veces desee actualizar los valores de la matriz a medida que se recorren en bucle. La
mayoría de los bucles anteriores usan una variable en el bucle que contiene una copia
del valor. Si actualiza esa variable, no se actualiza el valor original de la matriz.

La excepción a esa instrucción es el bucle for . Si desea recorrer una matriz y actualizar
los valores que contiene, el bucle for es lo que busca.

PowerShell

for ( $index = 0; $index -lt $data.count; $index++ )


{
$data[$index] = "Item: [{0}]" -f $data[$index]
}
En este ejemplo, se adopta un valor para el índice, se realizan algunos cambios y,
después, se usa ese mismo índice para volver a asignarlo.

Matrices de objetos
Hasta ahora, lo único que hemos colocado en una matriz es un tipo de valor, pero las
matrices también pueden contener objetos.

PowerShell

$data = @(
[pscustomobject]@{FirstName='Kevin';LastName='Marquette'}
[pscustomobject]@{FirstName='John'; LastName='Doe'}
)

Muchos cmdlets devuelven colecciones de objetos como matrices cuando se asignan a


una variable.

PowerShell

$processList = Get-Process

Todas las características básicas de las que ya se ha hablado también se aplican a las
matrices de objetos con algunos detalles que merece la pena destacar.

Acceso a las propiedades


Se puede usar un índice para acceder a un elemento individual de una colección, de la
misma forma que con los tipos de valor.

PowerShell

PS> $data[0]

FirstName LastName
----- ----
Kevin Marquette

Se puede acceder a las propiedades y actualizarlas directamente.

PowerShell

PS> $data[0].FirstName
Kevin

PS> $data[0].FirstName = 'Jay'


PS> $data[0]

FirstName LastName
----- ----
Jay Marquette

Propiedades de las matrices


Normalmente, tendría que enumerar la lista completa de la siguiente forma para
acceder a todas las propiedades:

PowerShell

PS> $data | ForEach-Object {$_.LastName}

Marquette
Doe

También puede usar el cmdlet Select-Object -ExpandProperty .

PowerShell

PS> $data | Select-Object -ExpandProperty LastName

Marquette
Doe

Pero PowerShell nos ofrece la posibilidad de solicitar LastName directamente. PowerShell


realiza la enumeración automáticamente y devuelve una lista limpia.

PowerShell

PS> $data.LastName

Marquette
Doe

Aún así, se realiza la enumeración, pero no vemos la complejidad subyacente.

Filtrado con Where-Object


Aquí es donde Where-Object entra en acción, de tal forma que se permite filtrar y
seleccionar lo que se desee fuera de la matriz en función de las propiedades del objeto.

PowerShell

PS> $data | Where-Object {$_.FirstName -eq 'Kevin'}

FirstName LastName
----- ----
Kevin Marquette

Se puede escribir esa misma consulta para obtener el elemento FirstName que se busca.

PowerShell

$data | Where FirstName -eq Kevin

Where()
Las matrices tienen un método Where() que permite especificar un elemento
scriptblock para el filtro.

PowerShell

$data.Where({$_.FirstName -eq 'Kevin'})

Esta característica se agregó en PowerShell 4.0.

Actualización de objetos en bucles


Con los tipos de valor, la única manera de actualizar la matriz es usar un bucle for,
porque es necesario conocer el índice para reemplazar el valor. Hay más opciones con
objetos porque son tipos de referencia. Este es un ejemplo rápido:

PowerShell

foreach($person in $data)
{
$person.FirstName = 'Kevin'
}

Este bucle recorre todos los objetos de la matriz $data . Dado que los objetos son tipos
de referencia, la variable $person hace referencia al mismo objeto que se encuentra en
la matriz. Por tanto, las actualizaciones de sus propiedades actualizan el original.

Todavía no se puede reemplazar todo el objeto de esta manera. Si se intenta asignar un


nuevo objeto a la variable $person , se actualiza la referencia de variable a otro elemento
que ya no apunta al objeto original de la matriz. Esto no funciona como cabría esperar:

PowerShell

foreach($person in $data)
{
$person = [pscustomobject]@{
FirstName='Kevin'
LastName='Marquette'
}
}

Operadores
Los operadores de PowerShell también sirven para las matrices. Algunos de ellos
funcionan de manera ligeramente diferente.

-join
El operador -join es el más obvio, por lo que vamos a profundizar en él primero. Me
gusta el operador -join y lo uso con frecuencia. Combina todos los elementos de la
matriz con el carácter o la cadena que se especifique.

PowerShell

PS> $data = @(1,2,3,4)


PS> $data -join '-'
1-2-3-4
PS> $data -join ','
1,2,3,4

Una de las características que me gustan del operador -join es que controla elementos
individuales.

PowerShell

PS> 1 -join '-'


1

Lo utilizo dentro de registros y mensajes detallados.


PowerShell

PS> $data = @(1,2,3,4)


PS> "Data is $($data -join ',')."
Data is 1,2,3,4.

-join $array
Este es un truco inteligente que Lee Dailey me indicó. Si alguna vez se desea combinar
todo sin un delimitador, en lugar de hacer esto:

PowerShell

PS> $data = @(1,2,3,4)


PS> $data -join $null
1234

Se puede usar -join con la matriz como parámetro sin prefijo. Eche un vistazo a este
ejemplo para saber de qué estoy hablando.

PowerShell

PS> $data = @(1,2,3,4)


PS> -join $data
1234

-replace y -split
Los otros operadores, como -replace y -split , se ejecutan en cada elemento de la
matriz. No puedo decir que siempre lo he utilizado de esta forma, pero aquí se muestra
un ejemplo.

PowerShell

PS> $data = @('ATX-SQL-01','ATX-SQL-02','ATX-SQL-03')


PS> $data -replace 'ATX','LAX'
LAX-SQL-01
LAX-SQL-02
LAX-SQL-03

-contains
El operador -contains permite comprobar una matriz de valores para ver si contiene un
valor especificado.

PowerShell

PS> $data = @('red','green','blue')


PS> $data -contains 'green'
True

-in
Si tiene un valor único que le gustaría comprobar si coincide con alguno de varios
valores, puede usar el operador -in . El valor se encontraría a la izquierda y la matriz en
el lado derecho del operador.

PowerShell

PS> $data = @('red','green','blue')


PS> 'green' -in $data
True

Esto puede resultar complicado si la lista es grande. A menudo, utilizo un patrón regex
si voy a comprobar más de unos pocos valores.

PowerShell

PS> $data = @('red','green','blue')


PS> $pattern = "^({0})$" -f ($data -join '|')
PS> $pattern
^(red|green|blue)$

PS> 'green' -match $pattern


True

-eq y -ne
La igualdad con las matrices puede resultar complicada. Cuando la matriz está en el
lado izquierdo, se compara cada elemento. En lugar de devolver True , se devuelve el
objeto con el que existe una coincidencia.

PowerShell

PS> $data = @('red','green','blue')


PS> $data -eq 'green'
green

Cuando se usa el operador -ne , se obtienen todos los valores que no son iguales a
nuestro valor.

PowerShell

PS> $data = @('red','green','blue')


PS> $data -ne 'green'
red
blue

Cuando se usa esto en una instrucción if() , el valor devuelto es True . Si no se


devuelve ningún valor, se trata de un valor False . En ambos casos, las instrucciones
siguientes se evalúan como True .

PowerShell

$data = @('red','green','blue')
if ( $data -eq 'green' )
{
'Green was found'
}
if ( $data -ne 'green' )
{
'And green was not found'
}

Examinaré esto cuando hablemos de las pruebas de $null .

-match
El operador -match intenta coincidir con cada elemento de la colección.

PowerShell

PS> $servers = @(
'LAX-SQL-01'
'LAX-API-01'
'ATX-SQL-01'
'ATX-API-01'
)
PS> $servers -match 'SQL'
LAX-SQL-01
ATX-SQL-01
Cuando se usa -match con un solo valor, una variable especial $Matches se rellena con
información de coincidencia. Esto no sucede cuando una matriz se procesa de esta
manera.

Se puede adoptar el mismo enfoque con Select-String .

PowerShell

$servers | Select-String SQL

Vamos a profundizar más sobre Select-String , -match y la variable $matches en otra


publicación titulada Las distintas formas de usar regex .

$null o valores vacíos


La prueba de $null o de matrices vacías puede resultar complicada. Estas son las
excepciones comunes con las matrices.

A primera vista, parece que esta instrucción debería funcionar.

PowerShell

if ( $array -eq $null)


{
'Array is $null'
}

Sin embargo, acabo de observar cómo -eq comprueba cada elemento de la matriz. Por
tanto, puede haber una matriz de varios elementos con un solo valor $null, que se
evaluaría como $true

PowerShell

$array = @('one',$null,'three')
if ( $array -eq $null)
{
'I think Array is $null, but I would be wrong'
}

Esta es la razón por la que se recomienda colocar $null a la izquierda del operador.
Esto hace que este escenario no plantee problemas.

PowerShell
if ( $null -eq $array )
{
'Array actually is $null'
}

Una matriz $null no es lo mismo que una matriz vacía. Si se sabe que existe una matriz,
compruebe el número de objetos que contiene. Si la matriz es $null , el recuento es 0 .

PowerShell

if ( $array.count -gt 0 )
{
"Array isn't empty"
}

Hay otra excepción que hay que tener en cuenta aquí. Se puede usar count incluso si
tiene un solo objeto, a menos que ese objeto sea PSCustomObject . Se trata de un error
que se corrigió en PowerShell 6.1. Es algo positivo, pero hay muchas personas que aún
usan la versión 5.1 y, por tanto, es necesario tenerlo en cuenta.

PowerShell

PS> $object = [PSCustomObject]@{Name='TestObject'}


PS> $object.count
$null

Si todavía usa PowerShell 5.1, puede encapsular el objeto en una matriz antes de
comprobar el recuento para obtener un número preciso.

PowerShell

if ( @($array).count -gt 0 )
{
"Array isn't empty"
}

Para hacerlo con seguridad, compruebe $null y, después, el recuento.

PowerShell

if ( $null -ne $array -and @($array).count -gt 0 )


{
"Array isn't empty"
}
All -eq
Recientemente observé que alguien preguntó cómo comprobar que todos los valores
de una matriz coinciden con un valor determinado . El usuario de Reddit /u/bis tenía
esta solución inteligente que comprueba si hay valores incorrectos y, después, cambia
el resultado.

PowerShell

$results = Test-Something
if ( -not ( $results -ne 'Passed') )
{
'All results a Passed'
}

Adición a matrices
Llegados a este punto, se empieza a preguntar cómo agregar elementos a una matriz.
La respuesta rápida es que no se puede. Una matriz tiene un tamaño de memoria fijo. Si
necesita aumentarlo o agregar un solo elemento a ella, se debe crear una matriz y
copiar todos los valores de la matriz anterior. Esto suena trabajoso, pero PowerShell
elimina la complejidad de crear la matriz. PowerShell implementa el operador de suma
( + ) para las matrices.

7 Nota

PowerShell no implementa una operación de resta. Si quiere una alternativa flexible


a una matriz, debe usar un objeto List genérico.

Adición de matrices
Se puede usar el operador de suma con matrices para crear una matriz. Por lo tanto,
dadas estas dos matrices:

PowerShell

$first = @(
'Zero'
'One'
)
$second = @(
'Two'
'Three'
)

Se pueden agregar juntas para obtener una nueva matriz.

PowerShell

PS> $first + $second

Zero
One
Two
Three

Signos más e igual (+=)


Se puede crear una matriz en contexto y agregarle un elemento similar al siguiente:

PowerShell

$data = @(
'Zero'
'One'
'Two'
'Three'
)
$data += 'four'

Recuerde que cada vez que se use += , se duplica y crea una matriz. Esto no es un
problema para los conjuntos de datos pequeños, pero el escalado es muy deficiente.

Asignación de canalización
Se pueden asignar los resultados de cualquier canalización en una variable. Se trata de
una matriz si contiene varios elementos.

PowerShell

$array = 1..5 | ForEach-Object {


"ATX-SQL-$PSItem"
}

Normalmente, al pensar en el uso de la canalización, viene a la mente la típica


integración de PowerShell. Se puede utilizar la canalización con instrucciones foreach()
y otros bucles. Por lo tanto, en lugar de agregar elementos a una matriz en un bucle, se
pueden colocar elementos en la canalización.

PowerShell

$array = foreach ( $node in (1..5))


{
"ATX-SQL-$node"
}

Tipos de matriz
De forma predeterminada, una matriz de PowerShell se crea como un tipo
[PSObject[]] . Esto permite que contenga cualquier tipo de objeto o valor. Esto funciona

porque todo se hereda del tipo PSObject .

Matrices fuertemente tipadas


Se puede crear una matriz de cualquier tipo con una sintaxis similar. Cuando se crea una
matriz fuertemente tipada, solo puede contener valores u objetos del tipo especificado.

PowerShell

PS> [int[]] $numbers = 1,2,3


PS> [int[]] $numbers2 = 'one','two','three'
ERROR: Cannot convert value "one" to type "System.Int32". Input string was
not in a correct format."

PS> [string[]] $strings = 'one','two','three'

ArrayList
Agregar elementos a una matriz es una de sus mayores limitaciones, pero hay algunas
otras colecciones que se pueden usar para solucionar este problema.

ArrayList suele ser una de las primeras soluciones a las que se recurre cuando se

necesita una matriz con la que se pueda trabajar más rápido. Actúa como una matriz de
objetos cada vez que se necesita, pero puede agregar los elementos con rapidez.

Aquí se muestra cómo se crea un elemento ArrayList y cómo se le agregan elementos.

PowerShell
$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value')

Se recurre a .NET para obtener este tipo. En este caso, se usa el constructor
predeterminado para crearlo. A continuación, se llama al método Add para agregarle un
elemento.

La razón por la que uso [void] al principio de la línea es para suprimir el código de
retorno. Algunas llamadas a .NET permiten hacer esto y pueden crear resultados
inesperados.

Si los únicos datos que hay en la matriz son cadenas, eche un vistazo al uso de
StringBuilder . Es prácticamente lo mismo, pero tiene algunos métodos que solo se
utilizan para tratar cadenas. StringBuilder está diseñado especialmente para el
rendimiento.

Es habitual que las personas pasen a ArrayList desde las matrices. Pero esto pertenece
a una época en la que C# no contaba con compatibilidad genérica. La compatibilidad de
ArrayList con el elemento List[] genérico ha quedado en desuso.

Lista genérica
Un tipo genérico es un tipo especial de C# que define una clase generalizada, y el
usuario especifica los tipos de datos que usa cuando se crea. Por lo tanto, si se desea
una lista de números o cadenas, hay que especificar que se desea una lista de tipos int
o string .

Aquí se muestra cómo crear una lista de cadenas.

PowerShell

$mylist = [System.Collections.Generic.List[string]]::new()

También podría ser una lista de números.

PowerShell

$mylist = [System.Collections.Generic.List[int]]::new()

Se puede convertir una matriz existente en una lista como esta sin crear primero el
objeto:
PowerShell

$mylist = [System.Collections.Generic.List[int]]@(1,2,3)

Se puede acortar la sintaxis con la instrucción using namespace en PowerShell 5 y


versiones posteriores. La instrucción using debe ser la primera línea del script. Al
declarar un espacio de nombres, PowerShell permite dejarlo fuera de los tipos de datos
cuando se hace referencia a ellos.

PowerShell

using namespace System.Collections.Generic


$myList = [List[int]]@(1,2,3)

Esto hace que List sea mucho más fácil de usar.

Tiene un método Add similar a su disposición. A diferencia de ArrayList, no hay ningún


valor devuelto en el método Add , por lo que no tenemos que aplicarle el elemento
void .

PowerShell

$myList.Add(10)

De esta forma, aún se puede acceder a los elementos como otras matrices.

PowerShell

PS> $myList[-1]
10

List[PSObject]
Puede haber una lista de cualquier tipo, pero cuando no se conozca el tipo de objetos,
se puede usar [List[PSObject]] para contenerlos.

PowerShell

$list = [List[PSObject]]::new()

Remove()
ArrayList y el elemento List[] genérico admiten la eliminación de elementos de la

colección.

PowerShell

using namespace System.Collections.Generic


$myList = [List[string]]@('Zero','One','Two','Three')
[void]$myList.Remove("Two")
Zero
One
Three

Cuando se trabaja con tipos de valor, se quita el primero de la lista. Puede llamarlo una
y otra vez para seguir quitando ese valor. Si se tienen tipos de referencia, se debe
proporcionar el objeto que se desea quitar.

PowerShell

[list[System.Management.Automation.PSDriveInfo]]$drives = Get-PSDrive
$drives.remove($drives[2])

PowerShell

$delete = $drives[2]
$drives.remove($delete)

El método Remove devuelve true si pudo encontrar y quitar el elemento de la


colección.

Más colecciones
Hay muchas otras colecciones que se pueden usar, pero estas son las sustituciones de
matrices genéricas adecuadas. Si le interesa obtener más información sobre estas
opciones, eche un vistazo a este gist que Mark Kraus ha organizado.

Otros matices
Ahora que he tratado toda la funcionalidad principal, aquí hay algunas cuestiones más
que quería mencionar antes de terminar.

Matrices con un tamaño establecido previamente


He mencionado que no se puede cambiar el tamaño de una matriz una vez creada. Se
puede crear una matriz de un tamaño determinado previamente si se le llama con el
constructor new($size) .

PowerShell

$data = [Object[]]::new(4)
$data.count
4

Multiplicación de matrices
Un truquito interesante es que se puede multiplicar una matriz por un entero.

PowerShell

PS> $data = @('red','green','blue')


PS> $data * 3
red
green
blue
red
green
blue
red
green
blue

Inicialización con 0
Un escenario común es la intención de crear una matriz que contenga solo ceros. Si solo
va a haber enteros, una matriz fuertemente tipada de enteros, de forma
predeterminada, solo contendrá ceros.

PowerShell

PS> [int[]]::new(4)
0
0
0
0

Se puede utilizar el truco de la multiplicación para hacer esto.

PowerShell
PS> $data = @(0) * 4
PS> $data
0
0
0
0

Lo bueno del truco de la multiplicación es que se puede usar cualquier valor. Por lo
tanto, si se prefiere tener 255 como valor predeterminado, sería una buena forma de
hacerlo.

PowerShell

PS> $data = @(255) * 4


PS> $data
255
255
255
255

Matrices anidadas
Una matriz dentro de una matriz se denomina matriz anidada. No la utilizo mucho en
PowerShell, pero sí la he usado más en otros lenguajes. Considere la posibilidad de usar
una matriz de matrices cuando los datos se ajusten a un patrón tipo cuadrícula.

A continuación, se muestran dos formas de crear una matriz bidimensional.

PowerShell

$data = @(@(1,2,3),@(4,5,6),@(7,8,9))

$data2 = @(
@(1,2,3),
@(4,5,6),
@(7,8,9)
)

La coma es muy importante en esos ejemplos. Proporcioné un ejemplo anterior de una


matriz normal en varias líneas donde la coma era opcional. Esto no sucede con una
matriz multidimensional.

La forma en que se usa la notación de índice cambia ligeramente ahora que hay una
matriz anidada. Con el elemento $data anterior, esta es la forma en que se accedería al
valor 3.
PowerShell

PS> $outside = 0
PS> $inside = 2
PS> $data[$outside][$inside]
3

Agregue un par de corchetes para cada nivel de anidamiento de matriz. El primer par de
corchetes es para la matriz más externa y, después, empiece a trabajar a partir de ahí.

Write-Output -NoEnumerate
En PowerShell, se suelen desajustar o enumerar las matrices. Este es un aspecto
fundamental de la forma en que PowerShell usa la canalización, pero hay ocasiones en
las que no se desea que esto sea así.

Normalmente, los objetos se canalizan hacia Get-Member para obtener más información
sobre ellos. Al canalizar una matriz hacia ahí, se desajusta, y Get-Member ve los
miembros de la matriz y no la matriz real.

PowerShell

PS> $data = @('red','green','blue')


PS> $data | Get-Member
TypeName: System.String
...

Para evitar que se desajuste la matriz, se puede usar Write-Output -NoEnumerate .

PowerShell

PS> Write-Output -NoEnumerate $data | Get-Member


TypeName: System.Object[]
...

Existe una segunda forma que es más que un truco, y trato de evitar trucos como este.
Se puede colocar una coma delante de la matriz antes de canalizarla. Esto encapsula a
$data en otra matriz donde es el único elemento, por lo que después de desencapsular
la matriz externa, $data se vuelve a desencapsular.

PowerShell

PS> ,$data | Get-Member


TypeName: System.Object[]
...
Devolución de una matriz
Este desajuste de matrices también se produce cuando se generan o se devuelven
valores a partir de una función. También se puede obtener una matriz si se asigna la
salida a una variable, por lo que esto no suele ser un problema.

El problema es que hay una nueva matriz. Si surge algún problema, puede usar Write-
Output -NoEnumerate $array o return ,$array para solucionarlo.

¿Algo más?
Sé que esto es mucho para asimilar. Espero que aprenda algo de este artículo cada vez
que lo lea y que se convierta en una buena referencia a la que recurrir a largo plazo. Si
le ha resultado útil, compártalo con otras personas a las que crea que puede servir.

Ahora, recomendaría consultar una publicación similar que escribí sobre las tablas hash.
Todo lo que quería saber sobre las
tablas hash
Artículo • 25/06/2023

Quiero volver atrás y hablar sobre las tablas hash. Yo ahora las uso continuamente.
Mientras se las explicaba a alguien después de nuestra reunión de grupo de usuarios la
pasada noche, me di cuenta de que ambos estábamos igual de confundidos. Las tablas
hash son realmente importantes en PowerShell, por lo que es conveniente entenderlas
bien.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

Las tablas hash como una colección de cosas


Quiero considerar primero una tabla hash como una colección en la definición
tradicional de una tabla hash. Esta definición proporciona una comprensión
fundamental de cómo funcionan cuando se usen luego para operaciones más
avanzadas. Omitir esta comprensión suele ser fuente de confusión.

¿Qué es una matriz?


Antes de pasar a lo que es una tabla hash, es necesario mencionar primero las matrices.
Para los fines de este análisis, una matriz es una lista o colección de valores u objetos.

PowerShell

$array = @(1,2,3,5,7,11)

Una vez que tenga los elementos en una matriz, puede usar foreach para recorrer en
iteración la lista o utilizar un índice para acceder a elementos de la matriz.

PowerShell

foreach($item in $array)
{
Write-Output $item
}

Write-Output $array[3]

También puede actualizar los valores mediante un índice de la misma manera.

PowerShell

$array[2] = 13

Aunque hemos tratado las matrices muy por encima, ya están en el contexto adecuado
para hablar de las tablas hash.

¿Qué es una tabla hash?


Voy a empezar con una descripción técnica básica de lo que son las tablas hash, en el
sentido general, antes de pasar a las otras formas en que las usa PowerShell.

Una tabla hash es una estructura de datos, en gran medida como una matriz, excepto
que cada valor (objeto) se almacena mediante una clave. Se trata de un almacén básicos
de clave-valor. Primero, se crea una tabla hash vacía.

PowerShell

$ageList = @{}

Observe que se usan llaves, en lugar de paréntesis, para definir una tabla hash. Luego,
se agrega un elemento con una clave similar a la siguiente:

PowerShell

$key = 'Kevin'
$value = 36
$ageList.add( $key, $value )

$ageList.add( 'Alex', 9 )

El nombre de la persona es la clave y su edad es el valor que queremos guardar.

Uso de los corchetes para el acceso


Una vez que agregue los valores a la tabla hash, puede retirarlos con la misma clave (en
lugar de usar un índice numérico como lo haría con una matriz).

PowerShell

$ageList['Kevin']
$ageList['Alex']

Cuando quiero la edad de Kevin, uso su nombre para acceder a ella. También podemos
usar este enfoque para agregar o actualizar valores en la tabla hash. Es igual que usar la
función add() anterior.

PowerShell

$ageList = @{}

$key = 'Kevin'
$value = 36
$ageList[$key] = $value

$ageList['Alex'] = 9

Hay otra sintaxis que se puede usar para acceder a los valores y actualizarlos, que
trataré en una sección posterior. Si llega a PowerShell desde otro lenguaje, estos
ejemplos servirán para saber cómo usaba antes las tablas hash.

Creación de tablas hash con valores


Hasta ahora he creado una tabla hash vacía para explicar estos ejemplos. Puede rellenar
previamente las claves y los valores al crearlas.

PowerShell

$ageList = @{
Kevin = 36
Alex = 9
}

Como tabla de búsqueda


El valor real de este tipo de una tabla hash es que se puede usar como una tabla de
búsqueda. A continuación se muestra un ejemplo sencillo.

PowerShell
$environments = @{
Prod = 'SrvProd05'
QA = 'SrvQA02'
Dev = 'SrvDev12'
}

$server = $environments[$env]

En este ejemplo, se especifica un entorno para la variable $env y se seleccionará el


servidor correcto. Aunque puede usar un elemento switch($env){...} para una
selección como esta, una tabla hash es una buena opción.

Incluso es aún mejor cuando se crea dinámicamente la tabla de búsqueda para usarla
más adelante. Por lo tanto, piense en usar este enfoque cuando necesite hacer
referencia cruzada de algo. Creo que esto lo veríamos incluso mejor si PowerShell no
fuera tan bueno en filtrar por la canalización con Where-Object . Si alguna vez se
encuentra en una situación en la que el rendimiento es importante, es necesario tener
en cuenta este enfoque.

No diría que es más rápido, pero encaja en la regla de si el rendimiento importa,


pruébelo .

Selección múltiple

Por lo general, se considera que una tabla hash es un par clave-valor, donde se
proporciona una clave y se obtiene un valor. PowerShell le permite proporcionar una
matriz de claves para obtener varios valores.

PowerShell

$environments[@('QA','DEV')]
$environments[('QA','DEV')]
$environments['QA','DEV']

En este ejemplo, uso la misma tabla hash de búsqueda de antes y proporciono tres
estilos de matriz diferentes para obtener las coincidencias. Este es un tesoro oculto de
PowerShell que la mayoría de la gente desconoce.

Iteración de tablas hash


Dado que una tabla hash es una colección de pares clave-valor, se recorre en iteración
de manera diferente a una matriz o una lista normal de elementos.
Lo primero que hay que tener en cuenta es que, si canaliza la tabla hash, la canalización
la trata como un objeto,

PowerShell

PS> $ageList | Measure-Object


count : 1

aunque la propiedad .count indica el número de valores que contiene.

PowerShell

PS> $ageList.count
2

Para solucionar este problema, use la propiedad .values si todo lo que necesita son
solo los valores.

PowerShell

PS> $ageList.values | Measure-Object -Average


Count : 2
Average : 22.5

A menudo resulta más útil enumerar las claves y usarlas para acceder a los valores.

PowerShell

PS> $ageList.keys | ForEach-Object{


$message = '{0} is {1} years old!' -f $_, $ageList[$_]
Write-Output $message
}
Kevin is 36 years old
Alex is 9 years old

Este es el mismo ejemplo con un bucle foreach(){...} .

PowerShell

foreach($key in $ageList.keys)
{
$message = '{0} is {1} years old' -f $key, $ageList[$key]
Write-Output $message
}
Vamos a recorrer cada clave de la tabla hash y, luego, usarla para acceder al valor. Este
es un patrón común al trabajar con tablas hash como una colección.

GetEnumerator()
Esto nos lleva a GetEnumerator() para recorrer en iteración la tabla hash.

PowerShell

$ageList.GetEnumerator() | ForEach-Object{
$message = '{0} is {1} years old!' -f $_.key, $_.value
Write-Output $message
}

El enumerador le proporciona cada par clave-valor uno detrás de otro. Se diseñó


específicamente para este caso de uso. Agradecerle a Mark Kraus que me haya
recordado esta información.

BadEnumeration
Un detalle importante es que no puede modificar una tabla hash mientras se está
enumerando. Si comenzamos con nuestro ejemplo básico de $environments :

PowerShell

$environments = @{
Prod = 'SrvProd05'
QA = 'SrvQA02'
Dev = 'SrvDev12'
}

Y al intentar establecer cada clave en el mismo valor de servidor se produce un error,

PowerShell

$environments.Keys | ForEach-Object {
$environments[$_] = 'SrvDev03'
}

An error occurred while enumerating through a collection: Collection was


modified;
enumeration operation may not execute.
+ CategoryInfo : InvalidOperation:
tableEnumerator:HashtableEnumerator) [],
RuntimeException
+ FullyQualifiedErrorId : BadEnumeration
la enumeración tampoco funcionará, aunque parezca que sí debería hacerlo:

PowerShell

foreach($key in $environments.keys) {
$environments[$key] = 'SrvDev03'
}

Collection was modified; enumeration operation may not execute.


+ CategoryInfo : OperationStopped: (:) [],
InvalidOperationException
+ FullyQualifiedErrorId : System.InvalidOperationException

El truco para esta situación consiste en clonar las claves antes de realizar la
enumeración.

PowerShell

$environments.Keys.Clone() | ForEach-Object {
$environments[$_] = 'SrvDev03'
}

Tablas hash como una colección de


propiedades
Hasta ahora, el tipo de objetos que colocamos en la tabla hash eran todos del mismo
tipo. Usé edades en todos esos ejemplos y la clave era el nombre de la persona. Esta es
una excelente manera de verlo cuando la colección de objetos tiene un nombre. Otra
forma habitual de usar tablas hash en PowerShell es almacenar una colección de
propiedades donde la clave es el nombre de la propiedad. Desarrollaré esta idea en el
ejemplo siguiente.

Acceso basado en propiedades


El uso del acceso basado en propiedades cambia la dinámica de las tablas hash y cómo
se pueden usar en PowerShell. Este es nuestro ejemplo habitual anterior, pero ahora se
tratan las claves como propiedades.

PowerShell

$ageList = @{}
$ageList.Kevin = 35
$ageList.Alex = 9
Al igual que en los ejemplos anteriores, en este se agregan esas claves si aún no existen
en la tabla hash. En función de cómo defina las claves y de cuáles sean los valores, esta
es una opción un poco rara o que encaja perfectamente. El ejemplo de la lista de edades
ha funcionado muy bien hasta este momento. Ahora necesitamos un nuevo ejemplo
que nos convenza para seguir adelante.

PowerShell

$person = @{
name = 'Kevin'
age = 36
}

Y podemos agregar atributos y acceder a ellos en $person de este modo.

PowerShell

$person.city = 'Austin'
$person.state = 'TX'

De repente, esta tabla hash comienza a parecerse a un objeto y a funcionar como tal.
Todavía es una colección de cosas, por lo que se siguen aplicando todos los ejemplos
anteriores. Simplemente nos aproximamos a ella desde un punto de vista diferente.

Búsqueda de claves y valores


En la mayoría de los casos, solo puede probar el valor con algo parecido a esto:

PowerShell

if( $person.age ){...}

Aunque es sencillo, en mi caso ha sido fuente de numerosos errores porque pasaba por
alto un detalle importante de mi lógica. Comencé a usarlo para probar si existía una
clave. Cuando el valor era $false o cero, esa instrucción devolvía $false de forma
inesperada.

PowerShell

if( $person.age -ne $null ){...}


El problema se soluciona así en el caso de valores cero, pero no para $null con claves no
existentes. La mayoría de las veces no es necesario hacer esa distinción, pero hay
funciones para cuando la haga.

PowerShell

if( $person.ContainsKey('age') ){...}

También tenemos un elemento ContainsValue() para la situación en la que necesita


probar un valor sin conocer la clave o recorrer en iteración toda la colección.

Eliminación y borrado de claves


Puede quitar claves con la función .Remove() .

PowerShell

$person.remove('age')

Al asignarles un valor $null , solo le queda una clave que tiene un valor $null .

Una forma habitual de borrar una tabla hash es simplemente inicializarla en una tabla
hash vacía.

PowerShell

$person = @{}

Aunque esta solución funciona, intente usar mejor la función clear() .

PowerShell

$person.clear()

Este es uno de esos casos en los que el uso de la función crea código de
autodocumentación y hace que las intenciones del código sean muy claras.

La parte divertida

Tablas hash ordenadas


De forma predeterminada, las tablas hash no se ordenan (ni se clasifican). En el contexto
tradicional, el orden no importa cuando siempre se usa una clave para acceder a los
valores. Es posible que quiera que las propiedades permanezcan en el orden definido.
Afortunadamente, hay una manera de hacerlo con la palabra clave ordered .

PowerShell

$person = [ordered]@{
name = 'Kevin'
age = 36
}

Ahora, cuando se enumeran las claves y los valores, permanecen en ese orden.

Tablas hash insertadas


Al definir una tabla hash en una línea, puede separar los pares clave-valor con punto y
coma.

PowerShell

$person = @{ name = 'kevin'; age = 36; }

Esto resultará útil si va a crearlos en la canalización.

Expresiones personalizadas en comandos de canalización


comunes
Hay algunos cmdlets que admiten el uso de tablas hash para crear propiedades
personalizadas o calculadas. Esto se ve normalmente con Select-Object y Format-Table .
Las tablas hash tienen una sintaxis especial parecida a esta cuando se expanden
totalmente.

PowerShell

$property = @{
name = 'totalSpaceGB'
expression = { ($_.used + $_.free) / 1GB }
}

Lo que el cmdlet etiquetaría en esa columna es name . expression es un bloque de script


que se ejecuta cuando $_ es el valor del objeto en la canalización. Aquí se muestra ese
script en acción:
PowerShell

$drives = Get-PSDrive | Where Used


$drives | Select-Object -Property name, $property

Name totalSpaceGB
---- ------------
C 238.472652435303

Lo he colocado en una variable, pero podría definirse fácilmente insertado y puede


acortar name a n y expression a e mientras está en él.

PowerShell

$drives | Select-Object -property name, @{n='totalSpaceGB';e={($_.used +


$_.free) / 1GB}}

Personalmente, no me gusta este enfoque porque hace que los comandos sean largos y
se fomentan comportamientos incorrectos en los que no quiero caer. Probablemente
cree otra tabla hash o un elemento pscustomobject con todos los campos y
propiedades que quiera en lugar de usar este enfoque en los scripts. Sin embargo, hay
mucho código que lo hace, por lo que me gustaría que se supiera. Hablo de crear un
elemento pscustomobject más adelante.

Expresión de ordenación personalizada


Es fácil ordenar una colección si los objetos tienen los datos que quiere ordenar. Puede
agregar los datos al objeto antes de ordenarlos o crear una expresión personalizada
para Sort-Object .

PowerShell

Get-ADUser | Sort-Object -Property @{ e={ Get-TotalSales $_.Name } }

En este ejemplo, se toma una lista de usuarios y se usa algún cmdlet personalizado para
obtener información adicional solo para la ordenación.

Ordenación de una lista de tablas hash

Si tiene una lista de tablas hash que quiere ordenar, verá que Sort-Object no trata las
claves como propiedades. Para solucionarlo, podemos usar una expresión de
ordenación personalizada.
PowerShell

$data = @(
@{name='a'}
@{name='c'}
@{name='e'}
@{name='f'}
@{name='d'}
@{name='b'}
)

$data | Sort-Object -Property @{e={$_.name}}

Expansión de tablas hash en cmdlets


Esta es una de mis cosas favoritas de las tablas hash que muchas personas no
descubren al principio. La idea es que, en lugar de proporcionar todas las propiedades a
un cmdlet en una sola línea, se pueden empaquetar primero en una tabla hash.
Después, se puede asignar la tabla hash a la función de una manera especial. Este es un
ejemplo de cómo crear un ámbito DHCP de la manera normal.

PowerShell

Add-DhcpServerV4Scope -Name 'TestNetwork' -StartRange '10.0.0.2' -EndRange


'10.0.0.254' -SubnetMask '255.255.255.0' -Description 'Network for testlab
A' -LeaseDuration (New-TimeSpan -Days 8) -Type "Both"

Sin usar la expansión, todas esas cosas deben definirse en una sola línea. Se desplazará
fuera de la pantalla o se ajustará cuando sea posible. Ahora compare esto con un
comando que usa expansión.

PowerShell

$DHCPScope = @{
Name = 'TestNetwork'
StartRange = '10.0.0.2'
EndRange = '10.0.0.254'
SubnetMask = '255.255.255.0'
Description = 'Network for testlab A'
LeaseDuration = (New-TimeSpan -Days 8)
Type = "Both"
}
Add-DhcpServerV4Scope @DHCPScope

El uso del signo @ en lugar de $ es lo que invoca la operación de expansión.


Dedique un momento a apreciar lo fácil que es leer ese ejemplo. Son exactamente el
mismo comando con todos los mismos valores. El segundo es más fácil de entender y
mantener con vistas al futuro.

Uso expansión siempre que el comando sea demasiado largo. Cuando digo demasiado
largo, me refiero a que mi ventana se desplace a la derecha. Si llego a tres propiedades
para una función, es probable que las vuelva a escribir con una tabla hash expandida.

Expansión para los parámetros opcionales


Una de las formas más comunes de usar la expansión es tratar con parámetros
opcionales que proceden de alguna parte del script. Supongamos que tengo una
función que contiene una llamada Get-CIMInstance que tiene un argumento
$Credential opcional.

PowerShell

$CIMParams = @{
ClassName = 'Win32_Bios'
ComputerName = $ComputerName
}

if($Credential)
{
$CIMParams.Credential = $Credential
}

Get-CIMInstance @CIMParams

Comenzamos por crear mi tabla hash con parámetros comunes. Después, agrego
$Credential si existe. Dado que estoy usando aquí expansión, solo necesito tener la

llamada a Get-CIMInstance en mi código una vez. Este patrón de diseño es muy limpio y
puede administrar fácilmente muchos parámetros opcionales.

Para ser justos, puede escribir los comandos para permitir parámetros con valores
$null . Lo que ocurre es que no siempre tiene control sobre los demás comandos a los
que llama.

Varias expansiones
Puede expandir varias tablas hash al mismo cmdlet. Si volvemos a examinar nuestro
ejemplo de expansión original:

PowerShell
$Common = @{
SubnetMask = '255.255.255.0'
LeaseDuration = (New-TimeSpan -Days 8)
Type = "Both"
}

$DHCPScope = @{
Name = 'TestNetwork'
StartRange = '10.0.0.2'
EndRange = '10.0.0.254'
Description = 'Network for testlab A'
}

Add-DhcpServerv4Scope @DHCPScope @Common

Usaré este método cuando disponga de un conjunto común de parámetros que voy a
pasar a muchos comandos.

Expansión para limpiar el código


No hay nada malo en expandir un solo parámetro si con ello el código es más limpio.

PowerShell

$log = @{Path = '.\logfile.log'}


Add-Content "logging this command" @log

Expansión de ejecutables
La expansión también funciona en algunos archivos ejecutables que usan una sintaxis
/param:value . Robocopy.exe , por ejemplo, tiene algunos parámetros como este.

PowerShell

$robo = @{R=1;W=1;MT=8}
robocopy source destination @robo

No sé si todo esto es de alguna utilidad, pero creo que es interesante.

Adición de tablas hash


Las tablas hash admiten el operador de suma para combinar dos tablas hash.

PowerShell
$person += @{Zip = '78701'}

Esto solo funciona si las dos tablas hash no comparten una clave.

Tablas hash anidadas


Se pueden usar tablas hash como valores dentro de una tabla hash.

PowerShell

$person = @{
name = 'Kevin'
age = 36
}
$person.location = @{}
$person.location.city = 'Austin'
$person.location.state = 'TX'

Comencé con una tabla hash básica que contenía dos claves. Agregué una clave llamada
location con una tabla hash vacía. Luego, agregué los dos últimos elementos al

elemento location de esa tabla hash. Esto también se puede hacer en línea.

PowerShell

$person = @{
name = 'Kevin'
age = 36
location = @{
city = 'Austin'
state = 'TX'
}
}

Se crea la misma tabla hash que vimos anteriormente y puede acceder a las
propiedades de la misma manera.

PowerShell

$person.location.city
Austin

Hay muchas formas de enfocar la estructura de los objetos. Esta es una segunda manera
de examinar una tabla hash anidada.

PowerShell
$people = @{
Kevin = @{
age = 36
city = 'Austin'
}
Alex = @{
age = 9
city = 'Austin'
}
}

Este escenario mezcla el concepto de usar tablas hash como una colección de objetos y
como una colección de propiedades. Los valores siguen siendo de acceso fácil incluso
cuando están anidados con el enfoque que prefiera.

PowerShell

PS> $people.kevin.age
36
PS> $people.kevin['city']
Austin
PS> $people['Alex'].age
9
PS> $people['Alex']['City']
Austin

Suelo usar la propiedad DOT cuando la trato como una propiedad. Esas son cosas que
por lo general he definido de forma estática en mi código y me las sé de memoria. Si
necesito recorrer la lista o tener acceso mediante programación a las claves, utilizo los
corchetes para proporcionar el nombre de la clave.

PowerShell

foreach($name in $people.keys)
{
$person = $people[$name]
'{0}, age {1}, is in {2}' -f $name, $person.age, $person.city
}

Tener la capacidad de anidar tablas hash le ofrece muchas opciones y flexibilidad.

Vista de las tablas hash anidadas


En cuanto empiece a anidar tablas hash, necesitará una manera fácil de verlas desde la
consola. Si tomo esa última tabla hash, obtengo una salida parecida a esta y solo llega
hasta aquí:
PowerShell

PS> $people
Name Value
---- -----
Kevin {age, city}
Alex {age, city}

Mi comando goto para ver estos aspectos es ConvertTo-JSON porque es muy limpio y,
con frecuencia, uso JSON en otras cosas.

PowerShell

PS> $people | ConvertTo-Json


{
"Kevin": {
"age": 36,
"city": "Austin"
},
"Alex": {
"age": 9,
"city": "Austin"
}
}

Incluso si no conoce JSON, debería poder ver lo que busca. Hay un comando Format-
Custom para datos estructurados como estos, pero aún me gusta más la vista JSON.

Creación de objetos
A veces, solo es necesario tener un objeto, y usar una tabla hash para que contenga
propiedades no es la mejor solución. Lo más habitual es que quiera ver las claves como
nombres de columna. Un elemento pscustomobject facilita este proceso.

PowerShell

$person = [pscustomobject]@{
name = 'Kevin'
age = 36
}

$person

name age
---- ---
Kevin 36
Incluso si no lo crea inicialmente como pscustomobject , siempre puede convertirlo más
adelante cuando sea necesario.

PowerShell

$person = @{
name = 'Kevin'
age = 36
}

[pscustomobject]$person

name age
---- ---
Kevin 36

Ya tengo una reseña detallada de pscustomobject que debería leer después de esta. Se
basa en muchos de los aspectos aprendidos aquí.

Lectura y escritura de tablas hash en un archivo

Guardar en CSV
Esforzarse en obtener una tabla hash para guardarla en un archivo CSV es una de las
dificultades a las que me refiero. Convierta la tabla hash en un elemento pscustomobject
y se guardará correctamente en CSV. Para facilitar las cosas, comience con un elemento
pscustomobject para que se conserve el orden de las columnas. Sin embargo, puede

convertirlo en pscustomobject insertado si es necesario.

PowerShell

$person | ForEach-Object{ [pscustomobject]$_ } | Export-CSV -Path $path

Una vez más, consulte mi reseña sobre el uso de un elemento pscustomobject.

Guardar una tabla hash anidada en un archivo


Si necesito guardar una tabla hash anidada en un archivo y, luego, volver a leerla, uso
los cmdlets JSON para hacerlo.

PowerShell
$people | ConvertTo-JSON | Set-Content -Path $path
$people = Get-Content -Path $path -Raw | ConvertFrom-JSON

Hay dos puntos importantes sobre este método. En primer lugar, el código JSON se
escribe en varias líneas, por lo que es necesario usar la opción -Raw para volver a leerlo
en una sola cadena. La segunda es que el objeto importado ya no es [hashtable] .
Ahora es [pscustomobject] y eso puede producir problemas si no lo espera.

Busque tablas hash profundamente anidadas. Al hacer la conversión a JSON, es posible


que no obtenga los resultados que espera.

PowerShell

@{ a = @{ b = @{ c = @{ d = "e" }}}} | ConvertTo-Json

{
"a": {
"b": {
"c": "System.Collections.Hashtable"
}
}
}

Use el parámetro Profundidad para comprobar que haya expandido todas las tablas
hash anidadas.

PowerShell

@{ a = @{ b = @{ c = @{ d = "e" }}}} | ConvertTo-Json -Depth 3

{
"a": {
"b": {
"c": {
"d": "e"
}
}
}
}

Si necesita que sea [hashtable] al importarlo, debe usar los comandos Export-CliXml y
Import-CliXml .

Conversión de JSON a tabla hash


Si necesita convertir JSON a [hashtable] , hay una forma de hacerlo con
JavaScriptSerializer en .NET.

PowerShell

[Reflection.Assembly]::LoadWithPartialName("System.Web.Script.Serialization"
)
$JSSerializer =
[System.Web.Script.Serialization.JavaScriptSerializer]::new()
$JSSerializer.Deserialize($json,'Hashtable')

A partir de la versión 6 de PowerShell, la compatibilidad con JSON usa NewtonSoft


JSON.NET y agrega compatibilidad con las tablas hash.

PowerShell

'{ "a": "b" }' | ConvertFrom-Json -AsHashtable

Name Value
---- -----
a b

Con PowerShell 6.2, se ha agregado el parámetro Profundidad a ConvertFrom-Json . El


valor predeterminado de Profundidad es 1024.

Lectura directa desde un archivo


Si tiene un archivo que contiene una tabla hash con la sintaxis de PowerShell, hay una
manera de importarlo directamente.

PowerShell

$content = Get-Content -Path $Path -Raw -ErrorAction Stop


$scriptBlock = [scriptblock]::Create( $content )
$scriptBlock.CheckRestrictedLanguage( $allowedCommands, $allowedVariables,
$true )
$hashtable = ( & $scriptBlock )

Se importa el contenido del archivo en un elemento scriptblock y, luego, se asegura de


que no contenga ningún otro comando de PowerShell antes de ejecutarlo.

Dicho lo cual, ¿sabía que un manifiesto de módulo (el archivo psd1) es solo una tabla
hash?
Las claves pueden ser cualquier objeto.
La mayoría de las veces, las claves son simplemente cadenas. Por lo tanto, podemos
incluir comillas alrededor de cualquier cosa y convertirla en una clave.

PowerShell

$person = @{
'full name' = 'Kevin Marquette'
'#' = 3978
}
$person['full name']

Puede hacer cosas raras que no sabía que podía hacer.

PowerShell

$person.'full name'

$key = 'full name'


$person.$key

Sin embargo, solo porque pueda hacerlas, no significa que deba. Eso último se parece a
un error a la espera de que pase, y cualquiera que lea el código podría malinterpretarlo
fácilmente.

Técnicamente, la clave no tiene que ser una cadena, pero es más fácil pensar en ella si
solo usa cadenas. Sin embargo, la indexación no funciona bien con las claves complejas.

PowerShell

$ht = @{ @(1,2,3) = "a" }


$ht

Name Value
---- -----
{1, 2, 3} a

No siempre es posible acceder a un valor de una tabla hash mediante su clave. Por
ejemplo:

PowerShell

$key = $ht.keys[0]
$ht.$($key)
a
$ht[$key]
a

Cuando la clave es una matriz, debe ajustar la variable $key en una subexpresión para
que se pueda usar con la notación de acceso a miembros ( . ). O bien, puede usar la
notación de índice de matriz ( [] ).

Uso en variables automáticas

$PSBoundParameters
$PSBoundParameters es una variable automática que solo existe dentro del contexto
de una función. Contiene todos los parámetros con los que se llamó a la función. No es
exactamente una tabla hash, pero se acerca lo bastante como para tratarla así.

Esto incluye la eliminación de claves y su expansión a otras funciones. Si tiene que


escribir funciones proxy, eche un vistazo más de cerca a esta.

Consulte about_Automatic_Variables para más información.

Problema de PSBoundParameters
Una cuestión importante que hay que recordar es que esta variable solo incluye los
valores que se pasan como parámetros. Si también tiene parámetros con valores
predeterminados, pero no los pasa el autor de la llamada, $PSBoundParameters no
contiene esos valores. Esto se suele pasar por alto.

$PSDefaultParameterValues
Esta variable automática le permite asignar valores predeterminados a cualquier cmdlet
sin cambiarlo. Eche un vistazo a este ejemplo.

PowerShell

$PSDefaultParameterValues["Out-File:Encoding"] = "UTF8"

Se agrega una entrada a la tabla hash $PSDefaultParameterValues que establece UTF8


como valor predeterminado del parámetro Out-File -Encoding . Como es específica de
la sesión, debe colocarla en $profile .
A menudo uso esta solución para asignar previamente valores que escribo con bastante
frecuencia.

PowerShell

$PSDefaultParameterValues[ "Connect-VIServer:Server" ] =
'VCENTER01.contoso.local'

Como también se aceptan caracteres comodines, se pueden definir valores de forma


masiva. Estas son algunas de las formas de uso:

PowerShell

$PSDefaultParameterValues[ "Get-*:Verbose" ] = $true


$PSDefaultParameterValues[ "*:Credential" ] = Get-Credential

Para un desglose más exhaustivo, consulte este excelente artículo sobre valores
predeterminados automáticos de Michael Sorens .

Regex $Matches
Cuando se usa el operador -match , se crea una variable automática llamada $matches
con los resultados de la coincidencia. Si tiene alguna subexpresión en su regex, también
se enumeran las coincidencias secundarias.

PowerShell

$message = 'My SSN is 123-45-6789.'

$message -match 'My SSN is (.+)\.'


$Matches[0]
$Matches[1]

Coincidencias con nombre


Esta es una de mis características favoritas que la mayoría de la gente no conoce. Si usa
una coincidencia regex con nombre, puede acceder a ella por el nombre en las
coincidencias.

PowerShell

$message = 'My Name is Kevin and my SSN is 123-45-6789.'

if($message -match 'My Name is (?<Name>.+) and my SSN is (?<SSN>.+)\.')


{
$Matches.Name
$Matches.SSN
}

En el ejemplo anterior, (?<Name>.*) es una subexpresión con nombre. A continuación,


este valor se coloca en la propiedad $Matches.Name .

Group-Object -AsHashtable
Una característica poco conocida de Group-Object es que puede convertir algunos
conjuntos de datos en una tabla hash.

PowerShell

Import-CSV $Path | Group-Object -AsHashtable -Property email

Cada fila se agrega a una tabla hash y se usa la propiedad especificada como clave para
acceder a ella.

Copia de tablas hash


Una cuestión importante que hay que saber es que las tablas hash son objetos, y cada
variable es simplemente una referencia a un objeto. Esto significa que cuesta más
realizar una copia válida de una tabla hash.

Asignación de tipos de referencia


Cuando tiene una tabla hash y le asigna una segunda variable, ambas variables apuntan
a la misma tabla hash.

PowerShell

PS> $orig = @{name='orig'}


PS> $copy = $orig
PS> $copy.name = 'copy'
PS> 'Copy: [{0}]' -f $copy.name
PS> 'Orig: [{0}]' -f $orig.name

Copy: [copy]
Orig: [copy]
Con ello se resalta que son la misma, dado que al alterar los valores de una también se
alteran los de la otra. Lo mismo se aplica cuando se pasan tablas hash a otras funciones.
Si esas funciones realizan cambios en esa tabla hash, también se modifica su original.

Copias superficiales, de un solo nivel


Si tenemos una tabla hash simple como la de nuestro ejemplo anterior, podemos usar
.Clone() para crear una copia superficial.

PowerShell

PS> $orig = @{name='orig'}


PS> $copy = $orig.Clone()
PS> $copy.name = 'copy'
PS> 'Copy: [{0}]' -f $copy.name
PS> 'Orig: [{0}]' -f $orig.name

Copy: [copy]
Orig: [orig]

Esto nos permite realizar algunos cambios básicos en una que no afecten a la otra.

Copias superficiales, anidadas


La razón por la que se llama copia superficial es que solo copia las propiedades de nivel
base. Si una de esas propiedades es un tipo de referencia (como otra tabla hash), esos
objetos anidados seguirán señalándose entre sí.

PowerShell

PS> $orig = @{
person=@{
name='orig'
}
}
PS> $copy = $orig.Clone()
PS> $copy.person.name = 'copy'
PS> 'Copy: [{0}]' -f $copy.person.name
PS> 'Orig: [{0}]' -f $orig.person.name

Copy: [copy]
Orig: [copy]

Por lo tanto, puede verse que, aunque cloné la tabla hash, no se clonó la referencia a
person . Necesitamos realizar una copia en profundidad para tener realmente una

segunda tabla hash que no esté vinculada a la primera.


Copias en profundidad
Existen un par de formas de crear una copia en profundidad de una tabla hash (y
mantenerla como tabla de este tipo). Esta es una función en la que se usa PowerShell
para crear de forma recursiva una copia en profundidad:

PowerShell

function Get-DeepClone
{
[CmdletBinding()]
param(
$InputObject
)
process
{
if($InputObject -is [hashtable]) {
$clone = @{}
foreach($key in $InputObject.keys)
{
$clone[$key] = Get-DeepClone $InputObject[$key]
}
return $clone
} else {
return $InputObject
}
}
}

No se controla ningún otro tipo de referencia o matriz, pero es un buen punto de


partida.

Otra posibilidad es usar .NET para deserializar la tabla usando CliXml como en esta
función:

PowerShell

function Get-DeepClone
{
param(
$InputObject
)
$TempCliXmlString =
[System.Management.Automation.PSSerializer]::Serialize($obj,
[int32]::MaxValue)
return
[System.Management.Automation.PSSerializer]::Deserialize($TempCliXmlString)
}
En el caso de las tablas hash que son extremadamente grandes, la función de
deserialización es más rápida, ya que escala horizontalmente. Sin embargo, hay algunas
cosas que se deben tener en cuenta a la hora de usar este método: Dado que usa
CliXml, conlleva un uso intensivo de la memoria y, si está clonando tablas hash muy
grandes, eso puede ser un problema. Otra limitación de CliXml es que existe una
limitación de profundidad de 48. Es decir, si tiene una tabla hash con 48 capas de tablas
hash anidadas, la clonación no funcionará, y en la salida no se proporcionará ninguna
tabla hash.

¿Algo más?
Hemos tocado muchos temas rápidamente. Mi esperanza es que le lleven a descubrir
algo nuevo o que los entienda mejor cada vez que lea esto. Dado que he cubierto todo
el espectro de esta característica, hay aspectos que es posible que no se apliquen en su
caso en este momento. Es completamente normal y es lo que se espera según cuánto
trabaje con PowerShell.
Todo lo que le interesa sobre
PSCustomObject
Artículo • 07/06/2023

PSCustomObject es una herramienta excelente para agregar al conjunto de herramientas


de PowerShell. Vamos a empezar por lo básico y, después, nos adentraremos en
características más avanzadas. La idea subyacente al uso de PSCustomObject es tener
una manera sencilla de crear datos estructurados. Eche un vistazo al primer ejemplo y
tendrá una idea más clara de lo que eso significa.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

Creación de un PSCustomObject
Me encanta usar [PSCustomObject] en PowerShell. La creación de un objeto útil nunca
había sido tan fácil. Por eso, voy a omitir todas las demás formas en que se puede crear
un objeto, pero necesito mencionar que la mayoría de estos ejemplos se aplican a
PowerShell 3.0 y versiones posteriores.

PowerShell

$myObject = [PSCustomObject]@{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}

Este método funciona bien porque utilizo tablas hash para casi todo. Sin embargo, hay
ocasiones en las que me gustaría que PowerShell tratara las tablas hash más bien como
un objeto. La primera vez que observa la diferencia es cuando desea utilizar Format-
Table o Export-CSV y se da cuenta de que una tabla hash es simplemente una colección
de pares clave-valor.

Después, puede acceder a los valores y usarlos como lo haría con un objeto normal.

PowerShell
$myObject.Name

Conversión de una tabla hash


Ahora que estoy tratando el tema, ¿sabía que podría hacer lo siguiente?

PowerShell

$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}
$myObject = [pscustomobject]$myHashtable

Me gustaría crear el objeto desde el principio, pero hay ocasiones en las que hay que
trabajar primero con una tabla hash. Este ejemplo funciona porque el constructor
adopta una tabla hash para las propiedades del objeto. Una nota importante es que,
aunque este método funciona, no es un equivalente exacto. La diferencia más
importante es que el orden de las propiedades no se conserva.

Si desea conservar el orden, consulte Tablas hash ordenadas.

Enfoque heredado
Es posible que haya observado que las personas usan New-Object para crear objetos
personalizados.

PowerShell

$myHashtable = @{
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}

$myObject = New-Object -TypeName PSObject -Property $myHashtable

Esta opción es bastante más lenta, pero puede ser la mejor en las primeras versiones de
PowerShell.

Guardar en un archivo
Considero que la mejor manera de guardar una tabla hash en un archivo es con formato
JSON. Puede importarlo de nuevo en un objeto [PSCustomObject] .

PowerShell

$myObject | ConvertTo-Json -depth 1 | Set-Content -Path $Path


$myObject = Get-Content -Path $Path | ConvertFrom-Json

Se abordan más opciones para guardar objetos en un archivo en mi artículo Las


distintas formas de leer y escribir en archivos .

Trabajar con propiedades

Adición de propiedades
También puede agregar nuevas propiedades a PSCustomObject con Add-Member .

PowerShell

$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value


'KevinMarquette'

$myObject.ID

Eliminación de propiedades
También puede quitar propiedades de un objeto.

PowerShell

$myObject.psobject.properties.remove('ID')

.psobject es un miembro intrínseco que proporciona acceso a los metadatos del objeto
base. Para obtener más información sobre miembros intrínsecos, vea
about_Intrinsic_Members.

Enumeración de nombres de propiedad


A veces, se necesita una lista de todos los nombres de propiedad de un objeto.

PowerShell
$myObject | Get-Member -MemberType NoteProperty | Select -ExpandProperty
Name

También podemos obtener esta misma lista de la propiedad psobject .

PowerShell

$myobject.psobject.properties.name

Acceso dinámico a las propiedades


Ya he mencionado que puede acceder a los valores de propiedad directamente.

PowerShell

$myObject.Name

Puede utilizar una cadena para el nombre de la propiedad y, de esta forma, seguirá
funcionando.

PowerShell

$myObject.'Name'

Podemos dar un paso más y usar una variable para el nombre de la propiedad.

PowerShell

$property = 'Name'
$myObject.$property

Sé que parece extraño, pero funciona.

Conversión de PSCustomObject en una tabla hash


Para continuar desde la última sección, puede recorrer dinámicamente las propiedades y
crear una tabla hash a partir de ellas.

PowerShell

$hashtable = @{}
foreach( $property in $myobject.psobject.properties.name )
{
$hashtable[$property] = $myObject.$property
}

Pruebas de propiedades
Si necesita saber si existe una propiedad, puede simplemente comprobar si esa
propiedad tiene un valor.

PowerShell

if( $null -ne $myObject.ID )

Sin embargo, si el valor pudiese ser $null , podría comprobar si existe buscándolo en
psobject.properties .

PowerShell

if( $myobject.psobject.properties.match('ID').Count )

Adición de métodos a objetos


Si necesita agregar un método de script a un objeto, puede hacerlo con Add-Member y
ScriptBlock . Tiene que utilizar la referencia automática de variable this al objeto

actual. A continuación, se muestra un elemento scriptblock para convertir un objeto en


una tabla hash. (El mismo código forma el último ejemplo).

PowerShell

$ScriptBlock = {
$hashtable = @{}
foreach( $property in $this.psobject.properties.name )
{
$hashtable[$property] = $this.$property
}
return $hashtable
}

Después, lo agregamos al objeto como una propiedad de script.

PowerShell
$memberParam = @{
MemberType = "ScriptMethod"
InputObject = $myobject
Name = "ToHashtable"
Value = $scriptBlock
}
Add-Member @memberParam

Después, se puede llamar a la función de la siguiente manera:

PowerShell

$myObject.ToHashtable()

Objetos frente a tipos de valor


Los objetos y los tipos de valor no controlan las asignaciones de variables de la misma
manera. Si asigna tipos de valor entre sí, solo el valor se copia en la nueva variable.

PowerShell

$first = 1
$second = $first
$second = 2

En este caso, $first es 1 y $second es 2.

Las variables de objeto contienen una referencia al objeto real. Cuando se asigna un
objeto a una nueva variable, siguen haciendo referencia al mismo objeto.

PowerShell

$third = [PSCustomObject]@{Key=3}
$fourth = $third
$fourth.Key = 4

Dado que $third y $fourth hacen referencia a la misma instancia de un objeto, tanto
$third.key como $fourth.Key son 4.

psobject.copy()
Si necesita una copia verdadera de un objeto, puede clonarlo.
PowerShell

$third = [PSCustomObject]@{Key=3}
$fourth = $third.psobject.copy()
$fourth.Key = 4

La clonación crea una copia superficial del objeto. Tienen instancias diferentes ahora, y
$third.key es 3 y $fourth.Key es 4 en este ejemplo.

Yo lo denomino copia superficial porque, si tiene objetos anidados (objetos con


propiedades que contienen otros objetos), solo se copian los valores del nivel superior.
Los objetos secundarios se hacen referencia entre sí.

PSTypeName para tipos de objeto personalizados


Ahora que tenemos un objeto, hay algunas cosas más que podemos hacer con él que
puede que no sean tan evidentes. Lo primero que debemos hacer es proporcionarle un
elemento PSTypeName . Esta es la opción más común que se suele utilizar:

PowerShell

$myObject.PSObject.TypeNames.Insert(0,"My.Object")

Recientemente, descubrí otra manera de hacer esto en esta publicación de


/u/markekraus . Profundicé un poco, y hay más publicaciones sobre la idea de Adam
Bertram y Mike Shepard donde hablan sobre este enfoque que le permite definirlo
en línea.

PowerShell

$myObject = [PSCustomObject]@{
PSTypeName = 'My.Object'
Name = 'Kevin'
Language = 'PowerShell'
State = 'Texas'
}

Me encanta lo bien que esto encaja en el lenguaje. Ahora que tenemos un objeto con
un nombre de tipo adecuado, podemos hacer algunas cosas más.

7 Nota
También puede crear tipos de PowerShell personalizados mediante clases de
PowerShell. Para obtener más información, vea la información general de las clases
de PowerShell.

Uso de DefaultPropertySet (el modo largo)


PowerShell decide qué propiedades se van a mostrar de forma predeterminada. Muchos
de los comandos nativos tienen un .ps1xml archivo de formato que realiza todo el
trabajo pesado. A partir de esta publicación de Boe Prox , hay otra manera de hacer
esto en nuestro objeto personalizado con PowerShell exclusivamente. Podemos
proporcionarle un elemento MemberSet para que lo use.

PowerShell

$defaultDisplaySet = 'Name','Language'
$defaultDisplayPropertySet = New-Object
System.Management.Automation.PSPropertySet('DefaultDisplayPropertySet',
[string[]]$defaultDisplaySet)
$PSStandardMembers =
[System.Management.Automation.PSMemberInfo[]]@($defaultDisplayPropertySet)
$MyObject | Add-Member MemberSet PSStandardMembers $PSStandardMembers

Ahora, cuando mi objeto solo se encuentra en el shell, solo mostrará esas propiedades
de forma predeterminada.

Update-TypeData con DefaultPropertySet


Esto está bien, pero recientemente he visto una mejor manera de utilizar Update-
TypeData para especificar las propiedades predeterminadas.

PowerShell

$TypeData = @{
TypeName = 'My.Object'
DefaultDisplayPropertySet = 'Name','Language'
}
Update-TypeData @TypeData

Eso es lo suficientemente sencillo que casi podría recordarlo si no tuviera esta


publicación como referencia rápida. Ahora puedo crear fácilmente objetos con una gran
cantidad de propiedades y seguir ofreciendo una buena imagen limpia al examinarlo
desde el shell. Si necesito acceder a esas otras propiedades o verlas, todavía siguen ahí.
PowerShell

$myObject | Format-List *

Update-TypeData con ScriptProperty


Otra cosa que se extrajo de ese vídeo fue crear propiedades de script para los objetos.
Este sería un buen momento para señalar que esto funciona también con los objetos
existentes.

PowerShell

$TypeData = @{
TypeName = 'My.Object'
MemberType = 'ScriptProperty'
MemberName = 'UpperCaseName'
Value = {$this.Name.toUpper()}
}
Update-TypeData @TypeData

Puede hacerlo antes o después de crear el objeto y seguirá funcionando. Esto es lo que
hace que sea diferente después de usar Add-Member con una propiedad de script.
Cuando se usa Add-Member de la forma en que se hizo referencia anteriormente, solo
existe en esa instancia específica del objeto. Esto se aplica a todos los objetos con este
elemento TypeName .

Parámetros de función
Ahora puede usar estos tipos personalizados para los parámetros de sus funciones y
scripts. Puede hacer que una función cree estos objetos personalizados y después
pasarlos a otras funciones.

PowerShell

param( [PSTypeName('My.Object')]$Data )

PowerShell requiere que el objeto sea el tipo especificado. Produce un error de


validación si el tipo no coincide automáticamente para ahorrarle el paso de probarlo en
el código. Un buen ejemplo de permitir que PowerShell haga lo que mejor sabe hacer.

Función OutputType
También puede definir un elemento OutputType para las funciones avanzadas.

PowerShell

function Get-MyObject
{
[OutputType('My.Object')]
[CmdletBinding()]
param
(
...

El valor del atributo OutputType solo es una nota de la documentación. No se deriva del
código de función ni se compara con la salida real de la función.

La razón principal por la que usaría un tipo de salida es que la metainformación sobre
su función refleje sus intenciones. Aspectos como Get-Command y Get-Help de los que el
entorno de desarrollo puede beneficiarse. Si desea obtener más información, eche un
vistazo a la ayuda relacionada: about_Functions_OutputTypeAttribute.

Dicho esto, si usa Pester para realizar pruebas unitarias de las funciones, sería una buena
idea validar los objetos de salida que coinciden con OutputType. Esto podría detectar
variables que solo se encuentran en la canalización cuando realmente no debería ser así.

Reflexiones finales
El contexto de esto trataba de [PSCustomObject] , pero una gran parte de esta
información se aplica a los objetos en general.

Antes he visto la mayoría de estas características de paso, pero nunca me las encontré
como una colección de información sobre PSCustomObject . Solo la semana pasada me
topé con otra y me sorprendió no haberla visto antes. Quería reunir todas estas ideas,
por lo que es posible que pueda ver la imagen más completa y tenerlas en cuenta
cuando tenga la oportunidad de usarlas. Espero que haya aprendido algo y pueda
encontrar una manera de ponerlo en práctica en sus scripts.
Todo lo que le interesa sobre la
sustitución de variables en cadenas
Artículo • 13/04/2023

Hay muchas maneras de usar variables en cadenas. Estoy llamando a esta sustitución de
variables, pero hago referencia a cada una de las veces que desea dar formato a una
cadena para incluir valores de variables. A menudo me encuentro explicando esto a
nuevos generadores de scripts.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

Concatenación
Se puede hacer referencia a la primera clase de métodos como concatenación.
Básicamente toma varias cadenas y las une. Existe un largo historial de uso de la
concatenación para crear cadenas con formato.

PowerShell

$name = 'Kevin Marquette'


$message = 'Hello, ' + $name

La concatenación funciona correctamente cuando solo hay algunos valores que agregar.
Sin embargo, esto puede complicarse rápidamente.

PowerShell

$first = 'Kevin'
$last = 'Marquette'

PowerShell

$message = 'Hello, ' + $first + ' ' + $last + '.'

Este sencillo ejemplo ya está resultando más difícil de leer.


Sustitución de variables
PowerShell tiene otra opción que es más sencilla. Puede especificar las variables
directamente en las cadenas.

PowerShell

$message = "Hello, $first $last."

El tipo de comillas que usa en torno a la cadena es fundamental. Una cadena entre
comillas dobles permite la sustitución, pero una cadena entre comillas simples no la
permite. Hay ocasiones en las que desea una u otra, por lo que tiene una opción.

Sustitución de comandos
Todo se complica un poco cuando empieza a intentar obtener los valores de las
propiedades en una cadena. Es en este punto donde muchos usuarios nuevos se
confunden. Antes permítame que le muestre lo que piensan que debería funcionar (y al
pie de la letra casi parece que debería).

PowerShell

$directory = Get-Item 'c:\windows'


$message = "Time: $directory.CreationTime"

Pese a esperar obtener CreationTime fuera de $directory , lo que obtiene es Time:


c:\windows.CreationTime como su valor. La razón es que este tipo de sustitución solo ve
la variable base. Considera que el punto forma parte de la cadena, de modo que deja de
resolver el valor con mayor profundidad.

Simplemente ocurre que este objeto proporciona una cadena como valor
predeterminado al colocarse en una cadena. En su lugar, algunos objetos proporcionan
el nombre de tipo como System.Collections.Hashtable . Algo de lo que es necesario
estar pendiente.

PowerShell le permite ejecutar comandos dentro de la cadena con una sintaxis especial.
Esto nos permite obtener las propiedades de estos objetos y ejecutar cualquier otro
comando para obtener un valor.

PowerShell

$message = "Time: $($directory.CreationTime)"


Esto funciona bien en algunas situaciones, pero puede volverse tan disparatado como la
concatenación si solo tiene algunas variables.

Ejecución del comando


Puede ejecutar comandos dentro de una cadena. Aunque tengo esta opción, no me
gusta. Se desordena rápidamente y es difícil de depurar. Ejecuto el comando y lo guardo
en una variable o uso una cadena de formato.

PowerShell

$message = "Date: $(Get-Date)"

Cadena de formato
.NET tiene un modo de dar formato a las cadenas con el que me resulta bastante fácil
trabajar. Permítame mostrarle en primer lugar su método estático antes de mostrarle el
acceso directo de PowerShell para hacer lo mismo.

PowerShell

# .NET string format string


[string]::Format('Hello, {0} {1}.',$first,$last)

# PowerShell format string


'Hello, {0} {1}.' -f $first, $last

Lo que ocurre aquí es que se analiza la cadena para los tokens {0} y {1} y, a
continuación, usa ese número para elegir entre los valores proporcionados. Si desea
repetir un valor en algún lugar de la cadena, puede reutilizar el número de ese valor.

Cuanto más complicada se vuelva la cadena, más valor obtendrá de este enfoque.

Dar formato a los valores como matrices


Si la línea de formato es demasiado larga, puede colocar primero los valores en una
matriz.

PowerShell

$values = @(
"Kevin"
"Marquette"
)
'Hello, {0} {1}.' -f $values

No se expande porque le pase toda la matriz, pero la idea es similar.

Formato avanzado
He indicado intencionadamente que su procedencia es .NET porque hay muchas
opciones de formato que ya están bien documentadas aquí. Existen formas integradas
de dar formato a diversos tipos de datos.

PowerShell

"{0:yyyyMMdd}" -f (Get-Date)
"Population {0:N0}" -f 8175133

Output

20211110
Population 8,175,133

No voy a entrar en ellas, solo quería informarle de que, en caso de necesitarlo, se trata
de un motor de formato muy eficaz.

Unión de cadenas
En ocasiones, realmente desea concatenar una lista de valores de forma conjunta. Hay
un operador -join que puede hacerlo automáticamente. Incluso permite especificar un
carácter que se va a combinar entre las cadenas.

PowerShell

$servers = @(
'server1'
'server2'
'server3'
)

$servers -join ','

Si desea concatenar ( -join ) algunas cadenas sin un separador, debe especificar una
cadena vacía '' . No obstante, si eso es todo lo que necesita, existe una opción más
rápida.
PowerShell

[string]::Concat('server1','server2','server3')
[string]::Concat($servers)

Asimismo, merece la pena señalar que también puede dividir ( -split ) cadenas.

Join-Path
Aunque suele pasarse por alto, es un cmdlet excelente para crear una ruta de acceso del
archivo.

PowerShell

$folder = 'Temp'
Join-Path -Path 'c:\windows' -ChildPath $folder

Lo mejor que tiene es que resuelve correctamente las barras diagonales inversas al
poner los valores juntos. Esto es especialmente importante si toma valores de usuarios o
archivos de configuración.

Esto también funciona bien con Split-Path y Test-Path . También se tratan en mi


publicación sobre cómo leer y guardar en archivos .

Las cadenas son matrices


Antes de continuar, necesito mencionar la adición de cadenas aquí. Recuerde que una
cadena es simplemente una matriz de caracteres. Al agregar varias cadenas juntas, se
crea una nueva matriz cada vez.

Fíjese en este ejemplo:

PowerShell

$message = "Numbers: "


foreach($number in 1..10000)
{
$message += " $number"
}

Parece muy básico, pero lo que no ve es que cada vez que se agrega una cadena a
$message , se crea una cadena nueva completa. Se asigna la memoria, se copian los
datos y se descartan los anteriores. No es nada del otro mundo llevándose a cabo solo
algunas veces, pero un bucle como este expondría realmente la incidencia.

StringBuilder
StringBuilder también es muy popular para crear cadenas de gran tamaño a partir de
muchas cadenas más pequeñas. La razón es que solo recopila todas las cadenas que le
agrega y solo concatena todas al final cuando recupera el valor.

PowerShell

$stringBuilder = New-Object -TypeName "System.Text.StringBuilder"

[void]$stringBuilder.Append("Numbers: ")
foreach($number in 1..10000)
{
[void]$stringBuilder.Append(" $number")
}
$message = $stringBuilder.ToString()

Una vez más, se trata de algo para lo cual me dirijo a .NET. Ya no suelo utilizarlo, pero
no está de más saber que está ahí.

Delineación con llaves


Se usa para la concatenación de sufijos dentro de la cadena. En ocasiones, su variable
no tiene un límite de palabra correcto.

PowerShell

$test = "Bet"
$tester = "Better"
Write-Host "$test $tester ${test}ter"

Gracias /u/real_parbold por ello.

Esta es una alternativa a este enfoque:

PowerShell

Write-Host "$test $tester $($test)ter"


Write-Host "{0} {1} {0}ter" -f $test, $tester
Personalmente uso la cadena de formato para esto, pero es bueno saberlo en caso de
que lo vea en su entorno natural.

Buscar y reemplazar tokens


Aunque la mayoría de estas características limitan su necesidad de implementar su
propia solución, hay ocasiones en las que puede tener archivos de plantilla de gran
tamaño donde desee reemplazar las cadenas de su interior.

Supongamos que ha extraído una plantilla de un archivo con mucho texto.

PowerShell

$letter = Get-Content -Path TemplateLetter.txt -RAW


$letter = $letter -replace '#FULL_NAME#', 'Kevin Marquette'

Es posible que tenga muchos tokens para su reemplazo. El truco consiste en usar un
token muy distinto que sea fácil de encontrar y reemplazar. Tiendo a usar un carácter
especial en ambos extremos para ayudar a distinguirlo.

Recientemente, he descubierto una nueva forma de abordar esto. Decidí dejar esta
sección aquí porque se trata de un patrón que se suele usar.

Reemplazar varios tokens


Cuando dispongo de una lista de tokens que es necesario reemplazar, adopto un
enfoque más genérico. Los colocaría en una tabla hash y procesaría una iteración en
ellos para realizar el reemplazo.

PowerShell

$tokenList = @{
Full_Name = 'Kevin Marquette'
Location = 'Orange County'
State = 'CA'
}

$letter = Get-Content -Path TemplateLetter.txt -RAW


foreach( $token in $tokenList.GetEnumerator() )
{
$pattern = '#{0}#' -f $token.key
$letter = $letter -replace $pattern, $token.Value
}

Esos tokens podrían cargarse desde JSON o CSV si es necesario.


ExecutionContext ExpandString
Existe una forma inteligente de definir una cadena de sustitución con comillas simples y
expandir las variables más adelante. Fíjese en este ejemplo:

PowerShell

$message = 'Hello, $Name!'


$name = 'Kevin Marquette'
$string = $ExecutionContext.InvokeCommand.ExpandString($message)

La llamada a .InvokeCommand.ExpandString en el contexto de ejecución actual utiliza las


variables en el ámbito actual para la sustitución. Lo clave aquí es que $message se puede
definir muy pronto, antes incluso de que las variables existan.

Si ampliamos eso un poco, podemos realizar esta sustitución una y otra vez con
diferentes valores.

PowerShell

$message = 'Hello, $Name!'


$nameList = 'Mark Kraus','Kevin Marquette','Lee Dailey'
foreach($name in $nameList){
$ExecutionContext.InvokeCommand.ExpandString($message)
}

Para seguir trabajando en esta idea, podría importar una plantilla de correo electrónico
de gran tamaño desde un archivo de texto para hacerlo. Tengo que agradecer a Mark
Kraus esta sugerencia .

Lo que más le convenga


Me encanta el enfoque de cadena de formato. Definitivamente hago esto con las
cadenas más complicadas o si hay varias variables. Puedo usar cualquiera en todo lo
que sea muy corto.

¿Algo más?
He abarcado mucho con esto. Espero que al irse se lleve consigo este aprendizaje.

Vínculos
Si deseas obtener más información sobre los métodos y características que hacen
posible la interpolación de cadenas, consulta la siguiente lista para leer la
documentación de referencia.

La concatenación usa el operador de suma


La sustitución de variables y comandos sigue las reglas de comillas
El formato usa el operador de formato
La combinación de cadenas usa el operador de combinación y hace referencia
aJoin-Path, pero también puedes consultar información sobre Join-String
Las matrices se documentan en: Acerca de las matrices
StringBuilder es una clase .NET con su documentación específica
Las llaves de las cadenas también se tratan en las reglas de comillas
El reemplazo de tokens usa el operador de reemplazo
El método $ExecutionContext.InvokeCommand.ExpandString() contiene
documentación de referencia de la API de .NET
Todo lo que le interesa sobre la
instrucción if
Artículo • 13/04/2023

Al igual que muchos otros lenguajes, PowerShell tiene instrucciones para ejecutar
código condicionalmente en los scripts. Una de esas instrucciones es la instrucción If.
Hoy vamos a profundizar en uno de los comandos más fundamentales de PowerShell.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

Ejecución condicional
A menudo, los scripts tienen que tomar decisiones y realizar una lógica diferente en
función de esas decisiones. A eso me refiero con "ejecución condicional". Tiene una
instrucción o un valor para evaluar y, a continuación, ejecuta una sección diferente de
código basada en esa evaluación. Esto es exactamente lo que hace la instrucción if .

Instrucción if
Este es un ejemplo básico de la instrucción if :

PowerShell

$condition = $true
if ( $condition )
{
Write-Output "The condition was true"
}

Lo primero que hace la instrucción if es evaluar la expresión entre paréntesis. Si se


evalúa como $true , ejecuta el valor scriptblock en las llaves. Si el valor fuera $false ,
se omitiría el bloque de script.

En el ejemplo anterior, la instrucción if simplemente estaba evaluando la variable


$condition . Era $true y habría ejecutado el comando Write-Output dentro del bloque
de script.

En algunos lenguajes, puede colocar una sola línea de código después de la instrucción
if y se ejecuta. Este no es el caso en PowerShell. Debe proporcionar un valor

scriptblock completo con llaves para que funcione correctamente.

Operadores de comparación
El uso más común de la instrucción if es comparar dos elementos entre sí. PowerShell
tiene operadores especiales para diferentes escenarios de comparación. Cuando se usa
un operador de comparación, el valor del lado izquierdo se compara con el valor del
lado derecho.

-eq para igualdad


El elemento -eq realiza una comprobación de igualdad entre dos valores para
asegurarse de que son iguales entre sí.

PowerShell

$value = Get-MysteryValue
if ( 5 -eq $value )
{
# do something
}

En este ejemplo, voy a tomar un valor conocido de 5 y a compararlo con $value para
ver si coinciden.

Un caso de uso posible es comprobar el estado de un valor antes de realizar una acción
en él. Puede obtener un servicio y comprobar que el estado se estaba ejecutando antes
de llamar a Restart-Service en él.

Es habitual en otros lenguajes como C# usar == para la igualdad (por ejemplo: 5 ==


$value ), pero eso no funciona con PowerShell. Otro error común es usar el signo igual
(por ejemplo: 5 = $value ), que está reservado para asignar valores a variables. Al
colocar el valor conocido a la izquierda, es más difícil que se produzca este error.

Este operador tiene algunas variaciones (otros también).

-eq igualdad sin distinción entre mayúsculas y minúsculas

-ieq igualdad sin distinción entre mayúsculas y minúsculas


-ceq igualdad con distinción entre mayúsculas y minúsculas

-ne no es igual a
Muchos operadores tienen un operador relacionado que está comprobando el
resultado opuesto. -ne comprueba que los valores no son iguales entre sí.

PowerShell

if ( 5 -ne $value )
{
# do something
}

Úselo para asegurarse de que la acción solo se ejecuta si el valor no es 5 . Un buen caso
de uso sería verificar si un servicio estaba en ejecución antes de intentar iniciarlo.

Variaciones:

-ne sin distinción de mayúsculas y minúsculas, no es igual a

-ine sin distinción de mayúsculas y minúsculas, no es igual a

-cne con distinción de mayúsculas y minúsculas, no es igual a

Se trata de variaciones inversas de -eq . Agruparé estos tipos al mostrar las variaciones
de otros operadores.

-gt -ge -lt -le para mayor que o menor que


Estos operadores se utilizan al comprobar si un valor es mayor o menor que otro valor.
-gt -ge -lt -le representa GreaterThan, GreaterThanOrEqual, LessThan y
LessThanOrEqual.

PowerShell

if ( $value -gt 5 )
{
# do something
}

Variaciones:

-gt mayor que


-igt mayor que, sin distinción de mayúsculas y minúsculas
-cgt mayor que, con distinción de mayúsculas y minúsculas

-ge mayor que o igual a


-ige mayor que o igual a, sin distinción de mayúsculas y minúsculas

-cge mayor que o igual a, con distinción de mayúsculas y minúsculas


-lt menor que

-ilt menor que, sin distinción de mayúsculas y minúsculas

-clt menor que, con distinción de mayúsculas y minúsculas


-le menor que o igual a

-ile menor que o igual a, sin distinción de mayúsculas y minúsculas


-cle menor que o igual a, con distinción de mayúsculas y minúsculas

No sé qué le llevaría a usar las opciones que distinguen mayúsculas de minúsculas y las
que no las distinguen para estos operadores.

Coincidencias con caracteres comodín -like


PowerShell tiene su propia sintaxis de coincidencia de patrones basada en comodines,
que se puede usar con el operador -like . Estos patrones de caracteres comodín son
bastante básicos.

? coincide con cualquier carácter individual.


* coincide con cualquier número de caracteres.

PowerShell

$value = 'S-ATX-SQL01'
if ( $value -like 'S-*-SQL??')
{
# do something
}

Es importante señalar que el patrón coincide con toda la cadena. Si necesita buscar
coincidencias con algo en el medio de la cadena, debe colocar * en ambos extremos de
la cadena.

PowerShell

$value = 'S-ATX-SQL02'
if ( $value -like '*SQL*')
{
# do something
}
Variaciones:

-like carácter comodín sin distinción de mayúsculas y minúsculas


-ilike carácter comodín sin distinción de mayúsculas y minúsculas

-clike carácter comodín con distinción de mayúsculas y minúsculas


-notlike carácter comodín sin distinción de mayúsculas y minúsculas no

coincidente
-inotlike carácter comodín sin distinción de mayúsculas y minúsculas no
coincidente
-cnotlike carácter comodín con distinción de mayúsculas y minúsculas no
coincidente

Expresión regular -match


El operador -match permite comprobar una cadena para buscar coincidencias basadas
en una expresión regular. Úselo cuando considere que los patrones de caracteres
comodín no son lo suficientemente flexibles.

PowerShell

$value = 'S-ATX-SQL01'
if ( $value -match 'S-\w\w\w-SQL\d\d')
{
# do something
}

De forma predeterminada, un patrón regex coincide con cualquier parte de la cadena.


Por lo tanto, puede especificar una subcadena que desee que coincida de la siguiente
manera:

PowerShell

$value = 'S-ATX-SQL01'
if ( $value -match 'SQL')
{
# do something
}

Regex es un lenguaje complejo propio y vale la pena analizarlo. Hablo más sobre -match
y las muchas maneras de usar regex en otro artículo.

Variaciones:

-match regex sin distinción de mayúsculas y minúsculas


-imatch regex sin distinción de mayúsculas y minúsculas

-cmatch regex con distinción de mayúsculas y minúsculas


-notmatch regex sin distinción de mayúsculas y minúsculas no coincidente

-inotmatch regex sin distinción de mayúsculas y minúsculas no coincidente


-cnotmatch regex con distinción de mayúsculas y minúsculas no coincidente

-is de tipo
Puede comprobar el tipo de un valor con el operador -is .

PowerShell

if ( $value -is [string] )


{
# do something
}

Puede usarlo si está trabajando con clases o acepta varios objetos a través de la
canalización. Puede tener como entrada un servicio o un nombre de servicio. A
continuación, compruebe si tiene un servicio y capture el servicio si solo tiene el
nombre.

PowerShell

if ( $Service -isnot [System.ServiceProcess.ServiceController] )


{
$Service = Get-Service -Name $Service
}

Variaciones:

-is de tipo

-isnot no de tipo

Operadores de recopilación
Cuando se usan los operadores anteriores con un solo valor, el resultado es $true o
$false . Esto se trata de forma ligeramente diferente cuando se trabaja con una
recopilación. Cada elemento de la recopilación se evalúa y el operador devuelve todos
los valores que se evalúan como $true .

PowerShell
PS> 1,2,3,4 -eq 3
3

Esto sigue funcionando correctamente en una instrucción if . Por lo tanto, el operador


devuelve un valor y toda la instrucción es $true .

PowerShell

$array = 1..6
if ( $array -gt 3 )
{
# do something
}

Hay una pequeña trampa oculta en estos detalles que debo señalar. Cuando se utiliza el
operador -ne de esta manera, es fácil mirar erróneamente la lógica hacia atrás. El uso
de -ne con una recopilación devuelve $true si algún elemento de la recopilación no
coincide con su valor.

PowerShell

PS> 1,2,3 -ne 4


1
2
3

Esto puede parecer un truco inteligente, pero tenemos operadores -contains y -in que
se ocupan de esto de forma más eficaz. Y -notcontains hace lo que espera.

-contains
El operador -contains busca su valor en la recopilación. En cuanto encuentra una
coincidencia, devuelve $true .

PowerShell

$array = 1..6
if ( $array -contains 3 )
{
# do something
}

Esta es la manera preferida de ver si una recopilación contiene su valor. El uso de Where-
Object (o -eq ) recorre toda la lista cada vez y es significativamente más lento.
Variaciones:

-contains coincidencia sin distinción de mayúsculas y minúsculas


-icontains coincidencia sin distinción de mayúsculas y minúsculas

-ccontains coincidencia con distinción de mayúsculas y minúsculas


-notcontains sin distinción de mayúsculas y minúsculas no coincidente

-inotcontains sin distinción de mayúsculas y minúsculas no coincidente

-cnotcontains con distinción de mayúsculas y minúsculas no coincidente

-in
El operador -in es igual que el operador -contains , excepto que la recopilación está en
el lado derecho.

PowerShell

$array = 1..6
if ( 3 -in $array )
{
# do something
}

Variaciones:

-in coincidencia sin distinción de mayúsculas y minúsculas


-iin coincidencia sin distinción de mayúsculas y minúsculas

-cin coincidencia con distinción de mayúsculas y minúsculas

-notin sin distinción de mayúsculas y minúsculas no coincidente


-inotin sin distinción de mayúsculas y minúsculas no coincidente

-cnotin con distinción de mayúsculas y minúsculas no coincidente

Operadores lógicos
Los operadores lógicos se utilizan para invertir o combinar otras expresiones.

-not
El operador -not invierte una expresión de $false a $true o de $true a $false . Este
es un ejemplo en el que queremos realizar una acción cuando Test-Path es $false .

PowerShell
if ( -not ( Test-Path -Path $path ) )

La mayoría de los operadores de los que hemos hablado tienen una variación en la que
no es necesario usar el operador -not . Pero hay ocasiones en las que resulta útil.

! operator
Puede usar ! como alias para -not .

PowerShell

if ( -not $value ){}


if ( !$value ){}

Puede percibir que ! se usa por más gente que proviene de otros lenguajes, como C#.
Prefiero escribirlo completo porque me resulta difícil de ver cuando miro rápidamente
mis scripts.

-and
Puede combinar expresiones con el operador -and . Al hacerlo, los dos lados deben ser
$true para que la expresión completa sea $true .

PowerShell

if ( ($age -gt 13) -and ($age -lt 55) )

En ese ejemplo, $age debe ser 13 o más años para el lado izquierdo y menor que 55
para el lado derecho. He añadido paréntesis adicionales para que el ejemplo estuviera
más claro, pero son opcionales dado que la expresión es simple. Este es el mismo
ejemplo sin ellos.

PowerShell

if ( $age -gt 13 -and $age -lt 55 )

La evaluación se produce de izquierda a derecha. Si el primer elemento se evalúa como


$false , se cierra pronto y no realiza la comparación adecuada. Esto resulta útil cuando
es necesario asegurarse de que existe un valor antes de usarlo. Por ejemplo, Test-Path
produce un error si se le asigna una ruta $null .
PowerShell

if ( $null -ne $path -and (Test-Path -Path $path) )

-or
-or permite especificar dos expresiones y devuelve $true si cualquiera de ellas es

$true .

PowerShell

if ( $age -le 13 -or $age -ge 55 )

Al igual que con el operador -and , la evaluación se produce de izquierda a derecha.


Excepto que si la primera parte es $true , toda la declaración es $true y no procesa el
resto de la expresión.

Además, fíjese en cómo funciona la sintaxis para estos operadores. Necesita dos
expresiones independientes. He visto a los usuarios intentar hacer algo como esto
$value -eq 5 -or 6 sin darse cuenta de su error.

-xor OR exclusivo
Este es poco habitual. -xor permite que solo una expresión se evalúe como $true . Por
tanto, si los dos elementos son $false o ambos elementos son $true , la expresión
completa es $false . Otra forma de verlo es que la expresión es solo $true cuando los
resultados de la expresión son diferentes.

Es raro que alguien use este operador lógico y no se me ocurre un buen ejemplo que
justifique su uso.

Operadores bit a bit


Los operadores bit a bit realizan cálculos en los bits dentro de los valores y generan un
nuevo valor como resultado. Las claves de los operadores bit a bit no se analizan en este
artículo, pero aquí los enumeramos.

-band AND binario


-bor OR binario

-bxor OR exclusivo binario


-bnot NOT binario

-shl desplazar a la izquierda


-shr desplazar a la derecha

Expresiones de PowerShell
Podemos usar PowerShell normal dentro de la instrucción de condición.

PowerShell

if ( Test-Path -Path $Path )

Test-Path devuelve $true o $false cuando se ejecuta. Esto también se aplica a los
comandos que devuelven otros valores.

PowerShell

if ( Get-Process Notepad* )

Se evalúa como $true si hay un proceso devuelto y $false si no hay nada. Es


perfectamente válido usar expresiones de canalización u otras instrucciones de
PowerShell como esta:

PowerShell

if ( Get-Process | Where Name -eq Notepad )

Estas expresiones se pueden combinar entre sí con los operadores -and y -or , pero
puede que tenga que usar paréntesis para dividirlas en subexpresiones.

PowerShell

if ( (Get-Process) -and (Get-Service) )

Comprobación de $null
Si no hay ningún resultado o un valor $null se evalúa como $false en la instrucción
if . Cuando se comprueba específicamente $null , se recomienda colocar $null en el

lado izquierdo.

PowerShell
if ( $null -eq $value )

Hay algunos matices al tratar con valores $null en PowerShell. Si está interesado en
profundizar más, hay un artículo sobre todo lo que interesa sobre $null.

Asignación de variables dentro de la condición


Casi me olvido de tratar esta cuestión, menos mal que Prasoon Karunan V me lo ha
recordado.

PowerShell

if ($process=Get-Process notepad -ErrorAction ignore) {$process} else


{$false}

Normalmente, cuando se asigna un valor a una variable, el valor no se pasa a la


canalización o la consola. Cuando se realiza una asignación de variables en una
subexpresión, esta se pasa a la canalización.

PowerShell

PS> $first = 1
PS> ($second = 2)
2

¿Ve cómo la asignación de $first no tiene ninguna salida y la asignación de $second sí


la tiene? Cuando se realiza una asignación en una instrucción if , se ejecuta
exactamente igual que la asignación de $second anterior. Este es un ejemplo claro de
cómo podría usarlo:

PowerShell

if ( $process = Get-Process Notepad* )


{
$process | Stop-Process
}

Si se asigna un valor a $process , la instrucción es $true y $process se detiene.

No confunda esto con -eq , porque no se trata de una comprobación de igualdad. Esta
es una característica más confusa que la mayoría de las personas no se dan cuenta de
que funciona de este modo.
Asignación de variables desde el bloque de
scripts
También puede usar el bloque de scripts de la instrucción if para asignar un valor a
una variable.

PowerShell

$discount = if ( $age -ge 55 )


{
Get-SeniorDiscount
}
elseif ( $age -le 13 )
{
Get-ChildDiscount
}
else
{
0.00
}

Cada bloque de scripts escribe los resultados de los comandos, o el valor, como salida.
Se puede asignar el resultado de la instrucción if a la variable $discount . En ese
ejemplo se pueden asignar fácilmente esos valores a la variable $discount directamente
en cada bloque de scripts. No puedo decir que use esto con la instrucción if a
menudo, pero tengo un ejemplo donde lo he usado hace poco.

Ruta de acceso de ejecución alternativa


La declaración if le permite especificar una acción no solo cuando la declaración es
$true , sino también cuando es $false . Aquí es donde entra en juego la instrucción

else .

else
La instrucción else siempre es la última parte de la instrucción if cuando se usa.

PowerShell

if ( Test-Path -Path $Path -PathType Leaf )


{
Move-Item -Path $Path -Destination $archivePath
}
else
{
Write-Warning "$path doesn't exist or isn't a file."
}

En este ejemplo, comprobamos $path para asegurarnos de que es un archivo. Si


encontramos el archivo, lo movemos. Si no es así, escribimos una advertencia. Este tipo
de lógica de bifurcación es muy común.

if anidado
Las instrucciones if y else toman un bloque de script, por lo que podemos colocar
cualquier comando de PowerShell dentro de ellas, incluida otra instrucción if . Esto le
permite hacer uso de una lógica mucho más complicada.

PowerShell

if ( Test-Path -Path $Path -PathType Leaf )


{
Move-Item -Path $Path -Destination $archivePath
}
else
{
if ( Test-Path -Path $Path )
{
Write-Warning "A file was required but a directory was found
instead."
}
else
{
Write-Warning "$path could not be found."
}
}

En este ejemplo, primero probamos la ruta de acceso ideal y luego tomamos medidas al
respecto. Si se produce un error, hacemos otra comprobación y proporcionamos
información más detallada al usuario.

elseif
No estamos limitados a una única comprobación condicional. Podemos encadenar
instrucciones if y else juntas en lugar de anidarlas mediante la instrucción elseif .

PowerShell

if ( Test-Path -Path $Path -PathType Leaf )


{
Move-Item -Path $Path -Destination $archivePath
}
elseif ( Test-Path -Path $Path )
{
Write-Warning "A file was required but a directory was found instead."
}
else
{
Write-Warning "$path could not be found."
}

La ejecución se produce desde la parte superior a la parte inferior. Primero se evalúa la


instrucción if superior. Si es $false , se desplaza hacia abajo hasta el siguiente elseif
o else de la lista. Esa última else es la acción predeterminada que se realizará si
ninguna de las otras devuelven $true .

Modificador
En este punto, es necesario mencionar la instrucción switch . Proporciona una sintaxis
alternativa para realizar varias comparaciones con un valor. Con switch , especifica una
expresión y el resultado se compara con varios valores diferentes. Si uno de esos valores
coincide, se ejecuta el bloque de código correspondiente. Eche un vistazo a este
ejemplo:

PowerShell

$itemType = 'Role'
switch ( $itemType )
{
'Component'
{
'is a component'
}
'Role'
{
'is a role'
}
'Location'
{
'is a location'
}
}

Existen tres valores posibles que pueden coincidir con $itemType . En este caso, coincide
con Role . He usado un ejemplo sencillo para mostrarle un poco del operador switch .
Hablo más sobre todo lo que le interesa saber sobre la instrucción switch en otro
artículo.

Matriz insertada
Tengo una función llamada Invoke-SnowSql que inicia un ejecutable con varios
argumentos de la línea de comandos. Aquí hay un clip de esa función donde compilo la
matriz de argumentos.

PowerShell

$snowSqlParam = @(
'--accountname', $Endpoint
'--username', $Credential.UserName
'--option', 'exit_on_error=true'
'--option', 'output_format=csv'
'--option', 'friendly=false'
'--option', 'timing=false'
if ($Debug)
{
'--option', 'log_level=DEBUG'
}
if ($Path)
{
'--filename', $Path
}
else
{
'--query', $singleLineQuery
}
)

Las variables $Debug y $Path son parámetros de la función que proporciona el usuario
final. Los evaluamos insertados dentro de la inicialización de la matriz. Si $Debug es
verdadero, esos valores se ubican en $snowSqlParam en el lugar correcto. Lo mismo se
aplica a la variable $Path .

Simplificación de las operaciones complejas


Es inevitable que se produzca una situación en la que tenga demasiadas comparaciones
que comprobar y que la instrucción If se desplace fuera del lado derecho de la
pantalla.

PowerShell
$user = Get-ADUser -Identity $UserName
if ( $null -ne $user -and $user.Department -eq 'Finance' -and $user.Title -
match 'Senior' -and $user.HomeDrive -notlike '\\server\*' )
{
# Do Something
}

Pueden resultar difíciles de leer, por lo que es más propenso a cometer errores.
Podemos tomar algunas medidas al respecto.

Continuación de línea
Algunos operadores de PowerShell permiten ajustar el comando a la línea siguiente. Los
operadores lógicos -and y -or son buenos operadores para usar en caso de que desee
dividir la expresión en varias líneas.

PowerShell

if ($null -ne $user -and


$user.Department -eq 'Finance' -and
$user.Title -match 'Senior' -and
$user.HomeDrive -notlike '\\server\*'
)
{
# Do Something
}

Sigue siendo complejo, pero colocar cada pieza en su propia línea marca una gran
diferencia. Normalmente recurro a esta opción cuando tengo más de dos
comparaciones o si tengo que desplazarme hacia la derecha para leer alguna de las
lógicas.

Cálculo previo de los resultados


Podemos sacar la instrucción de la instrucción if y comprobar solo el resultado.

PowerShell

$needsSecureHomeDrive = $null -ne $user -and


$user.Department -eq 'Finance' -and
$user.Title -match 'Senior' -and
$user.HomeDrive -notlike '\\server\*'

if ( $needsSecureHomeDrive )
{
# Do Something
}

Tiene un aspecto mucho más limpio que el ejemplo anterior. También tiene la
oportunidad de usar un nombre de variable que explique lo que está comprobando
realmente. Este también es un ejemplo de código autodocumentado que ahorra
comentarios innecesarios.

Varias instrucciones if
Podemos dividir esto en varias instrucciones y comprobarlas de una en una. En este
caso, usamos una marca o una variable de seguimiento para combinar los resultados.

PowerShell

$skipUser = $false

if( $null -eq $user )


{
$skipUser = $true
}

if( $user.Department -ne 'Finance' )


{
Write-Verbose "isn't in Finance department"
$skipUser = $true
}

if( $user.Title -match 'Senior' )


{
Write-Verbose "Doesn't have Senior title"
$skipUser = $true
}

if( $user.HomeDrive -like '\\server\*' )


{
Write-Verbose "Home drive already configured"
$skipUser = $true
}

if ( -not $skipUser )
{
# do something
}

Tuve que invertir la lógica para que la lógica de la marca funcionara correctamente.
Cada evaluación es una instrucción if individual. La ventaja de esto es que al depurar
puede saber exactamente lo que está haciendo la lógica. También pude agregar un nivel
de detalle mucho mayor.

La desventaja obvia es que es mucho más código que escribir. El código es más
complejo de ver porque toma una sola línea de lógica y la expande en 25 o más líneas.

Uso de funciones
También se puede trasladar toda la lógica de validación a una función. Fíjese qué limpio
se ve esto de un vistazo.

PowerShell

if ( Test-SecureDriveConfiguration -ADUser $user )


{
# do something
}

Todavía tiene que crear la función para realizar la validación, pero de este modo es
mucho más fácil trabajar con el código. Y también es más fácil de probar. En las
pruebas, puede simular la llamada a Test-ADDriveConfiguration y solo necesita dos
pruebas para esta función. Una en la que devuelve $true y otra en la que devuelve
$false . La prueba de la otra función es más sencilla porque es muy pequeña.

El cuerpo de esa función aún podría ser esa línea única con la que comenzamos o la
lógica explotada que usamos en la última sección. Esto funciona bien en ambos
escenarios y le permite cambiar fácilmente esa implementación más adelante.

Control de errores
Un uso importante de la instrucción if es comprobar las condiciones de error antes de
que se produzcan errores. Un buen ejemplo es comprobar si ya existe una carpeta antes
de intentar crearla.

PowerShell

if ( -not (Test-Path -Path $folder) )


{
New-Item -Type Directory -Path $folder
}

Me gustaría decir que, si espera que se produzca una excepción, esta no es realmente
una excepción. Compruebe los valores y valide las condiciones donde pueda hacerlo.
Si desea profundizar un poco más en el control de excepciones real, tengo un artículo
sobre lo que le interesa saber sobre las excepciones.

Conclusiones
La instrucción if es una instrucción bastante sencilla, pero es una parte fundamental de
PowerShell. Tendrá que usarla varias en casi todos los scripts que escriba. Espero que
ahora la conozca un poco mejor.
Todo lo que le interesa sobre la
instrucción switch
Artículo • 13/04/2023

Al igual que muchos otros lenguajes, PowerShell tiene comandos para controlar el flujo
de ejecución dentro de los scripts. Una de esas instrucciones es switch, que, en
PowerShell, ofrece características que no existen en otros lenguajes. Hoy, vamos a
profundizar en cómo trabajar con switch de PowerShell.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

Instrucción if
Una de las primeras instrucciones que se aprenden es if . Permite ejecutar un bloque de
script si una instrucción es $true .

PowerShell

if ( Test-Path $Path )
{
Remove-Item $Path
}

Puede tener una lógica mucho más complicada mediante las instrucciones elseif y
else . A continuación, se muestra un ejemplo en el que tengo un valor numérico para el

día de la semana y quiero obtener el nombre como una cadena.

PowerShell

$day = 3

if ( $day -eq 0 ) { $result = 'Sunday' }


elseif ( $day -eq 1 ) { $result = 'Monday' }
elseif ( $day -eq 2 ) { $result = 'Tuesday' }
elseif ( $day -eq 3 ) { $result = 'Wednesday' }
elseif ( $day -eq 4 ) { $result = 'Thursday' }
elseif ( $day -eq 5 ) { $result = 'Friday' }
elseif ( $day -eq 6 ) { $result = 'Saturday' }

$result

Output

Wednesday

Se trata de un patrón común y hay muchas maneras de abordarlo. Una de ellas es con
switch .

Instrucción switch
La instrucción switch permite proporcionar una variable y una lista de valores posibles.
Si el valor coincide con la variable, se ejecuta su bloque de script.

PowerShell

$day = 3

switch ( $day )
{
0 { $result = 'Sunday' }
1 { $result = 'Monday' }
2 { $result = 'Tuesday' }
3 { $result = 'Wednesday' }
4 { $result = 'Thursday' }
5 { $result = 'Friday' }
6 { $result = 'Saturday' }
}

$result

Output

'Wednesday'

En este ejemplo, el valor de $day coincide con uno de los valores numéricos y, después,
se asigna el nombre correcto a $result . En este ejemplo, solo se realiza la asignación a
una variable, pero cualquier comando de PowerShell puede ejecutarse en esos bloques
de script.

Asignación a una variable


Podemos escribir ese último ejemplo de otra manera.

PowerShell

$result = switch ( $day )


{
0 { 'Sunday' }
1 { 'Monday' }
2 { 'Tuesday' }
3 { 'Wednesday' }
4 { 'Thursday' }
5 { 'Friday' }
6 { 'Saturday' }
}

Se coloca el valor en la canalización de PowerShell y se asigna a $result . Puede hacer lo


mismo con las instrucciones if y foreach .

Valor predeterminado
Podemos usar la palabra clave default para identificar qué debe ocurrir si no hay
ninguna coincidencia.

PowerShell

$result = switch ( $day )


{
0 { 'Sunday' }
# ...
6 { 'Saturday' }
default { 'Unknown' }
}

Aquí se devuelve el valor Unknown en el caso predeterminado.

Cadenas
Creé correspondencias con los números en los últimos ejemplos, pero también se
puede establecer una coincidencia entre cadenas.

PowerShell

$item = 'Role'

switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}

Output

is a role

Decidí no encapsular aquí las coincidencias Component , Role y Location entre comillas
para resaltar que son opcionales. switch las trata como una cadena en la mayoría de los
casos.

Matrices
Una de las características interesantes de la instrucción switch de PowerShell es la
forma en que trata las matrices. Si proporciona una matriz a una instrucción switch ,
esta procesa cada elemento de dicha colección.

PowerShell

$roles = @('WEB','Database')

switch ( $roles ) {
'Database' { 'Configure SQL' }
'WEB' { 'Configure IIS' }
'FileServer' { 'Configure Share' }
}

Output

Configure IIS
Configure SQL

Si hay elementos repetidos en la matriz, la sección correspondiente establece


coincidencias entre ellos varias veces.
PSItem
Puede usar $PSItem o $_ para hacer referencia al elemento actual que se procesó.
Cuando establecemos una coincidencia simple, $PSItem es el valor con el que se crea la
coincidencia. Realizaré algunas coincidencias avanzadas en la sección siguiente donde
se usa esta variable.

Parámetros
Una característica exclusiva de switch de PowerShell es que tiene una serie de
Parámetros de modificador que cambian la forma en que se ejecuta.

-CaseSensitive
Las coincidencias no distinguen mayúsculas de minúsculas de forma predeterminada. Si
necesita que se distingan mayúsculas de minúsculas, puede usar -CaseSensitive . Se
puede utilizar en combinación con los otros parámetros switch.

-Wildcard
Se puede habilitar la compatibilidad con los caracteres comodín mediante el
modificador -wildcard . Usa la misma lógica del carácter comodín que el operador -
like para establecer cada coincidencia.

PowerShell

$Message = 'Warning, out of disk space'

switch -Wildcard ( $message )


{
'Error*'
{
Write-Error -Message $Message
}
'Warning*'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}
Output

WARNING: Warning, out of disk space

Aquí se procesa un mensaje y, después, se transmite en secuencias diferentes en función


del contenido.

-Regex
La instrucción switch admite las coincidencias regex del mismo modo que los caracteres
comodín.

PowerShell

switch -Regex ( $message )


{
'^Error'
{
Write-Error -Message $Message
}
'^Warning'
{
Write-Warning -Message $Message
}
default
{
Write-Information $message
}
}

Hay más ejemplos de uso de regex en otro artículo que escribí: Las distintas formas de
usar regex .

-File
Una característica poco conocida de la instrucción switch es que puede procesar un
archivo con el parámetro -File . Utilice -file con una ruta de acceso a un archivo, en
lugar de asignarle una expresión variable.

PowerShell

switch -Wildcard -File $path


{
'Error*'
{
Write-Error -Message $PSItem
}
'Warning*'
{
Write-Warning -Message $PSItem
}
default
{
Write-Output $PSItem
}
}

Funciona igual que el procesamiento de una matriz. En este ejemplo, se combina con la
coincidencia con caracteres comodín y se usa $PSItem . Esto procesaría un archivo de
registro y lo convertiría en mensajes de advertencia y error en función de las
coincidencias regex.

Detalles avanzados
Ahora que conoce todas estas características documentadas, podemos usarlas en el
contexto de un procesamiento más avanzado.

Expresiones
switch puede estar en una expresión en lugar de en una variable.

PowerShell

switch ( ( Get-Service | Where status -eq 'running' ).name ) {...}

Cualquiera que sea la expresión evaluada, será el valor que se utilizará para la
coincidencia.

Varias coincidencias
Puede que ya lo sepa, pero switch puede coincidir con varias condiciones. Esto sucede
especialmente cuando se usan las coincidencias -wildcard o -regex . Puede agregar la
misma condición varias veces, y todas se activarán.

PowerShell

switch ( 'Word' )
{
'word' { 'lower case word match' }
'Word' { 'mixed case word match' }
'WORD' { 'upper case word match' }
}

Output

lower case word match


mixed case word match
upper case word match

Estas tres instrucciones se activan. Esto muestra que se comprueba cada condición (en
orden). Esto se aplica al procesamiento de matrices en las que cada elemento
comprueba cada condición.

Continuar
Normalmente, aquí es donde se introduciría la instrucción break , pero es mejor
aprender a usar continue primero. Al igual que con un bucle foreach , continue
continúa en el siguiente elemento de la colección o sale de switch si no hay más
elementos. Podemos reescribir ese último ejemplo con instrucciones continue, para que
solo se ejecute una instrucción.

PowerShell

switch ( 'Word' )
{
'word'
{
'lower case word match'
continue
}
'Word'
{
'mixed case word match'
continue
}
'WORD'
{
'upper case word match'
continue
}
}

Output

lower case word match


En lugar de buscar coincidencias con los tres elementos, se establece una coincidencia
con el primero, y el modificador continúa hasta el valor siguiente. Dado que ya no
queda ningún valor por procesar, el modificador se cierra. En el ejemplo siguiente se
muestra cómo un carácter comodín podría coincidir con varios elementos.

PowerShell

switch -Wildcard -File $path


{
'*Error*'
{
Write-Error -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}

Dado que una línea del archivo de entrada podría contener las palabras Error y
Warning , solo deseamos que se ejecute la primera y que, después, se siga procesando el
archivo.

Break
Una instrucción break cierra el modificador. Este es el mismo comportamiento que
continue presenta para los valores únicos. La diferencia se muestra al procesar una

matriz. break detiene todo el procesamiento del modificador y continue pasa al


siguiente elemento.

PowerShell

$Messages = @(
'Downloading update'
'Ran into errors downloading file'
'Error: out of disk space'
'Sending email'
'...'
)

switch -Wildcard ($Messages)


{
'Error*'
{
Write-Error -Message $PSItem
break
}
'*Error*'
{
Write-Warning -Message $PSItem
continue
}
'*Warning*'
{
Write-Warning -Message $PSItem
continue
}
default
{
Write-Output $PSItem
}
}

Output

Downloading update
WARNING: Ran into errors downloading file
write-error -message $PSItem : Error: out of disk space
+ CategoryInfo : NotSpecified: (:) [Write-Error],
WriteErrorException
+ FullyQualifiedErrorId : Microsoft.PowerShell.Commands.WriteErrorException

En este caso, si se alcanzan las líneas que comienzan con Error , se obtiene un error y el
modificador se detiene. Esto es lo que hace la instrucción break . Si encontramos Error
dentro de la cadena y no solo al principio, lo escribimos como una advertencia.
Haremos lo mismo con Warning . Es posible que una línea pueda tener las palabras
Error y Warning , pero solo se necesita una para procesar. Esto es lo que hace la

instrucción continue .

Etiquetas de interrupción
La instrucción switch admite etiquetas break/continue , como foreach .

PowerShell

:filelist foreach($path in $logs)


{
:logFile switch -Wildcard -File $path
{
'Error*'
{
Write-Error -Message $PSItem
break filelist
}
'Warning*'
{
Write-Error -Message $PSItem
break logFile
}
default
{
Write-Output $PSItem
}
}
}

Personalmente, no me gusta usar las etiquetas de interrupción, pero quería destacarlas


porque son confusas si no se han visto antes. Si tiene varias instrucciones switch o
foreach anidadas, puede que quiera ir más allá del elemento más interno. Puede

colocar una etiqueta en switch que puede ser el destino de break .

Enum
PowerShell 5.0 proporcionó enumeraciones que podemos usar en un modificador.

PowerShell

enum Context {
Component
Role
Location
}

$item = [Context]::Role

switch ( $item )
{
Component
{
'is a component'
}
Role
{
'is a role'
}
Location
{
'is a location'
}
}
Output

is a role

Si desea conservarlas todas como enumeraciones fuertemente tipadas, puede colocarlas


entre paréntesis.

PowerShell

switch ($item )
{
([Context]::Component)
{
'is a component'
}
([Context]::Role)
{
'is a role'
}
([Context]::Location)
{
'is a location'
}
}

Los paréntesis son necesarios aquí para que el modificador no trate el valor
[Context]::Location como una cadena literal.

Bloque de script
Se puede usar un bloque de script para realizar la evaluación de una coincidencia, si es
necesario.

PowerShell

$age = 37

switch ( $age )
{
{$PSItem -le 18}
{
'child'
}
{$PSItem -gt 18}
{
'adult'
}
}

Output

'adult'

Esto agrega complejidad y puede hacer que switch sea difícil de leer. En la mayoría de
los casos en los que usaría algo parecido a esto, sería mejor usar instrucciones if y
elseif . Sería conveniente usar esto si ya existiera un modificador grande y se

necesitaran dos elementos para alcanzar el mismo bloque de evaluación.

Un aspecto que considero que ayuda con la legibilidad es colocar el bloque de script
entre paréntesis.

PowerShell

switch ( $age )
{
({$PSItem -le 18})
{
'child'
}
({$PSItem -gt 18})
{
'adult'
}
}

Todavía se ejecuta de la misma manera y ofrece una mejor interrupción visual cuando se
consulta rápidamente.

$matches en regex
Es necesario revisar la información relativa a regex para tratar algo que, a primera vista,
no resulta obvio. El uso de regex rellena la variable $matches . Voy a usar $matches más
cuando hablo de Las distintas formas de usar regex . A continuación, se muestra un
ejemplo rápido para mostrarlo en acción mediante coincidencias con nombre.

PowerShell

$message = 'my ssn is 123-23-3456 and credit card: 1234-5678-1234-5678'

switch -regex ($message)


{
'(?<SSN>\d\d\d-\d\d-\d\d\d\d)'
{
Write-Warning "message contains a SSN: $($matches.SSN)"
}
'(?<CC>\d\d\d\d-\d\d\d\d-\d\d\d\d-\d\d\d\d)'
{
Write-Warning "message contains a credit card number:
$($matches.CC)"
}
'(?<Phone>\d\d\d-\d\d\d-\d\d\d\d)'
{
Write-Warning "message contains a phone number: $($matches.Phone)"
}
}

Output

WARNING: message may contain a SSN: 123-23-3456


WARNING: message may contain a credit card number: 1234-5678-1234-5678

$null
Puede establecer una coincidencia con un valor $null que no tenga que ser el
predeterminado.

PowerShell

$values = '', 5, $null


switch ( $values )
{
$null { "Value '$_' is `$null" }
{ '' -eq $_ } { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}

Output

Value '' is an empty string


Value [5] isn't an empty string or $null
Value '' is $null

Al probar una cadena vacía en una instrucción switch , es importante usar la instrucción
de comparación como se muestra en este ejemplo en lugar del valor sin formato '' . En
una instrucción switch , el valor sin formato '' también coincide con $null . Por
ejemplo:
PowerShell

$values = '', 5, $null


switch ( $values )
{
$null { "Value '$_' is `$null" }
'' { "Value '$_' is an empty string" }
default { "Value [$_] isn't an empty string or `$null" }
}

Output

Value '' is an empty string


Value [5] isn't an empty string or $null
Value '' is $null
Value '' is an empty string

Además, debe tener cuidado con las devoluciones vacías de los cmdlets. Los cmdlets o
las canalizaciones que no tienen salida se tratan como una matriz vacía que no coincide
con nada, incluido el caso default .

PowerShell

$file = Get-ChildItem NonExistantFile*


switch ( $file )
{
$null { '$file is $null' }
default { "`$file is type $($file.GetType().Name)" }
}
# No matches

Expresión constante
Lee Dailey señaló que se puede usar una expresión $true constante para evaluar los
elementos [bool] . Imagine que hay varias comprobaciones booleanas que deben
realizarse.

PowerShell

$isVisible = $false
$isEnabled = $true
$isSecure = $true

switch ( $true )
{
$isEnabled
{
'Do-Action'
}
$isVisible
{
'Show-Animation'
}
$isSecure
{
'Enable-AdminMenu'
}
}

Output

Do-Action
Enabled-AdminMenu

Se trata de una forma sencilla de evaluar y tomar medidas en relación con el estado de
varios campos booleanos. Lo más interesante en este sentido es que puede haber una
variable que cambie el estado de un valor que aún no se ha evaluado.

PowerShell

$isVisible = $false
$isEnabled = $true
$isAdmin = $false

switch ( $true )
{
$isEnabled
{
'Do-Action'
$isVisible = $true
}
$isVisible
{
'Show-Animation'
}
$isAdmin
{
'Enable-AdminMenu'
}
}

Output

Do-Action
Show-Animation
Al establecer $isEnabled en $true , se garantiza que $isVisible también se establezca
en $true . Después, cuando se evalúa $isVisible , se invoca su bloque de script. Esto
resulta algo contradictorio, pero supone un uso inteligente de la mecánica.

Variable automática $switch


Cuando switch procesa sus valores, crea un enumerador y lo llama $switch . Se trata de
una variable automática creada por PowerShell, que se puede manipular directamente.

PowerShell

$a = 1, 2, 3, 4

switch($a) {
1 { [void]$switch.MoveNext(); $switch.Current }
3 { [void]$switch.MoveNext(); $switch.Current }
}

Aquí se presentan los resultados de:

Output

2
4

Al avanzar con el enumerador, switch no procesa el siguiente elemento, pero se puede


acceder a dicho valor directamente. Yo lo consideraría una locura.

Otros patrones

Tablas hash
Una de mis publicaciones más populares es la que hice sobre tablas hash. Uno de los
casos de uso de hashtable es que se trate de una tabla de búsqueda. Se trata de un
enfoque alternativo a un patrón común que una instrucción switch suele abordar.

PowerShell

$day = 3

$lookup = @{
0 = 'Sunday'
1 = 'Monday'
2 = 'Tuesday'
3 = 'Wednesday'
4 = 'Thursday'
5 = 'Friday'
6 = 'Saturday'
}

$lookup[$day]

Output

Wednesday

Si solo utilizo switch como una búsqueda, a menudo uso hashtable en su lugar.

Enum
PowerShell 5.0 presentó Enum y también es una opción en este caso.

PowerShell

$day = 3

enum DayOfTheWeek {
Sunday
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
}

[DayOfTheWeek]$day

Output

Wednesday

Podríamos pasar todo el día examinando diferentes formas de solucionar este


problema. Solo quería asegurarme de que sabía que tenía opciones.

Conclusiones
La instrucción switch es sencilla a primera vista, pero ofrece algunas características
avanzadas que la mayoría de las personas no saben que están disponibles. La
combinación de esas características convierte esto en una característica eficaz. Espero
que haya aprendido algo que antes no sabía.
Todo lo que quiso saber sobre las
excepciones
Artículo • 15/08/2023

El control de errores es solo parte de la vida cuando se trata de escribir código. A


menudo, se pueden comprobar y validar las condiciones del comportamiento esperado.
Cuando ocurre lo inesperado, acudimos al control de excepciones. Puede controlar
fácilmente las excepciones generadas por el código de otras personas o puede generar
sus propias excepciones para que las controlen otros usuarios.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

Terminología básica
Es necesario tratar algunos términos básicos antes de pasar a este.

Excepción
Una excepción es como un evento que se crea cuando el control de errores normal no
puede resolver el problema. Intentar dividir un número por cero o quedarse sin
memoria son ejemplos de situaciones que crean una excepción. En ocasiones, el autor
del código que se usa crea excepciones para determinados problemas cuando se
producen.

Throw (iniciar) y Catch (capturar)


Cuando se produce una excepción, decimos que se inicia una excepción. Para controlar
una excepción iniciada, debe capturarla. Si se inicia una excepción y no se captura con
algo, el script deja de ejecutarse.

La pila de llamadas
La pila de llamadas es la lista de funciones que se han llamado entre sí. Cuando se llama
a una función, se agrega a la pila o a la parte superior de la lista. Cuando la función
termina o devuelve un resultado, se quita de la pila.

Cuando se inicia una excepción, se comprueba esa pila de llamadas para que un
controlador de excepciones la capture.

Errores de terminación y no terminación


Por lo general, una excepción es un error de terminación. Una excepción iniciada se
captura o termina la ejecución actual. De forma predeterminada, Write-Error genera un
error de no terminación y agrega un error al flujo de salida sin iniciar una excepción.

Conviene destacar este punto porque Write-Error y otros errores de no terminación no


desencadenan una operación catch .

Tragarse una excepción


Es cuando se captura un error solo para suprimirlo. Hágalo con precaución, ya que
puede dificultar la solución de problemas.

Sintaxis básica de comandos


Esta es una introducción rápida a la sintaxis básica de control de excepciones que se usa
en PowerShell.

Throw
Para crear nuestro propio evento de excepción, iniciamos una excepción con la palabra
clave throw .

PowerShell

function Start-Something
{
throw "Bad thing happened"
}

Esta acción crea una excepción en tiempo de ejecución que es un error de terminación.
Se controla mediante una operación catch en una función de llamada o sale del script
con un mensaje similar a este.

PowerShell
PS> Start-Something

Bad thing happened


At line:1 char:1
+ throw "Bad thing happened"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (Bad thing happened:String)
[], RuntimeException
+ FullyQualifiedErrorId : Bad thing happened

Write-Error -ErrorAction Stop


He mencionado que Write-Error no produce un error de terminación de forma
predeterminada. Si especifica -ErrorAction Stop , Write-Error genera un error de
terminación que se puede controlar con catch .

PowerShell

Write-Error -Message "Houston, we have a problem." -ErrorAction Stop

Gracias a Lee Dailey por recordarnos el uso de -ErrorAction Stop de esta manera.

Cmdlet -ErrorAction Stop


Si especifica -ErrorAction Stop en cualquier función o cmdlet avanzados, todas las
instrucciones Write-Error se convierten en errores de terminación que detienen la
ejecución o que se pueden controlar mediante catch .

PowerShell

Start-Something -ErrorAction Stop

Para obtener más información sobre el parámetro ErrorAction, consulte


about_CommonParameters. Para obtener más información sobre la variable
$ErrorActionPreference , vea about_Preference_Variables.

Try/Catch
La forma en que funciona el control de excepciones en PowerShell (y muchos otros
lenguajes) es que primero se usa try para probar una sección del código y, si se
produce un error, puede usar catch para capturarlo. Este es un ejemplo rápido.
PowerShell

try
{
Start-Something
}
catch
{
Write-Output "Something threw an exception"
Write-Output $_
}

try
{
Start-Something -ErrorAction Stop
}
catch
{
Write-Output "Something threw an exception or used Write-Error"
Write-Output $_
}

El script catch solo se ejecuta si se produce un error de terminación. Si try se ejecuta


correctamente, se omite catch . Puede acceder a la información sobre la excepción del
bloque catch usando la variable $_ .

Try/Finally
En ocasiones, no es necesario controlar un error, pero sí es necesario ejecutar código
tanto si se produce una excepción como si no. Un script finally hace exactamente eso.

Eche un vistazo a este ejemplo:

PowerShell

$command = [System.Data.SqlClient.SqlCommand]::New(queryString, connection)


$command.Connection.Open()
$command.ExecuteNonQuery()
$command.Connection.Close()

Siempre que abra o se conecte a un recurso, debe cerrarlo. Si ExecuteNonQuery() inicia


una excepción, la conexión no se cierra. Este es el mismo código dentro de un bloque
try/finally .

PowerShell
$command = [System.Data.SqlClient.SqlCommand]::New(queryString, connection)
try
{
$command.Connection.Open()
$command.ExecuteNonQuery()
}
finally
{
$command.Connection.Close()
}

En este ejemplo, la conexión se cierra si hay un error. También se cierra si no hay ningún
error. El script finally se ejecuta cada vez.

Como no se captura la excepción, se sigue propagando a la pila de llamadas.

Try/Catch/Finally
Es absolutamente válido usar juntos catch y finally . Casi siempre usará uno u otro,
pero puede encontrarse con escenarios en los que se usen ambos.

$PSItem
Ahora que tenemos los aspectos básicos, podemos escarbar un poco más.

Dentro del bloque catch , hay una variable automática ( $PSItem o $_ ) de tipo
ErrorRecord que contiene los detalles sobre la excepción. Esta es una introducción

rápida a algunas de las propiedades principales.

En estos ejemplos, usé una ruta de acceso no válida en ReadAllText para generar esta
excepción.

PowerShell

[System.IO.File]::ReadAllText( '\\test\no\filefound.log')

PSItem.ToString()
Proporciona el mensaje más limpio para usar en el registro y la salida general.
ToString() se llama automáticamente si $PSItem se coloca dentro de una cadena.

PowerShell
catch
{
Write-Output "Ran into an issue: $($PSItem.ToString())"
}

catch
{
Write-Output "Ran into an issue: $PSItem"
}

$PSItem.InvocationInfo
Esta propiedad contiene información adicional recopilada por PowerShell sobre la
función o el script en el que se inició la excepción. Este es el elemento InvocationInfo
de la excepción de ejemplo que he creado.

PowerShell

PS> $PSItem.InvocationInfo | Format-List *

MyCommand : Get-Resource
BoundParameters : {}
UnboundArguments : {}
ScriptLineNumber : 5
OffsetInLine : 5
ScriptName : C:\blog\throwerror.ps1
Line : Get-Resource
PositionMessage : At C:\blog\throwerror.ps1:5 char:5
+ Get-Resource
+ ~~~~~~~~~~~~
PSScriptRoot : C:\blog
PSCommandPath : C:\blog\throwerror.ps1
InvocationName : Get-Resource

Aquí, los detalles importantes muestran el elemento ScriptName , el elemento Line del
código y el elemento ScriptLineNumber en el que se inició la invocación.

$PSItem.ScriptStackTrace
Esta propiedad muestra el orden de las llamadas de función que le han llevado al
código donde se generó la excepción.

PowerShell

PS> $PSItem.ScriptStackTrace
at Get-Resource, C:\blog\throwerror.ps1: line 13
at Start-Something, C:\blog\throwerror.ps1: line 5
at <ScriptBlock>, C:\blog\throwerror.ps1: line 18

Solo hago llamadas a funciones del mismo script, pero si se invocaran varios scripts, se
realizaría un seguimiento de las llamadas.

$PSItem.Exception
Esta es la excepción real que se inició.

$PSItem.Exception.Message
Este es el mensaje general que describe la excepción y es un buen punto de partida
para la solución de problemas. La mayoría de las excepciones tienen un mensaje
predeterminado, pero también se puede establecer en algo personalizado cuando se
inicia la excepción.

PowerShell

PS> $PSItem.Exception.Message

Exception calling "ReadAllText" with "1" argument(s): "The network path was
not found."

Este también es el mensaje que se devuelve al llamar a $PSItem.ToString() si no hay


uno establecido en ErrorRecord .

$PSItem.Exception.InnerException
Las excepciones pueden contener excepciones internas. Este suele ser el caso cuando el
código al que se llama captura una excepción e inicia una excepción diferente. La
excepción original se coloca dentro de la nueva excepción.

PowerShell

PS> $PSItem.Exception.InnerExceptionMessage
The network path was not found.

Más adelante volveremos a tratar este tema al hablar sobre el inicio repetido de
excepciones.

$PSItem.Exception.StackTrace
Es el elemento StackTrace de la excepción. Anteriormente mostré un elemento
ScriptStackTrace , pero este es para las llamadas a código administrado.

Output

at System.IO.FileStream.Init(String path, FileMode mode, FileAccess access,


Int32 rights, Boolean
useRights, FileShare share, Int32 bufferSize, FileOptions options,
SECURITY_ATTRIBUTES secAttrs,
String msgPath, Boolean bFromProxy, Boolean useLongPath, Boolean checkHost)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access,
FileShare share, Int32
bufferSize, FileOptions options, String msgPath, Boolean bFromProxy,
Boolean useLongPath, Boolean
checkHost)
at System.IO.StreamReader..ctor(String path, Encoding encoding, Boolean
detectEncodingFromByteOrderMarks,
Int32 bufferSize, Boolean checkHost)
at System.IO.File.InternalReadAllText(String path, Encoding encoding,
Boolean checkHost)
at CallSite.Target(Closure , CallSite , Type , String )

Solo se obtiene este seguimiento de la pila cuando se inicia el evento desde código
administrado. Voy a llamar directamente a una función de .NET Framework, así que eso
es todo lo que podemos ver en este ejemplo. Por lo general, cuando se examina un
seguimiento de la pila, se busca dónde se detiene el código y comienza la llamada del
sistema.

Trabajo con excepciones


Hay más excepciones que las propiedades básicas de excepción y sintaxis.

Captura de excepciones con tipo


Puede ser selectivo con las excepciones que capture. Las excepciones tienen un tipo y
puede especificar el tipo de excepción que desea capturar.

PowerShell

try
{
Start-Something -Path $path
}
catch [System.IO.FileNotFoundException]
{
Write-Output "Could not find $path"
}
catch [System.IO.IOException]
{
Write-Output "IO error with the file: $path"
}

El tipo de excepción se comprueba para cada bloque catch hasta que se encuentre uno
que coincida con la excepción. Es importante saber que las excepciones pueden heredar
de otras excepciones. En el ejemplo anterior, FileNotFoundException hereda de
IOException . Por lo tanto, si IOException fue primero, esta sería la excepción a la que se

llamaría. Solo se invoca un bloque catch aunque haya varias coincidencias.

Si tuviéramos una excepción System.IO.PathTooLongException , la excepción IOException


coincidiría, pero, si tuviéramos una excepción InsufficientMemoryException , nada la
capturaría y se propagaría arriba de la pila.

Captura de varios tipos a la vez


Es posible capturar varios tipos de excepción con la misma instrucción catch .

PowerShell

try
{
Start-Something -Path $path -ErrorAction Stop
}
catch [System.IO.DirectoryNotFoundException],
[System.IO.FileNotFoundException]
{
Write-Output "The path or file was not found: [$path]"
}
catch [System.IO.IOException]
{
Write-Output "IO error with the file: [$path]"
}

Le agradecemos a /u/Sheppard_Ra que nos haya sugerido este dato adicional.

Inicio de excepciones con tipo


Puede iniciar excepciones con tipo en PowerShell. En lugar de llamar a throw con una
cadena:

PowerShell
throw "Could not find: $path"

Use un acelerador de excepciones como este:

PowerShell

throw [System.IO.FileNotFoundException] "Could not find: $path"

Sin embargo, tendrá que especificar un mensaje cuando lo haga.

También puede crear una instancia de una excepción que se va a iniciar. El mensaje es
opcional cuando hace esto porque el sistema tiene mensajes predeterminados para
todas las excepciones integradas.

PowerShell

throw [System.IO.FileNotFoundException]::new()
throw [System.IO.FileNotFoundException]::new("Could not find path: $path")

Si no usa PowerShell 5.0 o posterior, debe utilizar el método New-Object anterior.

PowerShell

throw (New-Object -TypeName System.IO.FileNotFoundException )


throw (New-Object -TypeName System.IO.FileNotFoundException -ArgumentList
"Could not find path: $path")

Mediante una excepción con tipo, usted (u otros) puede capturar la excepción por el
tipo, como se ha mencionado en la sección anterior.

Error de escritura: excepción


Podemos agregar estas excepciones con tipo a Write-Error y todavía podemos usar
catch para capturar los errores por tipo de excepción. Use Write-Error como en estos

ejemplos:

PowerShell

# with normal message


Write-Error -Message "Could not find path: $path" -Exception
([System.IO.FileNotFoundException]::new()) -ErrorAction Stop

# With message inside new exception


Write-Error -Exception ([System.IO.FileNotFoundException]::new("Could not
find path: $path")) -ErrorAction Stop

# Pre PS 5.0
Write-Error -Exception ([System.IO.FileNotFoundException]"Could not find
path: $path") -ErrorAction Stop

Write-Error -Message "Could not find path: $path" -Exception (New-Object -


TypeName System.IO.FileNotFoundException) -ErrorAction Stop

A continuación, podemos capturarlo de la siguiente manera:

PowerShell

catch [System.IO.FileNotFoundException]
{
Write-Log $PSItem.ToString()
}

La lista grande de excepciones de .NET

He compilado una lista maestra con la ayuda de la comunidad de Reddit/r/PowerShell


que contiene cientos de excepciones de .NET para complementar esta entrada.

La lista grande de excepciones de .NET

Comencemos por buscar en esa lista las excepciones que podrían ser una buena opción
para mi situación. Debe intentar usar excepciones en el espacio de nombres System
base.

Las excepciones son objetos


Si empieza a usar muchas excepciones con tipo, recuerde que son objetos. Diferentes
excepciones tienen diferentes constructores y propiedades. Si examinamos la
documentación de FileNotFoundException para System.IO.FileNotFoundException ,
vemos que se puede pasar un mensaje y una ruta de acceso de archivo.

PowerShell

[System.IO.FileNotFoundException]::new("Could not find file", $path)

Además, tiene una propiedad FileName que expone esa ruta de acceso de archivo.

PowerShell
catch [System.IO.FileNotFoundException]
{
Write-Output $PSItem.Exception.FileName
}

Consulte la documentación de .NET para información sobre otros constructores y


propiedades de objeto.

Inicio repetido de una excepción


Si todo lo que va a hacer en el bloque catch es la acción throw con la misma excepción,
no use catch con ella. Solo debe usar catch con una excepción que planee controlar o
si va a realizar alguna acción cuando se produzca.

Hay ocasiones en las que querrá realizar una acción en una excepción, pero volver a
iniciar esta para que un elemento de nivel inferior pueda encargarse de ella. Podríamos
escribir un mensaje o registrar el problema cerca de donde lo detectamos, pero tratarlo
mejor arriba de la pila.

PowerShell

catch
{
Write-Log $PSItem.ToString()
throw $PSItem
}

Curiosamente, podemos llamar a throw desde dentro de catch y volver a iniciar la


excepción actual.

PowerShell

catch
{
Write-Log $PSItem.ToString()
throw
}

Queremos volver a iniciar la excepción para conservar la información de ejecución


original como el script de origen y el número de línea. Si se inicia una nueva excepción
en este punto, se oculta dónde comenzó.

Inicio repetido de una nueva excepción


Si captura una excepción, pero quiere iniciar una diferente, debe anidar la excepción
original dentro de la nueva. De esta manera, cualquier usuario de debajo de la pila
puede acceder a ella como $PSItem.Exception.InnerException .

PowerShell

catch
{
throw [System.MissingFieldException]::new('Could not access
field',$PSItem.Exception)
}

$PSCmdlet.ThrowTerminatingError()
Lo que no me gusta de usar throw para las excepciones sin procesar es que el mensaje
de error señala a la instrucción throw e indica que la línea es el lugar donde se
encuentra el problema.

Output

Unable to find the specified file.


At line:31 char:9
+ throw [System.IO.FileNotFoundException]::new()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [],
FileNotFoundException
+ FullyQualifiedErrorId : Unable to find the specified file.

Recibir el mensaje de error me dice que el script se ha interrumpido porque llamé a


throw en la línea 31 y este es un buen mensaje que deban ver los usuarios del script. No

les dice nada útil.

Dexter Dhami señaló que puedo usar ThrowTerminatingError() para corregirlo.

PowerShell

$PSCmdlet.ThrowTerminatingError(
[System.Management.Automation.ErrorRecord]::new(
([System.IO.FileNotFoundException]"Could not find $Path"),
'My.ID',
[System.Management.Automation.ErrorCategory]::OpenError,
$MyObject
)
)
Si damos por hecho que se llamó a ThrowTerminatingError() dentro de una función
llamada Get-Resource , este es el error que veremos.

Output

Get-Resource : Could not find C:\Program Files (x86)\Reference


Assemblies\Microsoft\Framework\.NETPortable\v4.6\System.IO.xml
At line:6 char:5
+ Get-Resource -Path $Path
+ ~~~~~~~~~~~~
+ CategoryInfo : OpenError: (:) [Get-Resource],
FileNotFoundException
+ FullyQualifiedErrorId : My.ID,Get-Resource

¿Ve cómo apunta a la función Get-Resource como el origen del problema? Esto indica al
usuario algo útil.

Dado que $PSItem es un elemento ErrorRecord , también podemos usar


ThrowTerminatingError de esta manera para volver a iniciarla.

PowerShell

catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}

Esto cambia el origen del error al cmdlet y oculta los elementos internos de la función a
los usuarios del cmdlet.

Try puede crear errores de terminación


Kirk Munro señala que algunas excepciones son solo errores de terminación cuando se
ejecutan dentro de un bloque try/catch . Este es el ejemplo que él me proporcionó que
genera una excepción de tiempo de ejecución de división por cero.

PowerShell

function Start-Something { 1/(1-1) }

Luego, se invoca así para ver cómo se genera el error y se envía el mensaje.

PowerShell
&{ Start-Something; Write-Output "We did it. Send Email" }

Sin embargo, al colocar ese mismo código dentro de un bloque try/catch , vemos que
sucede otra cosa.

PowerShell

try
{
&{ Start-Something; Write-Output "We did it. Send Email" }
}
catch
{
Write-Output "Notify Admin to fix error and send email"
}

Vemos que el error se convierte en un error de terminación y no genera el primer


mensaje. Lo que no me gusta de esto es que puede tener este código en una función y
actúa de forma diferente si alguien usa try/catch .

No he tenido problemas con esto, pero es una situación que puede darse.

$PSCmdlet.ThrowTerminatingError() dentro de try/catch


Un matiz de $PSCmdlet.ThrowTerminatingError() es que crea un error de terminación
dentro del cmdlet, pero se convierte en un error de no terminación después de salir de
él. Esto deja en manos del autor de la llamada de la función la decisión de cómo
controlar el error. Se puede volver a convertir en un error de terminación mediante -
ErrorAction Stop o si se llama desde try{...}catch{...} .

Plantillas de función públicas


Una última conclusión que saque de mi conversación con Kirk Munro era que coloca un
elemento try{...}catch{...} alrededor de cada bloque begin , process y end en todas
sus funciones avanzadas. En esos bloques catch genéricos, tiene una sola línea que usa
$PSCmdlet.ThrowTerminatingError($PSItem) para tratar todas las excepciones que

abandonan sus funciones.

PowerShell

function Start-Something
{
[CmdletBinding()]
param()

process
{
try
{
...
}
catch
{
$PSCmdlet.ThrowTerminatingError($PSItem)
}
}
}

Dado que todo está en una instrucción try dentro de sus funciones, todo funciona de
forma coherente. Esto también proporciona al usuario final errores limpios que ocultan
el código interno del error generado.

Trap
Me he centrado en el aspecto try/catch de las excepciones. Pero hay una característica
heredada que es necesario mencionar antes de terminar esta parte.

Un elemento trap se coloca en un script o en una función para capturar todas las
excepciones que se producen en ese ámbito. Cuando se produce una excepción, se
ejecuta el código de trap y, luego, continúa el código normal. Si se producen varias
excepciones, se llama a la captura una y otra vez.

PowerShell

trap
{
Write-Log $PSItem.ToString()
}

throw [System.Exception]::new('first')
throw [System.Exception]::new('second')
throw [System.Exception]::new('third')

Personalmente, nunca adopté este enfoque, pero puedo ver el valor en los scripts de
administrador o controlador que registran todas las excepciones y, luego, se siguen
ejecutando.

Comentarios de cierre
Agregar el control de excepciones adecuado a los scripts no solo hace que sean más
estables, sino que también facilita la solución de problemas de esas excepciones.

Pasé mucho tiempo hablando de throw porque es un concepto básico al hablar sobre el
control de excepciones. PowerShell también nos ha proporcionado Write-Error que
controla todas las situaciones en las que usaría throw . Por lo tanto, no debe pensar que
necesita usar throw después de leer esto.

Ahora que he tenido tiempo de escribir sobre el control de excepciones en este detalle,
voy a cambiar al uso de Write-Error -Stop para generar errores en mi código. También
voy a seguir los consejos de Kirk y a hacer de ThrowTerminatingError mi controlador de
excepciones goto para cada función.
Todo lo que le interesa sobre $null
Artículo • 13/04/2023

El valor $null de PowerShell puede parecer simple, pero tiene muchos matices.
Echemos un vistazo a $null para saber lo que ocurre cuando de forma inesperada se
encuentra con un valor $null .

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

¿Qué es NULL?
Puede pensar en NULL como un valor desconocido o vacío. Una variable tiene categoría
NULL hasta que se le asigna un valor o un objeto. Esto puede ser importante porque
hay algunos comandos que requieren un valor y generan errores si el valor es NULL.

$null de PowerShell
$null es una variable automática de PowerShell que se usa para representar un valor

NULL. Puede asignarla a variables y usarla en comparaciones y como marcador de


posición para NULL en una recopilación.

PowerShell trata $null como un objeto con un valor NULL. Si proviene de otro lenguaje,
verá que este proceso es diferente.

Ejemplos de $null
Siempre que intente usar una variable que no haya inicializado, el valor es $null . Esta es
una de las formas por las que los valores $null se cuelan en su código.

PowerShell

PS> $null -eq $undefinedVariable


True
Si escribe incorrectamente un nombre de variable, PowerShell lo percibe como una
variable diferente y el valor es $null .

La otra forma de encontrar valores $null es cuando proceden de otros comandos que
no proporcionan ningún resultado.

PowerShell

PS> function Get-Nothing {}


PS> $value = Get-Nothing
PS> $null -eq $value
True

Repercusión de $null
Los valores $null afectan al código de manera diferente dependiendo de dónde
aparezcan.

En cadenas
Si utiliza $null en una cadena, entonces es un valor en blanco (o una cadena vacía).

PowerShell

PS> $value = $null


PS> Write-Output "The value is $value"
The value is

Esta es una de las razones por las que me gusta poner corchetes alrededor de las
variables cuando se usan en los mensajes de registro. Es incluso más importante
identificar los límites de los valores de las variables cuando el valor está al final de la
cadena.

PowerShell

PS> $value = $null


PS> Write-Output "The value is [$value]"
The value is []

De este modo, las cadenas vacías y los valores $null son fáciles de identificar.

En ecuación numérica
Cuando se usa un valor $null en una ecuación numérica, los resultados no son válidos
si no dan un error. A veces, $null se evalúa como 0 y otras veces hace que todo el
resultado sea $null . Este es un ejemplo con multiplicación que proporciona 0 o $null
dependiendo del orden de los valores.

PowerShell

PS> $null * 5
PS> $null -eq ( $null * 5 )
True

PS> 5 * $null
0
PS> $null -eq ( 5 * $null )
False

En el lugar de una recopilación


Una recopilación le permite utilizar un índice para tener acceso a los valores. Si intenta
indizar en una recopilación que es realmente null , obtendrá este error: Cannot index
into a null array .

PowerShell

PS> $value = $null


PS> $value[10]
Cannot index into a null array.
At line:1 char:1
+ $value[10]
+ ~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : NullArray

Si tiene una recopilación pero intenta tener acceso a un elemento que no está en la
recopilación, obtendrá un resultado $null .

PowerShell

$array = @( 'one','two','three' )
$null -eq $array[100]
True

En el lugar de un objeto
Si intenta obtener acceso a una propiedad o subpropiedad de un objeto que no tiene la
propiedad especificada, obtendrá un valor $null igual que para una variable no
definida. No importa si la variable es $null o un objeto real en este caso.

PowerShell

PS> $null -eq $undefined.some.fake.property


True

PS> $date = Get-Date


PS> $null -eq $date.some.fake.property
True

Método en una expresión con valores NULL


La llamada a un método en un objeto $null produce RuntimeException .

PowerShell

PS> $value = $null


PS> $value.toString()
You cannot call a method on a null-valued expression.
At line:1 char:1
+ $value.tostring()
+ ~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull

Cada vez que veo la frase You cannot call a method on a null-valued expression , lo
primero que me fijo es los lugares en los que se llama a un método en una variable sin
buscar antes $null en ellos.

Búsqueda de $null
Es posible que haya observado que siempre coloco $null a la izquierda al buscar $null
en mis ejemplos. Lo hago a propósito y se acepta como procedimiento recomendado
de PowerShell. Hay algunos escenarios en los que si se coloca a la derecha no se
obtiene el resultado esperado.

Vea el ejemplo siguiente e intente predecir los resultados:

PowerShell
if ( $value -eq $null )
{
'The array is $null'
}
if ( $value -ne $null )
{
'The array is not $null'
}

Si no defino $value , el primero se evalúa como $true y nuestro mensaje es The array
is $null . La trampa aquí es que es posible crear un valor $value que permita que

ambos sean $false

PowerShell

$value = @( $null )

En este caso, $value es una matriz que contiene $null . -eq comprueba cada valor de la
matriz y devuelve el valor $null que coincida. Se evalúa como $false . -ne devuelve
todo lo que no coincide con $null y, en este caso, no hay ningún resultado (esto
también se evalúa como $false ). Ninguno de ellos es $true , aunque parezca que uno
de ellos debe serlo.

No solo podemos crear un valor que haga que ambos se evalúen como $false ; es
posible crear un valor en el que ambos se evalúen como $true . Mathias Jessen
(@IISResetMe) tiene una excelente publicación en la que se profundiza en este
escenario.

PSScriptAnalyzer y VSCode
El módulo PSScriptAnalyzer tiene una regla que busca este problema llamado
PSPossibleIncorrectComparisonWithNull .

PowerShell

PS> Invoke-ScriptAnalyzer ./myscript.ps1

RuleName Message
-------- -------
PSPossibleIncorrectComparisonWithNull $null should be on the left side of
equality comparisons.
Dado que VS Code usa también las reglas de PSScriptAnalyser, resalta o identifica esto
como un problema en el script.

Comprobación if simple
Una forma común para que los usuarios busquen un valor que no sea $null es usar una
instrucción if() simple sin la comparación.

PowerShell

if ( $value )
{
Do-Something
}

Si el valor es $null , se evalúa como $false . Resulta fácil de leer, pero fíjese en que esté
buscando exactamente lo que espera que busque. He leído esa línea de código como:

Si $value tiene un valor.

Pero eso no es todo. Esa línea está diciendo realmente:

Si $value no es $null , 0 o $false o una cadena o matriz vacía.

Este es un ejemplo más completo de esa instrucción.

PowerShell

if ( $null -ne $value -and


$value -ne 0 -and
$value -ne '' -and
($value -isnot [array] -or $value.Length -ne 0) -and
$value -ne $false )
{
Do-Something
}

Es absolutamente válido usar una comprobación básica if siempre que recuerde que
esos otros valores cuentan como $false y no solo que una variable tiene un valor.

Me encontré con este problema al refactorizar código hace unos días. Tenía una
comprobación de propiedad básica como esta.

PowerShell
if ( $object.property )
{
$object.property = $value
}

Quería asignar un valor a la propiedad del objeto solo si existiera. En la mayoría de los
casos, el objeto original tenía un valor que se evaluaría como $true en la instrucción
if . Pero se produjo un problema en el que, en ocasiones, el valor no se establecía.
Depuré el código y vi que el objeto tenía la propiedad, pero era un valor de cadena en
blanco. Esto impidió que se actualizara en algún caso con la lógica anterior. Por eso,
agregué una comprobación $null adecuada y todo funcionó.

PowerShell

if ( $null -ne $object.property )


{
$object.property = $value
}

Son pequeños errores como estos los que son difíciles de detectar y por los que tengo
que comprobar de forma agresiva los valores de $null .

$null.Count
Si intenta obtener acceso a una propiedad en un valor de $null , la propiedad también
es $null . La propiedad count es la excepción a esta regla.

PowerShell

PS> $value = $null


PS> $value.count
0

Cuando tiene un valor $null , count es 0 . PowerShell agrega esta propiedad especial.

[PSCustomObject] Count
Casi todos los objetos de PowerShell tienen esa propiedad count. Una excepción
importante es [PSCustomObject] en Windows PowerShell 5,.1 (esto se corrigió en
PowerShell 6.0). No tiene una propiedad count, por lo que obtiene un valor $null si
intenta usarla. Lo menciono aquí para que no intente usar .Count en lugar de una
comprobación $null .
La ejecución de este ejemplo en Windows PowerShell 5.1 y PowerShell 6.0 ofrece
resultados diferentes.

PowerShell

$value = [PSCustomObject]@{Name='MyObject'}
if ( $value.count -eq 1 )
{
"We have a value"
}

Null vacío
Hay un tipo especial de $null que actúa de manera diferente que los demás. Voy a
llamarlo el elemento $null vacío, pero es realmente
System.Management.Automation.Internal.AutomationNull. Este $null vacío es el que se
obtiene como resultado de una función o un bloque de script que no devuelve nada
(resultado nulo).

PowerShell

PS> function Get-Nothing {}


PS> $nothing = Get-Nothing
PS> $null -eq $nothing
True

Si lo compara con $null , obtiene un valor $null . Cuando se usa en una evaluación en
la que se requiere un valor, el valor siempre es $null . Pero si lo coloca dentro de una
matriz, se trata de la misma forma que una matriz vacía.

PowerShell

PS> $containempty = @( @() )


PS> $containnothing = @($nothing)
PS> $containnull = @($null)

PS> $containempty.count
0
PS> $containnothing.count
0
PS> $containnull.count
1

Puede incluso tener una matriz que contenga un valor $null y su count sea 1 . Pero si
coloca un resultado vacío dentro de una matriz, no se cuenta como un elemento. El
recuento es 0 .

Si trata el elemento $null vacío como una recopilación, estará vacía.

Si pasa un valor vacío a un parámetro de función que no está fuertemente tipado,


PowerShell convierte el valor nothing en un valor $null de manera predeterminada.
Esto significa que, dentro de la función, el valor se trata como $null en lugar del tipo
System.Management.Automation.Internal.AutomationNull.

Canalización
Donde se aprecia fundamentalmente la diferencia es en el uso de la canalización. Puede
canalizar un valor $null , pero no un valor $null vacío.

PowerShell

PS> $null | ForEach-Object{ Write-Output 'NULL Value' }


'NULL Value'
PS> $nothing | ForEach-Object{ Write-Output 'No Value' }

En función del código, debe tener en cuenta $null en la lógica.

Compruebe primero $null .

Filtre null en la canalización ( ... | Where {$null -ne $_} | ... ).


Adminístrelo en la función de canalización.

foreach
Una de mis características favoritas de foreach es que no se enumera en una
recopilación de $null .

PowerShell

foreach ( $node in $null )


{
#skipped
}

Esto me evita tener que comprobar $null en la recopilación antes de enumerarla. Si


tiene una recopilación de valores $null , $node todavía puede ser $null .
La instrucción foreach comenzó a funcionar de esta manera con PowerShell 3.0. Si tiene
una versión anterior, entonces este no es el caso. Se trata de uno de los cambios
importantes que se deben tener en cuenta al hacer posible la compatibilidad del código
con la versión 2.0.

Tipos de valor
Técnicamente, solo los tipos de referencia pueden ser $null . Sin embargo, PowerShell
es muy generoso y permite que las variables sean de cualquier tipo. Si decide establecer
un tipo de valor de forma inflexible, no puede ser $null . PowerShell convierte $null en
un valor predeterminado para muchos tipos.

PowerShell

PS> [int]$number = $null


PS> $number
0

PS> [bool]$boolean = $null


PS> $boolean
False

PS> [string]$string = $null


PS> $string -eq ''
True

Hay algunos tipos que no tienen una conversión válida desde $null . Estos tipos
generan un error Cannot convert null to type .

PowerShell

PS> [datetime]$date = $null


Cannot convert null to type "System.DateTime".
At line:1 char:1
+ [datetime]$date = $null
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : MetadataError: (:) [],
ArgumentTransformationMetadataException
+ FullyQualifiedErrorId : RuntimeException

Parámetros de función
El uso de valores con establecimiento inflexible de tipos en los parámetros de función es
muy común. En general, aprendemos a definir los tipos de nuestros parámetros, incluso
si tendemos a no definir los tipos de otras variables en nuestros scripts. Es posible que
ya tenga algunas variables con establecimiento inflexible de tipos en las funciones y que
no se haya dado cuenta.

PowerShell

function Do-Something
{
param(
[String] $Value
)
}

En cuanto establezca el tipo del parámetro como string , el valor nunca puede ser
$null . Es habitual comprobar si un valor es $null para ver si el usuario proporcionó un
valor o no.

PowerShell

if ( $null -ne $Value ){...}

$Value es una cadena vacía '' cuando no se proporciona ningún valor. En su lugar, use
la variable automática $PSBoundParameters.Value .

PowerShell

if ( $null -ne $PSBoundParameters.Value ){...}

$PSBoundParameters solo contiene los parámetros que se especificaron cuando se llamó

a la función. También puede utilizar el método ContainsKey para comprobar la


propiedad.

PowerShell

if ( $PSBoundParameters.ContainsKey('Value') ){...}

IsNotNullOrEmpty
Si el valor es una cadena, puede usar una función de cadena estática para comprobar si
el valor es $null o una cadena vacía al mismo tiempo.

PowerShell

if ( -not [string]::IsNullOrEmpty( $value ) ){...}


Con frecuencia uso esto cuando sé que el tipo de valor debe ser una cadena.

Cuando compruebo $null


Soy un escritor de scripts conservador. Cada vez que llamo a una función y la asigno a
una variable, compruebo si tiene valores $null .

PowerShell

$userList = Get-ADUser kevmar


if ($null -ne $userList){...}

Prefiero usar if o foreach antes que try/catch . No me entienda mal, sigo utilizando
try/catch mucho. Pero si puedo probar una condición de error o un conjunto vacío de
resultados, puedo permitir que mi control de excepciones sea para verdaderas
excepciones.

También suelo comprobar $null antes de indizar en un valor o llamar a métodos en un


objeto. Estas dos acciones producen un error en un objeto $null , por lo que me parece
importante validarlas primero. Ya he tratado estos escenarios anteriormente en esta
publicación.

Escenario sin resultados


Es importante saber que las distintas funciones y comandos controlan el escenario sin
resultados de forma diferente. Muchos comandos de PowerShell devuelven el valor
$null vacío y un error en la secuencia de error. Pero otros inician excepciones o
proporcionan un objeto de estado. Sigue siendo cosa suya saber de qué modo los
comandos que usa aborda los escenarios sin resultados y con errores.

Inicialización en $null
Un hábito que he adquirido es inicializar todas las variables antes de utilizarlas. En otros
lenguajes, es obligatorio hacerlo. En la parte superior de mi función o al escribir un
bucle foreach, defino todos los valores que estoy usando.

Este es un escenario en el que quiero detenerme un poco. Es un ejemplo de un error


que tuve que perseguir antes.

PowerShell
function Do-Something
{
foreach ( $node in 1..6 )
{
try
{
$result = Get-Something -ID $node
}
catch
{
Write-Verbose "[$result] not valid"
}

if ( $null -ne $result )


{
Update-Something $result
}
}
}

Aquí es de esperar que Get-Something devuelva un resultado o un $null vacío. Si se


produce un error, lo registramos. A continuación, comprobamos que obtuvimos un
resultado válido antes de procesarlo.

El error que se esconde en este código es cuando Get-Something produce una


excepción y no asigna un valor a $result . El problema ocurre antes de la asignación,
por lo que ni siquiera se asigna $null a la variable $result . $result todavía contiene el
$result válido anterior de otras iteraciones. Update-Something para ejecutar varias veces

en el mismo objeto en este ejemplo.

Establezco $result en $null justo dentro del bucle foreach antes de usarlo para mitigar
este problema.

PowerShell

foreach ( $node in 1..6 )


{
$result = $null
try
{
...

Problemas de ámbito
Esto también ayuda a mitigar los problemas de ámbito. En ese ejemplo, asignamos
valores a $result una y otra vez en un bucle. Sin embargo, dado que PowerShell
permite que los valores de variable de fuera de la función interfieran en el ámbito de la
función actual, su inicialización dentro de la función mitiga los errores que se pueden
producir de este modo.

Una variable no inicializada en la función no es $null si está establecida en un valor en


un ámbito primario. El ámbito primario podría ser otra función que llama a la función y
usa los mismos nombres de variable.

Si tomo ese mismo ejemplo Do-something y quito el bucle, terminaría con algo parecido
a este ejemplo:

PowerShell

function Invoke-Something
{
$result = 'ParentScope'
Do-Something
}

function Do-Something
{
try
{
$result = Get-Something -ID $node
}
catch
{
Write-Verbose "[$result] not valid"
}

if ( $null -ne $result )


{
Update-Something $result
}
}

Si la llamada a Get-Something produce una excepción, la comprobación de $null


encuentra $result en Invoke-Something . La inicialización del valor dentro de la función
soluciona este problema.

Asignar nombres a las variables es difícil y es habitual que un autor use los mismos
nombres de variable en varias funciones. Sé que utilizo $node , $result y $data todo el
tiempo. Por lo tanto, es muy fácil que los valores de distintos ámbitos se muestren en
lugares donde no deberían estar.

Redirección de la salida a $null


He estado hablando acerca de los valores $null durante todo este artículo, pero el
tema queda incompleto si no se menciona la redirección de la salida a $null . Hay
ocasiones en las que tiene comandos que generan información u objetos que desea
suprimir. La redirección de la salida a $null se ocupa de ello.

Out-Null
El comando Out-Null es la forma integrada de redirigir los datos de canalización a
$null .

PowerShell

New-Item -Type Directory -Path $path | Out-Null

Asignación a $null
Puede asignar los resultados de un comando a $null para obtener el mismo efecto que
usar Out-Null .

PowerShell

$null = New-Item -Type Directory -Path $path

Dado que $null es un valor constante, nunca se puede sobrescribir. No me gusta el


modo en el que se ve en el código, pero suele ser más rápido que Out-Null .

Redirección a $null
También puede usar el operador de redireccionamiento para enviar los resultados a
$null .

PowerShell

New-Item -Type Directory -Path $path > $null

Si está tratando con ejecutables de línea de comandos que se generan en los diferentes
flujos. Puede redirigir todos los flujos de salida a $null como se indica a continuación:

PowerShell

git status *> $null


Resumen
He tratado gran cantidad de aspectos y sé que este artículo está más fragmentado que
la mayoría de mis temas en profundidad. Esto se debe a que los valores de $null
pueden aparecer en muchos lugares diferentes de PowerShell y todos los matices son
específicos del lugar donde los encuentre. Espero que después de haberlo leído
entienda mejor $null y conozca los escenarios más complejos con los que puede
encontrarse.
Todo lo que le interesa saber sobre
ShouldProcess
Artículo • 13/04/2023

Las funciones de PowerShell tienen varias características que mejoran


considerablemente el modo en que los usuarios interactúan con ellas. Una característica
importante que a menudo se pasa por alto es la compatibilidad con -WhatIf y -
Confirm , y que es fácil de agregar a las funciones. En este artículo, profundizaremos en
la implementación de esta característica.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

Se trata de una característica sencilla que puede habilitar en sus funciones para
proporcionar una red de seguridad a los usuarios que la necesiten. No hay nada más
aterrador que ejecutar un comando que sabe que puede ser peligroso por primera vez.
La opción de ejecutarlo con -WhatIf puede suponer una gran diferencia.

CommonParameters
Antes de echar un vistazo a la implementación de estos parámetros comunes, deseo
echar un vistazo a cómo se usan.

Uso de -WhatIf
Cuando un comando admite el parámetro -WhatIf , le permite ver lo que habría hecho
el comando en lugar de realizar cambios. Resulta interesante probar el impacto de un
comando, especialmente antes de hacer algo destructivo.

PowerShell

PS C:\temp> Get-ChildItem
Directory: C:\temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 4/19/2021 8:59 AM 0 importantfile.txt
-a---- 4/19/2021 8:58 AM 0 myfile1.txt
-a---- 4/19/2021 8:59 AM 0 myfile2.txt

PS C:\temp> Remove-Item -Path .\myfile1.txt -WhatIf


What if: Performing the operation "Remove File" on target
"C:\Temp\myfile1.txt".

Si el comando implementa ShouldProcess correctamente, debería mostrar todos los


cambios que habría realizado. A continuación se muestra un ejemplo de uso de un
carácter comodín para eliminar varios archivos.

PowerShell

PS C:\temp> Remove-Item -Path * -WhatIf


What if: Performing the operation "Remove File" on target
"C:\Temp\myfile1.txt".
What if: Performing the operation "Remove File" on target
"C:\Temp\myfile2.txt".
What if: Performing the operation "Remove File" on target
"C:\Temp\importantfile.txt".

Uso de -Confirm
Los comandos que admiten -WhatIf también admiten -Confirm . Esto le brinda la
oportunidad de confirmar una acción antes de realizarla.

PowerShell

PS C:\temp> Remove-Item .\myfile1.txt -Confirm

Confirm
Are you sure you want to perform this action?
Performing the operation "Remove File" on target "C:\Temp\myfile1.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

En este caso, tiene varias opciones que le permiten continuar, omitir un cambio o
detener el script. El mensaje de ayuda describe cada una de estas opciones de este
modo.

Output

Y - Continue with only the next step of the operation.


A - Continue with all the steps of the operation.
N - Skip this operation and proceed with the next operation.
L - Skip this operation and all subsequent operations.
S - Pause the current pipeline and return to the command prompt. Type "exit"
to resume the pipeline.
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

Localización
Este mensaje se localiza en PowerShell para que el idioma cambie según el idioma del
sistema operativo. Esto es otro elemento del que PowerShell se ocupa
automáticamente.

Parámetros de modificador
Vamos a echar un vistazo rápido a cómo pasar un valor a un parámetro de modificador.
La razón principal por la que trato este aspecto es que es frecuente querer pasar valores
de parámetro a las funciones que llama.

El primer enfoque es una sintaxis de parámetro específica que se puede usar para todos
los parámetros, pero que en gran medida se usa para los parámetros de modificador.
Especifique un signo de dos puntos para adjuntar un valor al parámetro.

PowerShell

Remove-Item -Path:* -WhatIf:$true

Puede hacer lo mismo con una variable.

PowerShell

$DoWhatIf = $true
Remove-Item -Path * -WhatIf:$DoWhatIf

El segundo enfoque es usar una tabla hash para expandir el valor.

PowerShell

$RemoveSplat = @{
Path = '*'
WhatIf = $true
}
Remove-Item @RemoveSplat

Si no está familiarizado con las tablas hash o la expansión, tengo otro artículo que trata
todo lo que le interesa saber acerca de las tablas hash.
SupportsShouldProcess
El primer paso para habilitar la compatibilidad con -WhatIf y -Confirm es especificar
SupportsShouldProcess en el elemento CmdletBinding de la función.

PowerShell

function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
Remove-Item .\myfile1.txt
}

Al especificar SupportsShouldProcess de esta manera, ahora podemos llamar a nuestra


función con -WhatIf (o -Confirm ).

PowerShell

PS> Test-ShouldProcess -WhatIf


What if: Performing the operation "Remove File" on target
"C:\Temp\myfile1.txt".

Observe que no he creado ningún parámetro llamado -WhatIf . Si se especifica


SupportsShouldProcess , se crea automáticamente. Cuando se especifica el parámetro -

WhatIf en Test-ShouldProcess , algunas cosas a las que llamamos también realizan el

procesamiento de -WhatIf .

Confiar pero verificar


Existe cierto peligro en confiar en que todo lo que llama aquí hereda valores -WhatIf .
Para el resto de los ejemplos, voy a suponer que no funciona y ser muy explícito al hacer
llamadas a otros comandos. Le recomiendo que haga lo mismo.

PowerShell

function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()
Remove-Item .\myfile1.txt -WhatIf:$WhatIfPreference
}

Revisaremos los matices más adelante, una vez que tenga una mejor comprensión de
todas las piezas en juego.
$PSCmdlet.ShouldProcess
El método que permite implementar SupportsShouldProcess es
$PSCmdlet.ShouldProcess . Llame a $PSCmdlet.ShouldProcess(...) para ver si debe

procesar alguna lógica y PowerShell se encarga del resto. Comencemos con un ejemplo:

PowerShell

function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()

$file = Get-ChildItem './myfile1.txt'


if($PSCmdlet.ShouldProcess($file.Name)){
$file.Delete()
}
}

La llamada a $PSCmdlet.ShouldProcess($file.name) comprueba -WhatIf (y el parámetro


-Confirm ) y, a continuación se ocupa de ello según corresponda. El elemento -WhatIf
hace que ShouldProcess genere una descripción del cambio y devuelva $false :

PowerShell

PS> Test-ShouldProcess -WhatIf


What if: Performing the operation "Test-ShouldProcess" on target
"myfile1.txt".

Una llamada mediante -Confirm pausa el script y pregunta al usuario si desea continuar.
Devuelve $true si el usuario seleccionó Y .

PowerShell

PS> Test-ShouldProcess -Confirm


Confirm
Are you sure you want to perform this action?
Performing the operation "Test-ShouldProcess" on target "myfile1.txt".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

Una característica impresionante de $PSCmdlet.ShouldProcess es que se duplica como


salida detallada. Me ayuda muchísimo habitualmente al implementar ShouldProcess .

PowerShell
PS> Test-ShouldProcess -Verbose
VERBOSE: Performing the operation "Test-ShouldProcess" on target
"myfile1.txt".

Sobrecargas
Hay algunas sobrecargas diferentes para $PSCmdlet.ShouldProcess con distintos
parámetros para personalizar los mensajes. Ya hemos visto el primero en el ejemplo
anterior. Profundicemos en este aspecto.

PowerShell

function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()

if($PSCmdlet.ShouldProcess('TARGET')){
# ...
}
}

Esto produce una salida que incluye el nombre de la función y el destino (valor del
parámetro).

PowerShell

What if: Performing the operation "Test-ShouldProcess" on target "TARGET".

Al especificar un segundo parámetro como operación, se usa el valor de la operación en


lugar del nombre de la función en el mensaje.

PowerShell

## $PSCmdlet.ShouldProcess('TARGET','OPERATION')
What if: Performing the operation "OPERATION" on target "TARGET".

La opción siguiente consiste en especificar tres parámetros para personalizar el mensaje


por completo. Cuando se usan tres parámetros, el primero es el mensaje completo. Los
dos segundos parámetros se siguen usando en la salida del mensaje de -Confirm .

PowerShell

## $PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION')
What if: MESSAGE
Referencia rápida de parámetro
Por si hubiera llegado aquí únicamente para averiguar qué parámetros debe usar,
mostramos a continuación una referencia rápida en la que se muestra de qué manera
los parámetros cambian el mensaje en los diferentes escenarios de -WhatIf .

PowerShell

## $PSCmdlet.ShouldProcess('TARGET')
What if: Performing the operation "FUNCTION_NAME" on target "TARGET".

## $PSCmdlet.ShouldProcess('TARGET','OPERATION')
What if: Performing the operation "OPERATION" on target "TARGET".

## $PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION')
What if: MESSAGE

Yo suelo usar el que tiene dos parámetros.

ShouldProcessReason
Tenemos una cuarta sobrecarga que es más avanzada que las otras. Permite obtener la
razón por la que se ha ejecutado ShouldProcess . Únicamente se trata aquí para que el
tema quede completo, porque simplemente podemos verificar si $WhatIfPreference es
$true en su lugar.

PowerShell

$reason = ''
if($PSCmdlet.ShouldProcess('MESSAGE','TARGET','OPERATION',[ref]$reason)){
Write-Output "Some Action"
}
$reason

Tenemos que pasar la variable $reason al cuarto parámetro como una variable de
referencia con [ref] . ShouldProcess rellena $reason con el valor None o WhatIf . No he
dicho que esto fuera útil, y nunca he tenido motivo para usarlo.

Dónde colocarlo
Utilice ShouldProcess para que los scripts sean más seguros. De este modo, se usa
cuando los scripts están realizando cambios. Me gusta colocar la llamada
$PSCmdlet.ShouldProcess lo más cerca posible del cambio.

PowerShell

## general logic and variable work


if ($PSCmdlet.ShouldProcess('TARGET','OPERATION')){
# Change goes here
}

Si estoy procesando una recopilación de elementos, lo llamo para cada elemento. De


este modo, la llamada se coloca dentro del bucle foreach.

PowerShell

foreach ($node in $collection){


# general logic and variable work
if ($PSCmdlet.ShouldProcess($node,'OPERATION')){
# Change goes here
}
}

La razón por la que coloco ShouldProcess estrechamente alrededor del cambio es que
quiero que se ejecute la mayor cantidad de código posible cuando se especifica -
WhatIf . Deseo que la configuración y la validación se ejecuten, si es posible, para que el
usuario pueda ver esos errores.

También me gusta usarlo en las pruebas de Pester que validan mis proyectos. Si tengo
un fragmento de lógica que es difícil de simular en Pester, a menudo puedo
encapsularlo en ShouldProcess y llamarlo con -WhatIf en mis pruebas. Es mejor probar
parte del código que nada de él.

$WhatIfPreference
La primera variable de preferencia que tenemos es $WhatIfPreference . Es $false de
manera predeterminada. Si se establece en $true , la función se ejecuta como si se
hubiera especificado -WhatIf . Si establece esta configuración en la sesión, todos los
comandos ejecutarán -WhatIf .

Cuando llama a una función con -WhatIf , el valor de $WhatIfPreference se establece en


$true dentro del ámbito de la función.

ConfirmImpact
La mayoría de mis ejemplos son para -WhatIf , pero hasta ahora todo funciona también
con -Confirm para preguntar al usuario. Puede establecer el elemento ConfirmImpact de
la función en un valor alto y preguntar al usuario como si se hubiera llamado con -
Confirm .

PowerShell

function Test-ShouldProcess {
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param()

if ($PSCmdlet.ShouldProcess('TARGET')){
Write-Output "Some Action"
}
}

Esta llamada a Test-ShouldProcess está llevando a cabo la acción de -Confirm debido al


impacto de High .

PowerShell

PS> Test-ShouldProcess

Confirm
Are you sure you want to perform this action?
Performing the operation "Test-ShouldProcess" on target "TARGET".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): y
Some Action

El problema obvio es que ahora es más difícil de usar en otros scripts sin preguntar al
usuario. En este caso, podemos pasar $false a -Confirm para suprimir el aviso.

PowerShell

PS> Test-ShouldProcess -Confirm:$false


Some Action

Explicaré cómo agregar compatibilidad con -Force en una sección posterior.

$ConfirmPreference
$ConfirmPreference es una variable automática que controla cuándo ConfirmImpact le

pide que confirme la ejecución. Estos son los valores posibles para $ConfirmPreference y
ConfirmImpact .

High
Medium

Low

None

Con estos valores, puede especificar diferentes niveles de impacto para cada función. Si
tiene $ConfirmPreference establecido en un valor superior a ConfirmImpact , no se le
pedirá que confirme la ejecución.

De forma predeterminada, $ConfirmPreference está definido en High y ConfirmImpact


está Medium . Si desea que la función pregunte automáticamente al usuario, establezca
ConfirmImpact en High . De lo contrario, configúrelo en Medium si es destructivo y use

Low si el comando siempre se ejecuta de manera segura en producción. Si lo establece


en none , no se le preguntará aunque se haya especificado -Confirm (pero seguirá
ofreciendo compatibilidad con -WhatIf ).

Cuando llama a una función con -Confirm , el valor de $ConfirmPreference se establece


en Low dentro del ámbito de la función.

Supresión de mensajes de confirmación anidados


Las funciones a las que se llama pueden seleccionar $ConfirmPreference . Esto puede
crear escenarios en los que agrega un mensaje de confirmación y la función a la que
llama también le pregunta al usuario.

Lo que suelo hacer es especificar -Confirm:$false en los comandos a los que llamo
cuando ya me he ocupado del mensaje.

PowerShell

function Test-ShouldProcess {
[CmdletBinding(SupportsShouldProcess)]
param()

$file = Get-ChildItem './myfile1.txt'


if($PSCmdlet.ShouldProcess($file.Name)){
Remove-Item -Path $file.FullName -Confirm:$false
}
}
Esto nos lleva a una advertencia anterior: Hay matices en relación a los casos en que -
WhatIf no se pasa a una función y los casos en que -Confirm se pasa a una función.
Prometo volver sobre ello más adelante.

$PSCmdlet.ShouldContinue
Si necesita más control de lo que proporciona ShouldProcess , puede desencadenar el
aviso directamente con ShouldContinue . ShouldContinue omite $ConfirmPreference ,
ConfirmImpact , -Confirm , $WhatIfPreference y -WhatIf porque genera la advertencia

cada vez que se ejecuta.

A simple vista, es fácil confundir ShouldProcess y ShouldContinue . Yo me acuerdo de


usar ShouldProcess porque el parámetro se llama SupportsShouldProcess en
CmdletBinding . Debe usar ShouldProcess en casi todos los escenarios. Esa es la razón
por la que he tratado ese método primero.

Veamos a ShouldContinue en acción.

PowerShell

function Test-ShouldContinue {
[CmdletBinding()]
param()

if($PSCmdlet.ShouldContinue('TARGET','OPERATION')){
Write-Output "Some Action"
}
}

Nos proporciona un mensaje más sencillo con menos opciones.

PowerShell

Test-ShouldContinue

Second
TARGET
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"):

El problema más importante con ShouldContinue es que requiere que el usuario lo


ejecute de forma interactiva porque siempre le pregunta. Siempre debe crear
herramientas que puedan utilizar otros scripts. La manera de hacerlo es mediante la
implementación de -Force . Volveremos a este idea más adelante.
Sí a todo
Esto se controla automáticamente con ShouldProcess , pero tenemos que hacer más
cosas para ShouldContinue . Hay una segunda sobrecarga de método en la que tenemos
que pasar algunos valores por referencia para controlar la lógica.

PowerShell

function Test-ShouldContinue {
[CmdletBinding()]
param()

$collection = 1..5
$yesToAll = $false
$noToAll = $false

foreach($target in $collection) {

$continue = $PSCmdlet.ShouldContinue(
"TARGET_$target",
'OPERATION',
[ref]$yesToAll,
[ref]$noToAll
)

if ($continue){
Write-Output "Some Action [$target]"
}
}
}

He agregado un bucle foreach y una recopilación para mostrarlo en acción. He extraído


la llamada ShouldContinue de la instrucción if para que sea más fácil de leer. La
llamada a un método con cuatro parámetros comienza a ponerse un poco fea, pero he
tratado de que tenga un aspecto lo más limpio posible.

Implementación de -Force
ShouldProcess y ShouldContinue necesitan implementar -Force de manera diferente. El

truco para estas implementaciones es que ShouldProcess se debe ejecutar siempre,


pero ShouldContinue no se debería ejecutar si se especifica -Force .

ShouldProcess -Force
Si establece ConfirmImpact en high , lo primero que los usuarios van a intentar es
suprimirlo con -Force . Eso es lo primero que hago en cualquier caso.

PowerShell

Test-ShouldProcess -Force
Error: Test-ShouldProcess: A parameter cannot be found that matches
parameter name 'force'.

Si lo recuerda de la sección ConfirmImpact , en realidad tienen que llamarlo así:

PowerShell

Test-ShouldProcess -Confirm:$false

No todos los usuarios saben que necesitan hacerlo y -Force no suprime


ShouldContinue . Por tanto, debemos implementar -Force para que nuestros usuarios lo

vean claro. Echemos un vistazo aquí a este ejemplo completo:

PowerShell

function Test-ShouldProcess {
[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param(
[Switch]$Force
)

if ($Force -and -not $Confirm){


$ConfirmPreference = 'None'
}

if ($PSCmdlet.ShouldProcess('TARGET')){
Write-Output "Some Action"
}
}

Agregamos nuestro propio modificador -Force como parámetro. El parámetro -


Confirm se agrega automáticamente al usar SupportsShouldProcess en CmdletBinding .

PowerShell

[CmdletBinding(
SupportsShouldProcess,
ConfirmImpact = 'High'
)]
param(
[Switch]$Force
)

Céntrese en la lógica de -Force aquí:

PowerShell

if ($Force -and -not $Confirm){


$ConfirmPreference = 'None'
}

Si el usuario especifica -Force , queremos suprimir el mensaje de confirmación a menos


que también especifique -Confirm . Esto permite a un usuario forzar un cambio pero aún
así confirmar el cambio. A continuación, se establece $ConfirmPreference en el ámbito
local. Ahora, al usar el parámetro -Force se establece temporalmente
$ConfirmPreference en Ninguno, deshabilitando la solicitud de confirmación.

PowerShell

if ($PSCmdlet.ShouldProcess('TARGET')){
Write-Output "Some Action"
}

Si alguien especifica -Force y -WhatIf , -WhatIf debe tener prioridad. Este enfoque
conserva el procesamiento de -WhatIf porque ShouldProcess siempre se ejecuta.

No agregue una comprobación para el valor $Force dentro de la instrucción if con


ShouldProcess . Es un antipatrón para este escenario específico, aunque eso es lo que les

muestro en la siguiente sección para ShouldContinue .

ShouldContinue -Force
Esta es la manera correcta de implementar -Force con ShouldContinue .

PowerShell

function Test-ShouldContinue {
[CmdletBinding()]
param(
[Switch]$Force
)

if($Force -or $PSCmdlet.ShouldContinue('TARGET','OPERATION')){


Write-Output "Some Action"
}
}

Al colocar $Force a la izquierda del operador -or , se evalúa primero. Al escribirlo de


esta manera, se cortocircuita la ejecución de la instrucción if . Si $force es $true , no se
ejecuta ShouldContinue .

PowerShell

PS> Test-ShouldContinue -Force


Some Action

No es necesario preocuparse por -Confirm o -WhatIf en este escenario porque no son


compatibles con ShouldContinue . Esta es la razón por la que debe administrarse de
manera diferente que ShouldProcess .

Problemas de ámbito
Se supone que el uso de -WhatIf y -Confirm se aplica a todo el contenido de las
funciones y a todo lo que llaman. Para ello, se establece $WhatIfPreference en $true o
se establece $ConfirmPreference en Low en el ámbito local de la función. Cuando se
llama a otra función, las llamadas a ShouldProcess usan esos valores.

Realmente funciona correctamente la mayor parte del tiempo. Cada vez que se llama a
un cmdlet integrado o a una función en el mismo ámbito, funciona. También funciona
cuando se llama a un script o una función en un módulo de script desde la consola.

El único lugar en el que no funciona es cuando un script o un módulo de script llama a


una función en otro módulo de script. Es posible que esto no parezca un problema
importante, pero la mayoría de los módulos que crea o extrae de PSGallery son módulos
de script.

El problema principal es que los módulos de script no heredan los valores de


$WhatIfPreference o $ConfirmPreference (y otros) cuando se llaman desde funciones de

otros módulos de script.

La mejor manera de resumir esto como regla general es que funciona correctamente
para módulos binarios y nunca debe confiar en que funcione para módulos de script. Si
no está seguro, pruébelo o simplemente asuma que no funciona correctamente.
Personalmente, creo que es muy peligroso porque crea escenarios en los que agrega
compatibilidad con -WhatIf a varios módulos que funcionan correctamente de forma
aislada, pero no funcionan correctamente cuando se llaman entre sí.

Tenemos un RFC de GitHub trabajando para solucionar este problema. Consulte


Propagación de las preferencias de ejecución más allá del ámbito del módulo de
script para obtener más detalles.

Conclusión
Tengo que buscar cómo usar ShouldProcess cada vez que lo necesito. Me llevó mucho
tiempo distinguir ShouldProcess de ShouldContinue . Casi siempre tengo buscar los
parámetros que quiero usar. Por lo tanto, no se preocupe si se sigue confundiendo de
vez en cuando. Este artículo estará aquí cuando lo necesite. Estoy seguro de que yo
mismo lo consultaré con frecuencia.

Si le gustó esta publicación, comparta sus reflexiones conmigo en Twitter mediante el


vínculo siguiente. Siempre me gusta escuchar a personas que obtienen valor de mi
contenido.
Escritura de Progress en varios
subprocesos con Foreach Parallel
Artículo • 13/04/2023

Desde PowerShell 7.0, es posible trabajar en varios subprocesos simultáneamente


mediante el parámetro Parallel en el cmdlet Foreach-Object. No obstante, la supervisión
del progreso de estos subprocesos puede suponer un reto. Normalmente, puede
supervisar el progreso de un proceso mediante Write-Progress. Pero, debido a que
PowerShell usa un espacio de ejecución independiente para cada subproceso al emplear
Parallel, informar del progreso al host no es tan sencillo como el uso normal de Write-
Progress .

Uso de una tabla hash sincronizada para


realizar un seguimiento del progreso
Al escribir el progreso desde varios subprocesos, el seguimiento resulta difícil porque, al
ejecutar procesos paralelos en PowerShell, cada uno tiene su propio espacio de
ejecución. Para evitar esto, puede usar una tabla hash sincronizada. Una tabla hash
sincronizada es una estructura de datos segura para subprocesos que varios de ellos
pueden modificar simultáneamente sin que se produzca un error.

Configurar
Uno de los inconvenientes de este enfoque es que toma una configuración algo
compleja para asegurarse de que todo se ejecuta sin errores.

PowerShell

$dataset = @(
@{
Id = 1
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 2
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 3
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 4
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 5
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
)

# Create a hashtable for process.


# Keys should be ID's of the processes
$origin = @{}
$dataset | Foreach-Object {$origin.($_.id) = @{}}

# Create synced hashtable


$sync = [System.Collections.Hashtable]::Synchronized($origin)

En esta sección se crean tres estructuras de datos distintas, para tres propósitos
diferentes.

La variable $dataSet almacena una matriz de tablas hash que se usa para coordinar los
pasos siguientes sin el riesgo de que se modifiquen. Si se modifica una colección de
objetos mientras se recorre en iteración, se producirá un error en PowerShell. Debe
mantener la colección de objetos en el bucle independiente de los objetos que se van a
modificar. La clave Id de las tablas hash es el identificador de un proceso ficticio. La
clave Wait simula la carga de trabajo de los procesos ficticios de los que se realiza un
seguimiento.

La variable $origin almacena una tabla hash anidada, en la que cada clave es uno de
los identificadores del proceso ficticio. A continuación, se usa para hidratar la tabla hash
sincronizada almacenada en la variable $sync . La variable $sync es responsable de
notificar el progreso al espacio de ejecución primario, que muestra el progreso.

Ejecución de los procesos


En esta sección se ejecutan los procesos con varios subprocesos y se crean algunos de
los resultados que se usan para mostrar el progreso.

PowerShell

$job = $dataset | Foreach-Object -ThrottleLimit 3 -AsJob -Parallel {


$syncCopy = $using:sync
$process = $syncCopy.$($PSItem.Id)

$process.Id = $PSItem.Id
$process.Activity = "Id $($PSItem.Id) starting"
$process.Status = "Processing"
# Fake workload start up that takes x amount of time to complete
start-sleep -Milliseconds ($PSItem.wait*5)

# Process. update activity


$process.Activity = "Id $($PSItem.id) processing"
foreach ($percent in 1..100)
{
# Update process on status
$process.Status = "Handling $percent/100"
$process.PercentComplete = (($percent / 100) * 100)

# Fake workload that takes x amount of time to complete


Start-Sleep -Milliseconds $PSItem.Wait
}

# Mark process as completed


$process.Completed = $true
}

Los procesos ficticios se envían a Foreach-Object y se inician como trabajos. El valor de


ThrottleLimit se establece en 3 para resaltar la ejecución de varios procesos en una cola.
Los trabajos se almacenan en la variable $job , que nos permite saber cuándo se
completan todos los procesos más adelante.

Al utilizar la instrucción using: para hacer referencia a una variable de ámbito principal
en PowerShell, no puede usar expresiones para que sea dinámica. Por ejemplo, si ha
intentado crear la variable $process de este modo ( $process =
$using:sync.$($PSItem.id) ), se producirá un error en el que se le indicará que no puede
utilizar expresiones en ese lugar. Por lo tanto, creamos la variable $syncCopy para poder
hacer referencia a la variable $sync y modificarla sin el riesgo de que se produzca un
error.

A continuación, creamos una tabla hash para representar el progreso del proceso
actualmente en el bucle con la variable $process . Para ello, hacemos referencia a las
claves de la tabla hash sincronizadas. Las claves Activity y Status se utilizan como
valores de parámetro para que Write-Progress muestre el estado de un proceso ficticio
determinado en la sección siguiente.

El bucle foreach solo es una forma de simular el funcionamiento del proceso y es


aleatorio en función del atributo $dataSet Wait para establecer Start-Sleep con
milisegundos. La forma de calcular el progreso del proceso puede variar.

Vista del progreso de varios procesos


Ahora que los procesos ficticios se están ejecutando como trabajos, podemos empezar
a escribir el progreso de los procesos en la ventana de PowerShell.

PowerShell

while($job.State -eq 'Running')


{
$sync.Keys | Foreach-Object {
# If key is not defined, ignore
if(![string]::IsNullOrEmpty($sync.$_.keys))
{
# Create parameter hashtable to splat
$param = $sync.$_

# Execute Write-Progress
Write-Progress @param
}
}

# Wait to refresh to not overload gui


Start-Sleep -Seconds 0.1
}

La variable $job contiene el trabajo principal y tiene un trabajo secundario para cada
uno de los procesos ficticios. Mientras haya algún trabajo secundario en ejecución, el
valor de State del trabajo principal será "Running". Esto nos permite usar el bucle while
para actualizar continuamente el progreso de todos los procesos hasta que finalicen.

Dentro del bucle while, se recorren todas las claves de la variable $sync . Dado que se
trata de una tabla hash sincronizada, se actualiza constantemente, pero todavía se
puede acceder a ella sin que se produzcan errores.

Se realiza una comprobación para asegurarse de que el proceso del que se está
informando se está ejecutando realmente con el método IsNullOrEmpty() . Si el proceso
no se ha iniciado, el bucle no informará sobre él y pasará al siguiente hasta que llegue a
un proceso que se haya iniciado. Si se inicia el proceso, se usa la tabla hash de la clave
actual para expandir los parámetros a Write-Progress .

Ejemplo completo
PowerShell

# Example workload
$dataset = @(
@{
Id = 1
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 2
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 3
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 4
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
@{
Id = 5
Wait = 3..10 | get-random | Foreach-Object {$_*100}
}
)

# Create a hashtable for process.


# Keys should be ID's of the processes
$origin = @{}
$dataset | Foreach-Object {$origin.($_.id) = @{}}

# Create synced hashtable


$sync = [System.Collections.Hashtable]::Synchronized($origin)

$job = $dataset | Foreach-Object -ThrottleLimit 3 -AsJob -Parallel {


$syncCopy = $using:sync
$process = $syncCopy.$($PSItem.Id)

$process.Id = $PSItem.Id
$process.Activity = "Id $($PSItem.Id) starting"
$process.Status = "Processing"

# Fake workload start up that takes x amount of time to complete


start-sleep -Milliseconds ($PSItem.wait*5)

# Process. update activity


$process.Activity = "Id $($PSItem.id) processing"
foreach ($percent in 1..100)
{
# Update process on status
$process.Status = "Handling $percent/100"
$process.PercentComplete = (($percent / 100) * 100)

# Fake workload that takes x amount of time to complete


Start-Sleep -Milliseconds $PSItem.Wait
}

# Mark process as completed


$process.Completed = $true
}

while($job.State -eq 'Running')


{
$sync.Keys | Foreach-Object {
# If key is not defined, ignore
if(![string]::IsNullOrEmpty($sync.$_.keys))
{
# Create parameter hashtable to splat
$param = $sync.$_

# Execute Write-Progress
Write-Progress @param
}
}

# Wait to refresh to not overload gui


Start-Sleep -Seconds 0.1
}

Vínculos relacionados
about_Jobs
about_Scopes
about_Splatting
Compatibilidad para agregar
credenciales a funciones de PowerShell
Artículo • 13/04/2023

7 Nota

La versión original de este artículo apareció en el blog escrito por


@joshduffney . Este artículo se ha editado para su inclusión en este sitio. El
equipo de PowerShell agradece a Josh que comparta este contenido con nosotros.
Visite su blog en duffney.io .

En este artículo se muestra cómo agregar parámetros de credencial a las funciones de


PowerShell y su utilidad. Un parámetro de credencial sirve para permitir la ejecución de
la función o el cmdlet como un usuario diferente. El uso más común es ejecutar la
función o el cmdlet como una cuenta de usuario con privilegios elevados.

Por ejemplo, el cmdlet New-ADUser tiene un parámetro Credential, que podría


proporcionar credenciales de administrador de dominio para crear una cuenta en un
dominio. Suponiendo que la cuenta normal que ejecuta la sesión de PowerShell no
tenga ya ese acceso.

Creación de objeto de credencial


El objeto PSCredential representa un conjunto de credenciales de seguridad, como un
nombre de usuario y una contraseña. El objeto se puede pasar como un parámetro a
una función que se ejecuta como la cuenta de usuario en ese objeto de credencial. Hay
varias maneras de crear un objeto de credencial. La primera de ellas es usar el cmdlet de
PowerShell Get-Credential . Cuando se ejecuta sin parámetros, le pide un nombre de
usuario y una contraseña. O bien, puede llamar al cmdlet con algunos parámetros
opcionales.

Para especificar el nombre de dominio y el nombre de usuario de antemano, puede usar


los parámetros Credential o UserName. Al usar el parámetro UserName, también se le
pedirá que proporcione un valor Message. En el código siguiente se muestra cómo usar
el cmdlet. También puede almacenar el objeto de credencial en una variable para que
pueda usar la credencial varias veces. En el ejemplo siguiente, el objeto de credencial se
almacena en la variable $Cred .

PowerShell
$Cred = Get-Credential
$Cred = Get-Credential -Credential domain\user
$Cred = Get-Credential -UserName domain\user -Message 'Enter Password'

A veces, no puede usar el método interactivo para crear los objetos de credencial que se
muestran en el ejemplo anterior. La mayoría de las herramientas de automatización
requieren un método no interactivo. Para crear una credencial sin interacción del
usuario, cree una cadena segura que contenga la contraseña. A continuación, pase la
cadena segura y el nombre de usuario al método
System.Management.Automation.PSCredential() .

Use el siguiente comando para crear una cadena segura que contenga la contraseña:

PowerShell

ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force

Se requieren los parámetros AsPlainText y Force. Sin esos parámetros, recibirá un


mensaje advirtiendo que no debe pasar texto sin formato a una cadena segura.
PowerShell devuelve esta advertencia porque la contraseña de texto sin formato se
registra en varios registros. Una vez que haya creado una cadena segura, deberá pasarla
al método PSCredential() para crear el objeto de credencial. En el ejemplo siguiente, la
variable $password contiene la cadena segura $Cred que contiene el objeto de
credencial.

PowerShell

$password = ConvertTo-SecureString "MyPlainTextPassword" -AsPlainText -Force


$Cred = New-Object System.Management.Automation.PSCredential ("username",
$password)

Ahora que sabe cómo crear objetos de credencial, puede agregar parámetros de
credencial a las funciones de PowerShell.

Adición de un parámetro de credencial


Al igual que con cualquier otro parámetro, comience agregándolo al bloque param de
su función. Se recomienda asignar un nombre al parámetro $Credential porque eso es
lo que usan los cmdlets de PowerShell existentes. El tipo del parámetro debe ser
[System.Management.Automation.PSCredential] .
En el ejemplo siguiente se muestra el bloque de parámetros de una función llamada
Get-Something . Tiene dos parámetros: $Name y $Credential .

PowerShell

function Get-Something {
param(
$Name,
[System.Management.Automation.PSCredential]$Credential
)

El código de este ejemplo es suficiente para tener un parámetro de credencial de


trabajo; sin embargo, puede añadirle más elementos para mejorar su eficacia.

Agregue el atributo de validación [ValidateNotNull()] para comprobar el valor


que se pasa a Credential. Si el valor del parámetro es NULL, este atributo impide
que la función se ejecute con credenciales no válidas.

Agregue [System.Management.Automation.Credential()] . Esto le permite pasar un


nombre de usuario como una cadena y tener una solicitud interactiva para la
contraseña.

Establezca un valor predeterminado para el parámetro $Credential en


[System.Management.Automation.PSCredential]::Empty . Su función podría estar

pasando este objeto $Credential a los cmdlets de PowerShell existentes. La


provisión de un valor NULL al cmdlet llamado dentro de la función produce un
error. Al proporcionar un objeto de credencial vacío, se evita este error.

 Sugerencia

Algunos cmdlets que aceptan un parámetro de credencial no admiten


[System.Management.Automation.PSCredential]::Empty como deberían. Consulte la

sección Trabajo con cmdlets heredados para obtener una solución alternativa.

Uso de parámetros de credencial


En el ejemplo siguiente se muestra cómo usar parámetros de credencial. En este
ejemplo se muestra una función llamada Set-RemoteRegistryValue , que está fuera de
The Pester Book . Esta función define el parámetro de credencial mediante las técnicas
descritas en la sección anterior. La función llama a Invoke-Command utilizando la variable
$Credential creada por la función. Esto le permite cambiar el usuario que ejecuta
Invoke-Command . Dado que el valor predeterminado de $Credential es una credencial

vacía, la función se puede ejecutar sin proporcionar credenciales.

PowerShell

function Set-RemoteRegistryValue {
param(
$ComputerName,
$Path,
$Name,
$Value,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
$null = Invoke-Command -ComputerName $ComputerName -ScriptBlock {
Set-ItemProperty -Path $using:Path -Name $using:Name -Value
$using:Value
} -Credential $Credential
}

En las secciones siguientes se muestran diferentes métodos para proporcionar


credenciales a Set-RemoteRegistryValue .

Solicitud de credenciales
El uso de Get-Credential entre paréntesis () en el entorno de ejecución hace que Get-
credential se ejecute en primer lugar. Se le pide un nombre de usuario y una
contraseña. Puede usar los parámetros Credential o UserName de Get-credential para
rellenar previamente el nombre de usuario y el dominio. En el ejemplo siguiente se
utiliza una técnica denominada expansión para pasar parámetros a la función Set-
RemoteRegistryValue . Para obtener más información sobre la expansión, consulte el

artículo Acerca de expansión.

PowerShell

$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential (Get-Credential)


El uso de (Get-Credential) parece complicado. Normalmente, cuando se usa el
parámetro Credential solo con un nombre de usuario, el cmdlet solicita
automáticamente la contraseña. El atributo
[System.Management.Automation.Credential()] habilita este comportamiento.

PowerShell

$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential duffney


7 Nota

Para establecer el valor del registro que se muestra, en estos ejemplos se supone
que tiene las características de servidor web de Windows instaladas. Ejecute
Install-WindowsFeature Web-Server y Install-WindowsFeature web-mgmt-tools si es
necesario.

Suministro de credenciales en una variable


También puede rellenar una variable de credencial de antemano y pasarla al parámetro
Credential de la función Set-RemoteRegistryValue . Use este método con herramientas
de integración continua e implementación continua (CI/CD) como Jenkins, TeamCity y
Octopus Deploy. Para obtener un ejemplo de uso de Jenkins, consulte la entrada de
blog de Hodge Automatización con Jenkins y PowerShell en Windows, parte 2 .

En este ejemplo se usa el método .NET para crear el objeto de credencial y una cadena
segura para pasar la contraseña.

PowerShell

$password = ConvertTo-SecureString "P@ssw0rd" -AsPlainText -Force


$Cred = New-Object System.Management.Automation.PSCredential ("duffney",
$password)

$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams -Credential $Cred

En este ejemplo, la cadena segura se crea con una contraseña de texto no cifrado. Todo
el proceso de CI/CD que se menciona anteriormente tiene un método seguro para
proporcionar esa contraseña en el entorno de ejecución. Al usar esas herramientas,
reemplace la contraseña de texto sin formato por la variable definida en la herramienta
de CI/CD que use.

Ejecución sin credenciales


Puesto que $Credential tiene como valor predeterminado un objeto de credencial
vacío, puede ejecutar el comando sin credenciales, como se muestra en este ejemplo:

PowerShell

$remoteKeyParams = @{
ComputerName = $env:COMPUTERNAME
Path = 'HKLM:\SOFTWARE\Microsoft\WebManagement\Server'
Name = 'EnableRemoteManagement'
Value = '1'
}

Set-RemoteRegistryValue @remoteKeyParams

Trabajo con cmdlets heredados


No todos los cmdlets admiten objetos de credencial ni permiten credenciales vacías. En
su lugar, el cmdlet requiere parámetros de nombre de usuario y contraseña como
cadenas. Hay varias maneras de solucionar esta limitación.

Uso de if-else para administrar las credenciales vacías


En este escenario, el cmdlet que desea ejecutar no acepta un objeto de credencial vacío.
En este ejemplo se agrega el parámetro Credential a Invoke-Command solo si no está
vacío. De lo contrario, ejecuta Invoke-Command sin el parámetro Credential.

PowerShell

function Set-RemoteRegistryValue {
param(
$ComputerName,
$Path,
$Name,
$Value,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)

if($Credential -ne [System.Management.Automation.PSCredential]::Empty) {


Invoke-Command -ComputerName:$ComputerName -Credential:$Credential
{
Set-ItemProperty -Path $using:Path -Name $using:Name -Value
$using:Value
}
} else {
Invoke-Command -ComputerName:$ComputerName {
Set-ItemProperty -Path $using:Path -Name $using:Name -Value
$using:Value
}
}
}

Uso de expansión para administrar credenciales vacías


En este ejemplo se usa el parámetro de expansión para llamar al cmdlet heredado. El
objeto $Credential se agrega condicionalmente a la tabla hash de expansión y evita la
necesidad de repetir el bloque de script de Invoke-Command . Para obtener más
información sobre la expansión dentro de las funciones, consulte la entrada de blog
Parámetros de expansión dentro de funciones avanzadas .

PowerShell

function Set-RemoteRegistryValue {
param(
$ComputerName,
$Path,
$Name,
$Value,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)

$Splat = @{
ComputerName = $ComputerName
}

if ($Credential -ne
[System.Management.Automation.PSCredential]::Empty) {
$Splat['Credential'] = $Credential
}

$null = Invoke-Command -ScriptBlock {


Set-ItemProperty -Path $using:Path -Name $using:Name -Value
$using:Value
} @splat
}

Trabajo con contraseñas de cadena


El cmdlet Invoke-Sqlcmd es un ejemplo de cmdlet que acepta una cadena como
contraseña. Invoke-Sqlcmd permite ejecutar instrucciones insert, update y delete de SQL
simples. Invoke-Sqlcmd requiere un nombre de usuario y una contraseña de texto no
cifrado en lugar de un objeto de credencial más seguro. En este ejemplo se muestra
cómo extraer el nombre de usuario y la contraseña de un objeto de credencial.

La función Get-AllSQLDatabases de este ejemplo llama al cmdlet Invoke-Sqlcmd para


consultar en todas las bases de datos de SQL Server. La función define un parámetro
Credential con el mismo atributo que se usa en los ejemplos anteriores. Dado que el
nombre de usuario y la contraseña existen dentro de la variable $Credential , puede
extraer esos valores para usarlos con Invoke-Sqlcmd .

El nombre de usuario está disponible en la propiedad UserName de la variable


$Credential . Para obtener la contraseña, tiene que utilizar el método

GetNetworkCredential() del objeto $Credential . Los valores se extraen en variables que


se agregan a una tabla hash que se utiliza para expandir parámetros en Invoke-Sqlcmd .

PowerShell

function Get-AllSQLDatabases {
param(
$SQLServer,
[ValidateNotNull()]
[System.Management.Automation.PSCredential]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)

$UserName = $Credential.UserName
$Password = $Credential.GetNetworkCredential().Password

$splat = @{
UserName = $UserName
Password = $Password
ServerInstance = 'SQLServer'
Query = "Select * from Sys.Databases"
}

Invoke-Sqlcmd @splat
}

$credSplat = @{
TypeName = 'System.Management.Automation.PSCredential'
ArgumentList = 'duffney',('P@ssw0rd' | ConvertTo-SecureString -
AsPlainText -Force)
}
$Credential = New-Object @credSplat

Get-AllSQLDatabases -SQLServer SQL01 -Credential $Credential

Administración de credenciales de aprendizaje


continuo
La creación y el almacenamiento de objetos de credencial de forma segura puede ser
difícil. Los recursos siguientes pueden ayudarle a mantener las credenciales de
PowerShell.

BetterCredentials
Azure Key Vault
Proyecto Vault
Módulo SecretManagement
Evitar la asignación de variables en
expresiones
Artículo • 13/04/2023

PowerShell permite usar asignaciones dentro de expresiones incluyendo la asignación


entre paréntesis () . PowerShell pasa el valor asignado. Por ejemplo:

PowerShell

# In an `if` conditional
if ($foo = Get-Item $PROFILE) { "$foo exists" }

# Property access
($profileFile = Get-Item $PROFILE).LastWriteTime

# You can even *assign* to such expressions.


($profileFile = Get-Item $PROFILE).LastWriteTime = Get-Date

7 Nota

Aunque esta sintaxis está permitida, se desaconseja su uso. Hay casos en los que
esto no funciona y la intención del autor del código puede resultar confusa para
otros revisores del código.

Limitaciones
El caso de asignación no siempre funciona. Cuando no funciona, la asignación se
descarta. Si crea una instancia de un tipo de valor mutable, e intenta guardarla en una
variable y modificar una de sus propiedades en la misma expresión, se descarta la
asignación de propiedades.

PowerShell

# create mutable value type


PS> Add-Type 'public struct Foo { public int x; }'

# Create an instance, store it in a variable, and try to modify its


property.
# This assignment is effectively IGNORED.
PS> ($var = [Foo]::new()).x = 1
PS> $var.x
0
La diferencia es que no se puede devolver una referencia al valor. Básicamente, ($var =
[Foo]::new()) es equivalente a $($var = [Foo]::new(); $var) . Ya no va a realizar un
acceso de miembro en la variable a la que va a realizar un acceso de miembro en la
salida de la variable, que es una copia.

La solución consiste en crear la instancia y guardarla primero en una variable y, después,


asignarla a la propiedad mediante la variable:

PowerShell

# create mutable value type


PS> Add-Type 'public struct Foo { public int x; }'

# Create an instance and store it in a variable first


# and then modify its property via the variable.
PS> $var = [Foo]::new()
PS> $var.x = 1
PS> $var.x
1
Evitar el uso de Invoke-Expression
Artículo • 13/04/2023

El cmdlet Invoke-Expression solo se debe utilizar como último recurso. En la mayoría de


los recursos hay disponibles alternativas más seguras y sólidas. Los foros como Stack
Overflow están repletos de ejemplos de uso incorrecto de Invoke-Expression . Tenga en
cuenta también que PSScriptAnalyzer tiene una regla para esto. Para obtener más
información, vea AvoidUsingInvokeExpression.

Plantéese con atención las implicaciones de seguridad. Cuando una cadena de un


origen que no es de confianza, como la entrada de usuario, se pasa directamente a
Invoke-Expression , se pueden ejecutar comandos arbitrarios. Plantéese siempre
primero una solución diferente, más sólida y segura.

Escenarios frecuentes
Considere los escenarios de uso siguientes:

Es más sencillo redirigir PowerShell para ejecutar algo de forma natural. Por
ejemplo:

PowerShell

Get-Content ./file.ps1 | Invoke-Expression

Estos casos son extremadamente evitables. El script o código ya existe en el


archivo o formulario AST, por lo que debe escribir un script con parámetros e
invocarlo directamente en lugar de usar Invoke-Expression en una cadena.

Ejecución de un script desde un origen de confianza. Por ejemplo, al ejecutar el


script de instalación desde el repositorio de PowerShell:

PowerShell

Invoke-WebRequest https://aka.ms/install-powershell.ps1 | Invoke-


Expression

Solo debe usar esto de forma interactiva. Y, aunque esto hace que todo sea más
sencillo, esta práctica debe desaconsejarse.
Prueba de errores de análisis. El equipo de PowerShell comprueba si hay errores
de análisis en el código fuente mediante Invoke-Expression porque esa es la única
manera de convertir un error en tiempo de análisis en uno en tiempo de ejecución.

Conclusión
La mayoría de los demás lenguajes de scripting tienen una manera de evaluar una
cadena como código y, como lenguaje interpretado, PowerShell debe tener una manera
de ejecutarse dinámicamente. Pero no hay ningún motivo convincente para usar
Invoke-Expression en un entorno de producción.

Referencias
Explicación de Stack Overflow: ¿En qué escenario está diseñado para usarse
Invoke-Expression?
Entrada de blog de PowerShell: Invoke-Expression se considera dañina
Limitaciones de las transcripciones de
PowerShell
Artículo • 13/04/2023

Mezclar la salida Write-Host con los objetos de salida, las cadenas y la transcripción de
PowerShell es complicado. Hay una interacción sutil entre el script y cómo funciona la
transcripción con canalizaciones de PowerShell que pueden tener resultados
inesperados.

Al emitir objetos desde el script, la aplicación de formato de esos objetos lo controla


Out-Default . Pero la aplicación de formato puede producirse después de que el script
se haya completado y se haya detenido la transcripción. Esto significa que la salida no se
transcribe. Las cadenas se controlan de forma diferente. A veces, la salida de cadena se
pasa mediante el formato, pero no siempre. Write-Host realiza una escritura inmediata
en el proceso de host. Write-Object se envía mediante el sistema de aplicación de
formato. La combinación de la salida de objetos complejos con escrituras en el host
dificulta la predicción de lo que se registra en la transcripción.

Escenario 1: Salida de un objeto estructurado al


final de todas las demás operaciones
Tenga en cuenta el siguiente script y su salida:

PowerShell

PS> Get-Content scenario1.ps1


Start-Transcript scenario1.log -UseMinimalHeader
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
Stop-Transcript

PS> ./scenario1.ps1
Transcript started, output file is scenario1.log
1
2

4
Path
----
/Users/user1/src/projects/transcript
5
Transcript stopped, output file is
/Users/user1/src/projects/transcript/scenario1.log

La salida de la consola muestra el resultado esperado, pero no en el orden en que lo


espera. Write-Host 4 es visible antes que Get-Location porque Write-Host está
optimizado para escribir directamente en el host. Hay código en la transcripción que
copia la salida en el archivo de transcripción y la consola. Después, tenemos la salida
normal de Get-Location y Write-Output 5 enviados como salida del script.

PowerShell

PS> Get-Content scenario1.log


**********************
PowerShell transcript start
Start time: 20191106114858
**********************
Transcript started, output file is s2
1
2

4
**********************
PowerShell transcript end
End time: 20191106114858
**********************

Puesto que la transcripción está desactivada antes de que se cierre el script, no se


representa en la transcripción. Los objetos se enviaron al consumidor siguiente de la
canalización. En este caso, es Out-Default , que PowerShell insertó automáticamente.
Para complicar aún más las cosas, la salida de las cadenas también está optimizada en el
sistema de aplicación de formato. El primer elemento Write-Output 2 lo emite y captura
la transcripción. Pero la inserción del objeto Get-Location hace que su salida se inserte
en la pila de elementos que necesitan aplicación de formato real, que establece un bit
de estado para los objetos restantes que también pueden necesitar aplicación de
formato. Este es el motivo por el que el segundo elemento Write-Output 5 no se agrega
a la transcripción.

Escenario 2: Traslado de la emisión del objeto


al principio
Tenga en cuenta el siguiente script y su salida:

PowerShell
PS> Get-Content scenario2.ps1
Start-Transcript scenario2.log -UseMinimalHeader
Get-Location
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
Stop-Transcript

PS> ./scenario2.ps1
Transcript started, output file is scenario2.log

1
4
Path
----
/Users/user1/src/projects/transcript
2
5
Transcript stopped, output file is
/Users/user1/src/projects/transcript/scenario2.log

Podemos ver que los comandos Write-Host se producen antes que cualquier cosa y,
después, los objetos comienzan a salir. El elemento Write-Output de una cadena obliga
a que el objeto se represente en la pantalla, pero observe que la transcripción contiene
solo la salida de Write-Host . Esto se debe a que esos objetos de cadena se canalizan a
Out-Default para aplicar formato después de que el script desactive la transcripción.

PowerShell

PS> Get-Content scenario2.log


**********************
PowerShell transcript start
Start time: 20220606094609
**********************
Transcript started, output file is s3

1
4
**********************
PowerShell transcript end
End time: 20220606094609
**********************

Escenario 3: Objeto emitido al final del script


En este escenario, la salida del objeto complejo está al final del script.
PowerShell

PS> Get-Content scenario3.ps1


Start-Transcript scenario3.log -UseMinimalHeader
Write-Host '1'
Write-Output '2'
Write-Host '4'
Write-Output '5'
Get-Location
Stop-Transcript

PS> ./scenario3.ps1
Transcript started, output file is scenario3.log
1
2
4
5

Path
----
/Users/user1/src/projects/transcript
Transcript stopped, output file is
/Users/user1/src/projects/transcript/scenario3.log

La salida de cadena de Write-Host y Write-Object la convierte en la transcripción. Pero


la salida de Get-Location se produce después de que la transcripción se haya detenido.

**********************
PowerShell transcript start
Start time: 20220606100342
**********************
Transcript started, output file is scenario3.log
1
2
4
5

**********************
PowerShell transcript end
End time: 20220606100342
**********************

Una manera de garantizar la transcripción


completa
Este ejemplo es una ligera variación frente al escenario original, pero ahora todo se
registra en la transcripción. El código original se encapsula en un bloque de script y el
formateador se invoca explícitamente mediante Out-Default .

PowerShell

PS> Get-Content scenario4.ps1


Start-Transcript scenario4.log -UseMinimalHeader
. {
Write-Host '1'
Write-Output '2'
Get-Location
Write-Host '4'
Write-Output '5'
} | Out-Default
Stop-Transcript

PS> ./scenario4.ps1
Transcript started, output file is scenario4.log
1
2

4
Path
----
/Users/user1/src/projects/transcript
5

Transcript stopped, output file is


/Users/user1/src/projects/transcript/scenario4.log

Observe que la última llamada de Write-Host sigue desordenada; esto se debe a la


optimización en Write-Host que no entra en el flujo de salida.

PowerShell

PS> Get-Content scenario4.log


**********************
PowerShell transcript start
Start time: 20220606101038
**********************
Transcript started, output file is s5
1
2

4
Path
----
/Users/user1/src/projects/transcript
5
**********************
PowerShell transcript end
End time: 20220606101038
**********************
Scripts de muestra para la
administración del sistema
Una colección de ejemplos recorre los escenarios para la administración de sistemas con
PowerShell.

Trabajar con objetos

c GUÍA PASO A PASO

Ver la estructura del objeto

Selección de partes de objetos

Eliminación de objetos de la canalización

Ordenar objetos

Crear objetos .NET y COM

Usar métodos y clases estáticas

Obtención de objetos de WMI con Get-CimInstance

Manipular elementos directamente

Administración de equipos

c GUÍA PASO A PASO

Cambiar el estado del equipo

Recopilar información acerca de los equipos

Creación de consultas Get-WinEvent con FilterHashtable

Administración de procesos y servicios

c GUÍA PASO A PASO

Administración de procesos con cmdlets de proceso

Administración de servicios
Trabajar con impresoras

Realizar tareas de redes

Trabajar con instalaciones de software

Descodificación de un comando de PowerShell desde un proceso en ejecución

Trabajar con la salida

p CONCEPTO

Redirección de la salida

Usar comandos de formato para cambiar la vista de salida

Administrar unidades y archivos

c GUÍA PASO A PASO

Administrar la ubicación actual

Administración de unidades de PowerShell

Trabajar con archivos y carpetas

Trabajar con archivos, carpetas y claves del Registro

Trabajar con entradas del Registro

Trabajar con claves del Registro

Creación de elementos de UI

c GUÍA PASO A PASO

Crear un cuadro de entrada personalizado

Crear un selector de fecha gráfico

Cuadros de lista de selección múltiple

Seleccionar elementos de un cuadro de lista


Ver la estructura del objeto
Artículo • 13/04/2023

Dado que los objetos desempeñan una función esencial en PowerShell, existen varios
comandos nativos diseñados para trabajar con tipos de objetos arbitrarios. El más
importante es el comando Get-Member .

Es la técnica más sencilla para analizar los objetos que devuelve un comando es
canalizar la salida del comando al cmdlet Get-Member . El cmdlet Get-Member muestra el
nombre formal del tipo de objeto y una lista completa de sus miembros. En ocasiones,
el número de elementos devuelto puede ser excesivo. Por ejemplo, un objeto de
proceso puede tener más de 100 miembros.

El siguiente comando permite ver todos los miembros de un objeto Process y una
página a través de la salida.

PowerShell

Get-Process | Get-Member | Out-Host -Paging

Output

TypeName: System.Diagnostics.Process

Name MemberType Definition


---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
NPM AliasProperty NPM = NonpagedSystemMemorySize
PM AliasProperty PM = PagedMemorySize
VM AliasProperty VM = VirtualMemorySize
WS AliasProperty WS = WorkingSet
add_Disposed Method System.Void
add_Disposed(Event...
...

Podemos hacer que esta larga lista de información sea más fácil de usar mediante el
filtrado de los elementos que quiere ver. El comando Get-Member permite mostrar solo
los miembros que son propiedades. Existen varios formatos de propiedades. El cmdlet
muestra las propiedades de un tipo mediante el parámetro MemberType con el valor
Properties . La lista resultante todavía es muy larga, pero un poco más manejable:

PowerShell
Get-Process | Get-Member -MemberType Properties

Output

TypeName: System.Diagnostics.Process

Name MemberType Definition


---- ---------- ----------
Handles AliasProperty Handles = Handlecount
Name AliasProperty Name = ProcessName
...
ExitCode Property System.Int32 ExitCode {get;}
...
Handle Property System.IntPtr Handle {get;}
...
CPU ScriptProperty System.Object CPU
{get=$this.Total...
...
Path ScriptProperty System.Object Path
{get=$this.Main...
...

7 Nota

Los valores permitidos de MemberType son AliasProperty, CodeProperty, Property,


NoteProperty, ScriptProperty, Properties, PropertySet, Method, CodeMethod,
ScriptMethod, Methods, ParameterizedProperty, MemberSet y All.

Existen más de 60 propiedades para un proceso. PowerShell determina cómo mostrar


un tipo de objeto mediante la información almacenada en archivos XML cuyos nombres
terminan con .format.ps1xml . La definición de formato para los objetos de proceso se
almacena en DotNetTypes.format.ps1xml .

Si necesita consultar propiedades distintas de las que PowerShell muestra de forma


predeterminada, deberá formatear la salida mediante los cmdlets Format-* .
Selección de partes de objetos
Artículo • 13/04/2023

Puede usar el cmdlet Select-Object para crear objetos de PowerShell personalizados


que contengan las propiedades seleccionadas de los objetos que usa para crearlos.
Escriba el siguiente comando para crear un nuevo objeto que incluya solamente las
propiedades Name y FreeSpace de la clase Win32_LogicalDisk de WMI:

PowerShell

Get-CimInstance -Class Win32_LogicalDisk |


Select-Object -Property Name, FreeSpace

Output

Name FreeSpace
---- ---------
C: 50664845312

Con Select-Object , puede crear propiedades calculadas para mostrar FreeSpace en


gigabytes en lugar de en bytes.

PowerShell

Get-CimInstance -Class Win32_LogicalDisk |


Select-Object -Property Name, @{
label='FreeSpace'
expression={($_.FreeSpace/1GB).ToString('F2')}
}

Output

Name FreeSpace
---- ---------
C: 47.18
Eliminación de objetos de la
canalización
Artículo • 13/04/2023

En PowerShell, se suelen generar y pasar más objetos de los deseados a una


canalización. Puede especificar las propiedades de los objetos concretos que quiere que
se muestren mediante los cmdlets Format-* , pero esto no ayuda a resolver el problema
de eliminación de objetos completos de la pantalla. Es posible que quiera filtrar objetos
antes del final de una canalización, a fin de poder realizar acciones solo en un
subconjunto de los objetos generados inicialmente.

PowerShell incluye el cmdlet Where-Object , que permite probar cada objeto de la


canalización y pasarlo solo a la canalización si cumple una condición de prueba
determinada. Los objetos que no pasan la prueba se quitan de la canalización. Debe
indicar la condición de prueba como el valor del parámetro FilterScript.

Realización de pruebas simples con Where-


Object
El valor de FilterScript es un bloque de script; es decir, uno o más comandos de
PowerShell entre llaves ( {} ), que se evalúa como true o false. Estos bloques de script
pueden ser muy simples, pero su creación requiere el conocimiento de otro concepto
de PowerShell: los operadores de comparación. Un operador de comparación compara
los elementos que aparecen en cada uno de sus lados. Los operadores de comparación
comienzan con un carácter ( - ) seguido de un nombre. Los operadores de comparación
básicos funcionan en casi todos los tipos de objeto. Es posible que los operadores de
comparación más avanzados solo funcionen en texto o matrices.

7 Nota

De manera predeterminada, los operadores de comparación de PowerShell no


distinguen mayúsculas de minúsculas.

Debido a consideraciones de análisis, símbolos como < , > y = no se usan como


operadores de comparación. En su lugar, los operadores de comparación están
formados por letras. Los operadores lógicos básicos se muestran en la tabla siguiente.
Operadores de Significado Ejemplo (devuelve
comparación true)

-eq es igual a 1 -eq 1

-ne no es igual a 1 -ne 2

-lt Es menor que 1 -lt 2

-le Es menor o igual que 1 -le 2

-gt Es mayor que 2 -gt 1

-ge Es mayor o igual que 2 -ge 1

-like Es como (comparación de comodín para "file.doc" -like "f*.do?"


texto)

-notlike No es como (comparación de comodín para "file.doc" -notlike


texto) "p*.doc"

-contains Contiene 1,2,3 -contains 1

-notcontains No contiene 1,2,3 -notcontains 4

Los bloques de script Where-Object usan la variable especial $_ para hacer referencia al
objeto actual en la canalización. A continuación se incluye un ejemplo de cómo
funciona: Si tiene una lista de números y solo quiere que se devuelvan los que sean
inferiores a 3, puede usar Where-Object para filtrar los números; para ello, escriba:

1,2,3,4 | Where-Object {$_ -lt 3}


1
2

Filtrado por las propiedades de objeto


Dado que $_ hace referencia al objeto de canalización actual, podemos acceder a sus
propiedades para nuestras pruebas.

Por ejemplo, podemos observar la clase Win32_SystemDriver en WMI. Puede haber


cientos de controladores del sistema en un determinado sistema, pero puede que solo
esté interesado en un conjunto concreto de estos controladores, como, por ejemplo,
aquellos que se ejecutan actualmente. En la clase Win32_SystemDriver, la propiedad
pertinente es State. Para filtrar los controladores del sistema seleccione solo los que se
estén ejecutando. Para ello, escriba:

PowerShell

Get-CimInstance -Class Win32_SystemDriver |


Where-Object {$_.State -eq 'Running'}

Esto sigue produciendo una larga lista. Es posible que también quiera filtrar para
seleccionar solo los controladores configurados para iniciarse automáticamente al
probar el valor StartMode:

PowerShell

Get-CimInstance -Class Win32_SystemDriver |


Where-Object {$_.State -eq "Running"} |
Where-Object {$_.StartMode -eq "Auto"}

Output

DisplayName : RAS Asynchronous Media Driver


Name : AsyncMac
State : Running
Status : OK
Started : True

DisplayName : Audio Stub Driver


Name : audstub
State : Running
Status : OK
Started : True
...

Esto nos da mucha información que ya no necesitamos porque sabemos que los
controladores se están ejecutando. De hecho, los únicos datos que probablemente
necesitamos en este momento son el nombre y el nombre para mostrar. El siguiente
comando solo incluye esas dos propiedades, lo que produce una salida mucho más
simple:

PowerShell

Get-CimInstance -Class Win32_SystemDriver |


Where-Object {$_.State -eq "Running"} |
Where-Object {$_.StartMode -eq "Manual"} |
Format-Table -Property Name,DisplayName
Output

Name DisplayName
---- -----------
AsyncMac RAS Asynchronous Media Driver
bindflt Windows Bind Filter Driver
bowser Browser
CompositeBus Composite Bus Enumerator Driver
condrv Console Driver
HdAudAddService Microsoft 1.1 UAA Function Driver for High Definition
Audio Service
HDAudBus Microsoft UAA Bus Driver for High Definition Audio
HidUsb Microsoft HID Class Driver
HTTP HTTP Service
igfx igfx
IntcDAud Intel(R) Display Audio
intelppm Intel Processor Driver
...

Hay dos elementos Where-Object en el comando anterior, pero pueden expresarse en


un único elemento Where-Object mediante el operador lógico -and , de manera similar a
la siguiente:

PowerShell

Get-CimInstance -Class Win32_SystemDriver |


Where-Object {($_.State -eq 'Running') -and ($_.StartMode -eq 'Manual')}
|
Format-Table -Property Name,DisplayName

Los operadores lógicos estándar se muestran en la tabla siguiente.

Operador lógico Significado Ejemplo (devuelve true)

-and Lógico and; true si ambos lados son true (1 -eq 1) -and (2 -eq 2)

-or Lógico or; true si algún lado es true (1 -eq 1) -or (1 -eq 2)

-not Lógico not; invierte true y false -not (1 -eq 2)

! Lógico not; invierte true y false !(1 -eq 2)


Ordenar objetos
Artículo • 13/04/2023

Mediante el cmdlet Sort-Object se pueden organizar los datos que se muestran para
facilitar su examen. Sort-Object toma el nombre de una o varias propiedades por los
que se ordena y devuelve los datos ordenados por los valores de dichas propiedades.

Ordenación básica
Considere el problema de enumerar los subdirectorios y los archivos del directorio
actual. Si queremos ordenar por LastWriteTime y luego por Name, podemos escribir lo
siguiente para hacerlo:

PowerShell

Get-ChildItem |
Sort-Object -Property LastWriteTime, Name |
Format-Table -Property LastWriteTime, Name

Resultados

LastWriteTime Name
------------- ----
11/6/2017 10:10:11 AM .localization-config
11/6/2017 10:10:11 AM .openpublishing.build.ps1
11/6/2017 10:10:11 AM appveyor.yml
11/6/2017 10:10:11 AM LICENSE
11/6/2017 10:10:11 AM LICENSE-CODE
11/6/2017 10:10:11 AM ThirdPartyNotices
11/6/2017 10:10:15 AM tests
6/6/2018 7:58:59 PM CONTRIBUTING.md
6/6/2018 7:58:59 PM README.md
...

También puede ordenar los objetos en orden inverso especificando el parámetro de


modificador Descending.

PowerShell

Get-ChildItem |
Sort-Object -Property LastWriteTime, Name -Descending |
Format-Table -Property LastWriteTime, Name

Resultados
LastWriteTime Name
------------- ----
12/1/2018 10:13:50 PM reference
12/1/2018 10:13:50 PM dsc
...
6/6/2018 7:58:59 PM README.md
6/6/2018 7:58:59 PM CONTRIBUTING.md
11/6/2017 10:10:15 AM tests
11/6/2017 10:10:11 AM ThirdPartyNotices
11/6/2017 10:10:11 AM LICENSE-CODE
11/6/2017 10:10:11 AM LICENSE
11/6/2017 10:10:11 AM appveyor.yml
11/6/2017 10:10:11 AM .openpublishing.build.ps1
11/6/2017 10:10:11 AM .localization-config

Uso de las tablas hash


Puede ordenar propiedades diferentes en distintos órdenes mediante tablas hash en
una matriz. Cada tabla hash utiliza una clave Expression para especificar el nombre de la
propiedad como cadena y una clave Ascending o Descending para especificar el criterio
de ordenación por $true o $false . La clave Expression es obligatoria. La clave
Ascending o Descending es opcional.

El ejemplo siguiente ordena los objetos en orden descendente por LastWriteTime y en


orden ascendente por Name.

PowerShell

Get-ChildItem |
Sort-Object -Property @{ Expression = 'LastWriteTime'; Descending = $true
},
@{ Expression = 'Name'; Ascending = $true } |
Format-Table -Property LastWriteTime, Name

Resultados

LastWriteTime Name
------------- ----
12/1/2018 10:13:50 PM dsc
12/1/2018 10:13:50 PM reference
11/29/2018 6:56:01 PM .openpublishing.redirection.json
11/29/2018 6:56:01 PM gallery
11/24/2018 10:33:22 AM developer
11/20/2018 7:22:19 PM .markdownlint.json
...
También puede establecer un bloque de script en la clave Expression. Cuando se ejecuta
el cmdlet Sort-Object , se ejecuta el bloque de script y el resultado se utiliza para
ordenar.

El ejemplo siguiente ordena los objetos en orden descendente según el intervalo de


tiempo entre CreationTime y LastWriteTime.

PowerShell

Get-ChildItem |
Sort-Object -Property @{ Exp = { $_.LastWriteTime - $_.CreationTime };
Desc = $true } |
Format-Table -Property LastWriteTime, CreationTime

Resultados

LastWriteTime CreationTime
------------- ------------
12/1/2018 10:13:50 PM 11/6/2017 10:10:11 AM
12/1/2018 10:13:50 PM 11/6/2017 10:10:11 AM
11/7/2018 6:52:24 PM 11/6/2017 10:10:11 AM
11/7/2018 6:52:24 PM 11/6/2017 10:10:15 AM
11/3/2018 9:58:17 AM 11/6/2017 10:10:11 AM
10/26/2018 4:50:21 PM 11/6/2017 10:10:11 AM
11/17/2018 1:10:57 PM 11/29/2017 5:48:30 PM
11/12/2018 6:29:53 PM 12/7/2017 7:57:07 PM
...

Sugerencias
Puede omitir el nombre de parámetro Property del modo siguiente:

PowerShell

Sort-Object LastWriteTime, Name

Además, puede hacer referencia a Sort-Object mediante su alias integrado, sort :

PowerShell

sort LastWriteTime, Name

Las claves de las tablas hash para la ordenación se pueden abreviar como sigue:

PowerShell
Sort-Object @{ e = 'LastWriteTime'; d = $true }, @{ e = 'Name'; a = $true }

En este ejemplo, e significa Expression, d significa Descending y a significa Ascending.

Para mejorar la legibilidad, puede colocar las tablas hash en una variable independiente:

PowerShell

$order = @(
@{ Expression = 'LastWriteTime'; Descending = $true }
@{ Expression = 'Name'; Ascending = $true }
)

Get-ChildItem |
Sort-Object $order |
Format-Table LastWriteTime, Name
Crear objetos .NET y COM
Artículo • 13/04/2023

Este ejemplo solo se ejecuta en plataformas Windows.

Existen componentes de software con interfaces de .NET Framework y COM que


permiten realizar muchas tareas de administración del sistema. PowerShell le permite
usar estos componentes, por lo que no está limitado a las tareas que pueden realizarse
mediante cmdlets. Muchos de los cmdlets de la versión inicial de PowerShell no
funcionan en equipos remotos. Demostraremos cómo superar esta limitación al
administrar registros de eventos mediante el uso de la clase
System.Diagnostics.EventLog de .NET Framework directamente desde PowerShell.

Uso de New-Object para el acceso al registro


de eventos
La biblioteca de clases de .NET Framework incluye una clase denominada
System.Diagnostics.EventLog que se puede usar para administrar registros de eventos.
Puede crear una nueva instancia de una clase de .NET Framework mediante el cmdlet
New-Object con el parámetro TypeName. Por ejemplo, el comando siguiente crea una

referencia de registro de eventos:

PowerShell

New-Object -TypeName System.Diagnostics.EventLog

Output

Max(K) Retain OverflowAction Entries Name


------ ------ -------------- ------- ----

Aunque el comando creó una instancia de la clase EventLog, la instancia no incluye


ningún dato. Esto se debe a que no se especificó un registro de eventos determinado.
¿Cómo se consigue un registro de eventos real?

Uso de constructores con New-Object


Para hacer referencia a un registro de eventos específico, debe especificar el nombre del
registro. New-Object tiene un parámetro ArgumentList. Los argumentos que se pasan
como valores a este parámetro se usan en un método de inicio especial del objeto. El
método se llama constructor porque se usa para construir el objeto. Por ejemplo, para
obtener una referencia al registro de aplicaciones, especifique la cadena "Application"
como argumento:

PowerShell

New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application

Output

Max(K) Retain OverflowAction Entries Name


------ ------ -------------- ------- ----
16,384 7 OverwriteOlder 2,160 Application

7 Nota

Puesto que la mayoría de las clases de .NET Framework se incluyen en el espacio de


nombres System, PowerShell intenta automáticamente buscar clases que se
especifiquen en dicho espacio de nombres si no se encuentra a una coincidencia
para el nombre de tipo especificado. Esto significa que puede especificar
Diagnostics.EventLog en lugar de System.Diagnostics.EventLog .

Almacenar objetos en Variables


Es posible que desee almacenar una referencia a un objeto, para poder usarla en el shell
actual. Aunque PowerShell permite realizar muchas tareas con las canalizaciones, lo que
reduce la necesidad de variables, almacenar referencias a objetos en variables puede
facilitar la manipulación de esos objetos en determinadas ocasiones.

La salida de cualquier comando válido de PowerShell puede almacenarse en una


variable. Los nombres de variable siempre comienzan por $ . Si desea almacenar la
referencia del registro de aplicaciones en una variable denominada $AppLog , escriba el
nombre de la variable, seguido de un signo igual y, a continuación, escriba el comando
usado para crear el objeto de registro de aplicaciones:

PowerShell

$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList


Application
Si luego escribe $AppLog , puede ver que contiene el registro de aplicaciones:

PowerShell

$AppLog

Output

Max(K) Retain OverflowAction Entries Name


------ ------ -------------- ------- ----
16,384 7 OverwriteOlder 2,160 Application

Acceso a un registro de eventos remoto con New-Object


Los comandos usados en la sección anterior son para el equipo local; el cmdlet Get-
EventLog puede hacerlo. Para acceder al registro de aplicaciones en un equipo remoto,

debe proporcionar el nombre del registro y un nombre de equipo (o dirección IP) como
argumentos.

PowerShell

$RemoteAppLog = New-Object -TypeName System.Diagnostics.EventLog


Application, 192.168.1.81
$RemoteAppLog

Output

Max(K) Retain OverflowAction Entries Name


------ ------ -------------- ------- ----
512 7 OverwriteOlder 262 Application

Ahora que tenemos una referencia a un registro de eventos almacenado en la variable


$RemoteAppLog , ¿qué tareas podemos realizar en él?

Borrado de un registro de eventos con los métodos de


objeto
Los objetos suelen tener métodos que se puedan llamar para realizar tareas. Puede usar
Get-Member para mostrar los métodos asociados con un objeto. El siguiente comando y

la salida seleccionada muestran algunos de los métodos de la clase EventLog:

PowerShell
$RemoteAppLog | Get-Member -MemberType Method

Output

TypeName: System.Diagnostics.EventLog

Name MemberType Definition


---- ---------- ----------
...
Clear Method System.Void Clear()
Close Method System.Void Close()
...
GetType Method System.Type GetType()
...
ModifyOverflowPolicy Method System.Void
ModifyOverflowPolicy(Overfl...
RegisterDisplayName Method System.Void RegisterDisplayName(String
...
...
ToString Method System.String ToString()
WriteEntry Method System.Void WriteEntry(String
message),...
WriteEvent Method System.Void WriteEvent(EventInstance
in...

El método Clear() se puede usar para borrar el registro de eventos. Cuando se llama a
un método, siempre hay que poner el nombre del método entre paréntesis, aunque el
método no requiera argumentos. Esto permite que PowerShell distinga entre el método
y una posible propiedad con el mismo nombre. Escriba lo siguiente para llamar al
método Clear:

PowerShell

$RemoteAppLog.Clear()
$RemoteAppLog

Output

Max(K) Retain OverflowAction Entries Name


------ ------ -------------- ------- ----
512 7 OverwriteOlder 0 Application

Verá que se ha borrado el registro de eventos y ahora tiene 0 entradas en lugar de 262.

Creación de objetos COM con New-Object


Puede usar New-Object para trabajar con componentes del Modelo de objetos
componentes (COM). Los componentes van desde las distintas bibliotecas incluidas con
Windows Script Host (WSH) hasta las aplicaciones de ActiveX, como Internet Explorer,
que están instaladas en la mayoría de los sistemas.

New-Object usa contenedores RCW de .NET Framework para crear objetos COM, por lo

que tiene las mismas limitaciones que .NET Framework al llamar a objetos COM. Para
crear un objeto COM, debe especificar el parámetro ComObject con el identificador de
programación o ProgID de la clase COM que quiere usar. Una explicación completa de
las limitaciones del uso de COM y determinar qué valores ProgId están disponibles en
un sistema está fuera del ámbito de esta guía de usuario, pero la mayoría de los objetos
conocidos de entornos como WSH pueden usarse en PowerShell.

Puede crear los objetos WSH especificando estos ProgID: WScript.Shell,


WScript.Network, Scripting.Dictionary y Scripting.FileSystemObject. Los siguientes
comandos crean estos objetos:

PowerShell

New-Object -ComObject WScript.Shell


New-Object -ComObject WScript.Network
New-Object -ComObject Scripting.Dictionary
New-Object -ComObject Scripting.FileSystemObject

Aunque la mayor parte de la funcionalidad de estas clases está disponible de otras


maneras en Windows PowerShell, algunas tareas como la creación de accesos directos
son aún más fáciles con las clases de WSH.

Creación de un acceso directo de escritorio con


WScript.Shell
Una tarea que se puede realizar rápidamente con un objeto COM es crear un acceso
directo. Supongamos que quiere crear un acceso directo en el escritorio que vincule a la
carpeta principal de PowerShell. Primero debe crear una referencia a WScript.Shell, que
se almacenará en una variable denominada $WshShell :

PowerShell

$WshShell = New-Object -ComObject WScript.Shell

Get-Member funciona con objetos COM, por lo que es posible escribir lo siguiente para

explorar los miembros del objeto:


PowerShell

$WshShell | Get-Member

Output

TypeName: System.__ComObject#{41904400-be18-11d3-a28b-00104bd35090}

Name MemberType Definition


---- ---------- ----------
AppActivate Method bool AppActivate (Variant,
Va...
CreateShortcut Method IDispatch CreateShortcut
(str...
...

Get-Member tiene un parámetro InputObject opcional que puede usar en lugar de las
canalizaciones para proporcionar la entrada a Get-Member . Obtendría la misma salida
mostrada anteriormente si en su lugar usara el comando Get-Member -InputObject
$WshShell. Si usa InputObject, trata su argumento como un solo elemento. Esto
significa que si tiene varios objetos en una variable, Get-Member los trata como una
matriz de objetos. Por ejemplo:

PowerShell

$a = 1,2,"three"
Get-Member -InputObject $a

Output

TypeName: System.Object[]
Name MemberType Definition
---- ---------- ----------
Count AliasProperty Count = Length
...

El método WScript.Shell CreateShortcut acepta un solo argumento, la ruta de acceso al


archivo de acceso directo que se va a crear. Podríamos escribir la ruta de acceso
completa al escritorio, pero hay una manera más fácil. El escritorio suele representarse
con una carpeta denominada Desktop dentro de la carpeta principal del usuario actual.
Windows PowerShell tiene una variable $HOME que contiene la ruta de acceso a esta
carpeta. Podemos especificar la ruta de acceso a la carpeta principal mediante esta
variable y, después, agregar el nombre de la carpeta Desktop y el nombre del acceso
directo que crearemos escribiéndolo:
PowerShell

$lnk = $WshShell.CreateShortcut("$HOME\Desktop\PSHome.lnk")

Si usa algo parecido a un nombre de variable entre comillas dobles, PowerShell intenta
sustituir un valor coincidente. Si usa comillas simples, PowerShell no intenta sustituir el
valor de la variable. Por ejemplo, intente escribir los siguientes comandos:

PowerShell

"$HOME\Desktop\PSHome.lnk"

Output

C:\Documents and Settings\aka\Desktop\PSHome.lnk

PowerShell

'$HOME\Desktop\PSHome.lnk'

Output

$HOME\Desktop\PSHome.lnk

Ahora tenemos una variable denominada $lnk que contiene una nueva referencia de
acceso directo. Si quiere ver sus miembros, puede canalizarla a Get-Member . La salida
siguiente muestra los miembros que debemos usar para terminar de crear el acceso
directo:

PowerShell

$lnk | Get-Member

Output

TypeName: System.__ComObject#{f935dc23-1cf0-11d0-adb9-00c04fd58a0b}
Name MemberType Definition
---- ---------- ----------
...
Save Method void Save ()
...
TargetPath Property string TargetPath () {get} {set}
Es preciso especificar TargetPath, que es la carpeta de aplicación de PowerShell y, luego,
guardar el acceso directo llamando al método Save . La ruta de acceso a la carpeta de la
aplicación de PowerShell se almacena en la variable $PSHome , por lo que podemos
escribir lo siguiente para hacerlo:

PowerShell

$lnk.TargetPath = $PSHome
$lnk.Save()

Uso de Internet Explorer desde PowerShell


Muchas aplicaciones (incluida la familia de aplicaciones de Microsoft Office e Internet
Explorer) pueden automatizarse mediante COM. En los ejemplos siguientes se muestran
algunas de las técnicas y problemas típicos que supone trabajar con aplicaciones
basadas en COM.

Una instancia de Internet Explorer se crea especificando el ProgID de Internet Explorer,


InternetExplorer.Application:

PowerShell

$ie = New-Object -ComObject InternetExplorer.Application

Este comando inicia Internet Explorer, pero no hace que sea visible. Si escribe Get-
Process , puede ver que se ejecuta un proceso llamado iexplore . De hecho, si sale de

PowerShell, el proceso se seguirá ejecutando. Debe reiniciar el equipo o usar una


herramienta como el Administrador de tareas para finalizar el proceso iexplore .

7 Nota

Los objetos COM que se inician como procesos independientes, denominados


normalmente ejecutables de ActiveX, pueden mostrar o no una ventana de interfaz
de usuario al iniciarse. Si crean una ventana pero no la hacen visible, como Internet
Explorer, el foco normalmente se mueve al escritorio de Windows. Debe hacer que
la ventana sea visible para interactuar con ella.

Si escribe $ie | Get-Member , podrá ver las propiedades y los métodos de Internet
Explorer. Para ver la ventana de Internet Explorer, establezca la propiedad Visible en
$true . Para ello, escriba:
PowerShell

$ie.Visible = $true

A continuación, puede navegar a una dirección web específica mediante el método


Navigate :

PowerShell

$ie.Navigate("https://devblogs.microsoft.com/scripting/")

Con otros miembros del modelo de objetos de Internet Explorer, es posible recuperar el
contenido de texto de la página web. El siguiente comando mostrará el texto HTML en
el cuerpo de la página web actual:

PowerShell

$ie.Document.Body.InnerText

Para cerrar Internet Explorer desde PowerShell, llame a su método Quit() :

PowerShell

$ie.Quit()

La variable $ie ya no contiene una referencia válida, aunque parece ser un objeto COM.
Si intenta usarla, PowerShell devuelve un error de automatización:

PowerShell

$ie | Get-Member

Output

Get-Member : Exception retrieving the string representation for property


"Appli
cation" : "The object invoked has disconnected from its clients. (Exception
fro
m HRESULT: 0x80010108 (RPC_E_DISCONNECTED))"
At line:1 char:16
+ $ie | Get-Member <<<<
Puede quitar la referencia que queda con un comando como $ie = $null , o bien
escribir lo siguiente para quitar la variable completamente:

PowerShell

Remove-Variable ie

7 Nota

No hay un estándar común para determinar si los ejecutables de ActiveX se cierran


o se siguen ejecutando cuando se quita una referencia a uno de ellos. Que la
aplicación se cierre o no dependerá de las circunstancias, como, por ejemplo, si la
aplicación es visible, si está ejecutando en ella un documento editado e incluso si
PowerShell todavía se está ejecutando. Por este motivo, debe probar el
comportamiento de finalización de cada ejecutable de ActiveX que quiera usar en
PowerShell.

Obtención de advertencias sobre los objetos


COM encapsulados por .NET Framework
En algunos casos, un objeto COM puede tener un contenedor RCW (Runtime-Callable
Wrapper) que New-Object usa. Dado que el comportamiento del RCW puede ser
diferente del comportamiento del objeto COM normal, New-Object tiene un parámetro
Strict para advertirle del acceso del RCW. Si especifica el parámetro Strict y, a
continuación, crea un objeto COM que usa un RCW, recibirá un mensaje de advertencia:

PowerShell

$xl = New-Object -ComObject Excel.Application -Strict

Output

New-Object : The object written to the pipeline is an instance of the type


"Mic
rosoft.Office.Interop.Excel.ApplicationClass" from the component's primary
interop assembly. If
this type exposes different members than the IDispatch members , scripts
written to work with this
object might not work if the primary interop assembly isn't installed. At
line:1 char:17 + $xl =
New-Object <<<< -ComObject Excel.Application -Strict
Aunque el objeto se creará de todos modos, se le advertirá que no es un objeto COM
estándar.
Usar métodos y clases estáticas
Artículo • 13/04/2023

No todas las clases de .NET Framework se pueden crear mediante New-Object . Por
ejemplo, si intenta crear un objeto System.Environment o System.Math con New-Object ,
obtendrá los siguientes mensajes de error:

PowerShell

New-Object System.Environment

Output

New-Object : Constructor not found. Cannot find an appropriate constructor


for
type System.Environment.
At line:1 char:11
+ New-Object <<<< System.Environment

PowerShell

New-Object System.Math

Output

New-Object : Constructor not found. Cannot find an appropriate constructor


for
type System.Math.
At line:1 char:11
+ New-Object <<<< System.Math

Estos errores se producen porque no hay ninguna manera de crear un nuevo objeto
desde estas clases. Estas clases son bibliotecas de métodos y propiedades de referencia
que no cambian el estado. No es necesario crearlas, simplemente úselas. Las clases y
métodos de este tipo se denominan clases estáticas porque no se crean, destruyen ni
modifican. Para aclarar esto, proporcionaremos algunos ejemplos que usan clases
estáticas.

Obtención de datos del entorno con


System.Environment
Normalmente, el primer paso para trabajar con un objeto en Windows PowerShell es
usar Get-Member para averiguar qué miembros contiene. Con las clases estáticas, el
proceso es un poco diferente, porque la clase real no es un objeto.

Referencia a la clase System.Environment estática


Para hacer referencia a una clase estática incluya el nombre de la clase entre corchetes.
Por ejemplo, para hacer referencia a System.Environment escriba el nombre entre
corchetes. Al hacerlo, se mostrará alguna información de tipo genérico:

PowerShell

[System.Environment]

Output

IsPublic IsSerial Name BaseType


-------- -------- ---- --------
True False Environment System.Object

7 Nota

Como mencionamos anteriormente, Windows PowerShell antepone 'System.'


automáticamente a los nombres de tipos cuando usa New-Object . Lo mismo ocurre
cuando se usa un nombre de tipo entre corchetes, por lo que
[System.Environment] se puede especificar como [Environment].

La clase System.Environment contiene información general sobre el entorno de trabajo


para el proceso actual, que es powershell.exe al trabajar en Windows PowerShell.

Si intenta ver los detalles de esta clase y escribe [System.Environment] | Get-Member,


el tipo de objeto se indica como System.RuntimeType, no como System.Environment:

PowerShell

[System.Environment] | Get-Member

Output

TypeName: System.RuntimeType
Para ver los miembros estáticos con Get-Member, especifique el parámetro Static:

PowerShell

[System.Environment] | Get-Member -Static

Output

TypeName: System.Environment

Name MemberType Definition


---- ---------- ----------
Equals Method static System.Boolean Equals(Object
ob...
Exit Method static System.Void Exit(Int32
exitCode)
...
CommandLine Property static System.String CommandLine
{get;}
CurrentDirectory Property static System.String CurrentDirectory
...
ExitCode Property static System.Int32 ExitCode
{get;set;}
HasShutdownStarted Property static System.Boolean
HasShutdownStart...
MachineName Property static System.String MachineName
{get;}
NewLine Property static System.String NewLine {get;}
OSVersion Property static System.OperatingSystem
OSVersio...
ProcessorCount Property static System.Int32 ProcessorCount
{get;}
StackTrace Property static System.String StackTrace {get;}
SystemDirectory Property static System.String SystemDirectory
{...
TickCount Property static System.Int32 TickCount {get;}
UserDomainName Property static System.String UserDomainName
{g...
UserInteractive Property static System.Boolean UserInteractive
...
UserName Property static System.String UserName {get;}
Version Property static System.Version Version {get;}
WorkingSet Property static System.Int64 WorkingSet {get;}
TickCount ExitCode

Ahora podemos seleccionar las propiedades que queremos ver desde


System.Environment.
Visualización de las propiedades estáticas de
System.Environment
Las propiedades de System.Environment también son estáticas y deben especificarse de
manera diferente que las propiedades normales. Usamos :: para indicar a Windows
PowerShell que queremos trabajar con una propiedad o un método estático. Para ver el
comando que se usó para iniciar Windows PowerShell, comprobamos la propiedad
CommandLine, para lo cual escribimos:

PowerShell

[System.Environment]::Commandline

Output

"C:\Program Files\Windows PowerShell\v1.0\powershell.exe"

Para comprobar la versión del sistema operativo, debemos mostrar la propiedad


OSVersion. Para ello, escribimos:

PowerShell

[System.Environment]::OSVersion

Output

Platform ServicePack Version VersionString


-------- ----------- ------- -------------
Win32NT Service Pack 2 5.1.2600.131072 Microsoft
Windows...

Para comprobar si el equipo se está apagando, podemos mostrar la propiedad


HasShutdownStarted:

PowerShell

[System.Environment]::HasShutdownStarted

Output

False
Operaciones matemáticas con System.Math
La clase estática System.Math es útil para realizar algunas operaciones matemáticas. La
clase incluye varios métodos útiles, que podemos mostrar mediante Get-Member .

7 Nota

System.Math tiene varios métodos con el mismo nombre, pero se distinguen por el
tipo de sus parámetros.

Escriba el siguiente comando para enumerar los métodos de la clase System.Math.

PowerShell

[System.Math] | Get-Member -Static -MemberType Methods

Output

TypeName: System.Math

Name MemberType Definition


---- ---------- ----------
Abs Method static System.Single Abs(Single value), static
Sy...
Acos Method static System.Double Acos(Double d)
Asin Method static System.Double Asin(Double d)
Atan Method static System.Double Atan(Double d)
Atan2 Method static System.Double Atan2(Double y, Double x)
BigMul Method static System.Int64 BigMul(Int32 a, Int32 b)
Ceiling Method static System.Double Ceiling(Double a), static
Sy...
Cos Method static System.Double Cos(Double d)
Cosh Method static System.Double Cosh(Double value)
DivRem Method static System.Int32 DivRem(Int32 a, Int32 b,
Int3...
Equals Method static System.Boolean Equals(Object objA, Object
...
Exp Method static System.Double Exp(Double d)
Floor Method static System.Double Floor(Double d), static
Syst...
IEEERemainder Method static System.Double IEEERemainder(Double x,
Doub...
Log Method static System.Double Log(Double d), static
System...
Log10 Method static System.Double Log10(Double d)
Max Method static System.SByte Max(SByte val1, SByte val2),
...
Min Method static System.SByte Min(SByte val1, SByte val2),
...
Pow Method static System.Double Pow(Double x, Double y)
ReferenceEquals Method static System.Boolean ReferenceEquals(Object
objA...
Round Method static System.Double Round(Double a), static
Syst...
Sign Method static System.Int32 Sign(SByte value), static
Sys...
Sin Method static System.Double Sin(Double a)
Sinh Method static System.Double Sinh(Double value)
Sqrt Method static System.Double Sqrt(Double d)
Tan Method static System.Double Tan(Double a)
Tanh Method static System.Double Tanh(Double value)
Truncate Method static System.Decimal Truncate(Decimal d),
static...

Muestra varios métodos matemáticos. A continuación, presentamos una lista de


comandos que muestran el funcionamiento de algunos de los métodos comunes:

PowerShell

[System.Math]::Sqrt(9)
3
[System.Math]::Pow(2,3)
8
[System.Math]::Floor(3.3)
3
[System.Math]::Floor(-3.3)
-4
[System.Math]::Ceiling(3.3)
4
[System.Math]::Ceiling(-3.3)
-3
[System.Math]::Max(2,7)
7
[System.Math]::Min(2,7)
2
[System.Math]::Truncate(9.3)
9
[System.Math]::Truncate(-9.3)
-9
Obtención de objetos de WMI con Get-
CimInstance
Artículo • 21/10/2023

Este ejemplo solo se aplica a las plataformas Windows.

Windows Management Instrumentation (WMI) es una tecnología principal para la


administración del sistema de Windows porque expone una amplia gama de
información de manera uniforme. Debido a la medida en que WMI lo hace posible, el
cmdlet de PowerShell para acceder a objetos WMI, Get-CimInstance es uno de los más
útiles para realizar el trabajo real. Vamos a explicar cómo usar los cmdlets de CIM para
acceder a objetos WMI y, después, cómo usar objetos WMI para realizar acciones
específicas.

Enumeración de clases WMI


El primer problema que la mayoría de los usuarios de WMI experimentan es intentar
averiguar qué se puede hacer con WMI. Las clases WMI describen los recursos que se
pueden administrar. Existen cientos de clases WMI, algunas de los cuales contienen
decenas de propiedades.

Get-CimClass hace que WMI se pueda detectar para abordar este problema. Para

obtener una lista de las clases WMI disponibles en el equipo local, escriba:

PowerShell

Get-CimClass -Namespace root/CIMV2 |


Where-Object CimClassName -like Win32* |
Select-Object CimClassName

Output

CimClassName
------------
Win32_DeviceChangeEvent
Win32_SystemConfigurationChangeEvent
Win32_VolumeChangeEvent
Win32_SystemTrace
Win32_ProcessTrace
Win32_ProcessStartTrace
Win32_ProcessStopTrace
Win32_ThreadTrace
Win32_ThreadStartTrace
Win32_ThreadStopTrace
...

Puede recuperar la misma información de un equipo remoto mediante el parámetro


ComputerName. Para ello, especifique un nombre de equipo o una dirección IP:

PowerShell

Get-CimClass -Namespace root/CIMV2 -ComputerName 192.168.1.29

El listado de clases devuelto por los equipos remotos puede variar debido al sistema
operativo específico que ejecuta el equipo y a las extensiones WMI concretas que
agregan las aplicaciones instaladas.

7 Nota

Al usar cmdlets de CIM para conectarse a un equipo remoto, este debe ejecutar
WMI y la cuenta que está usando debe estar en el grupo de Administradores local
en el equipo remoto. El sistema remoto no necesita tener PowerShell instalado.
Esto permite administrar los sistemas operativos que no ejecutan PowerShell, pero
tienen WMI disponible.

Visualización de los detalles de clases WMI


Si conoce el nombre de una clase WMI, puede usarlo para obtener información
inmediatamente. Por ejemplo, una de las clases WMI que se usa habitualmente para
recuperar información sobre un equipo es Win32_OperatingSystem.

PowerShell

Get-CimInstance -Class Win32_OperatingSystem

Output

SystemDirectory Organization BuildNumber RegisteredUser SerialNumber


Version
--------------- ------------ ----------- -------------- ------------
-------
C:\WINDOWS\system32 Microsoft 22621 USER1 00330-80000-
00000-AA175 10.0.22621
Aunque vamos a mostrar todos los parámetros, el comando se puede expresar de forma
más concisa. El parámetro ComputerName no es necesario cuando se conecta al
sistema local. Los presentamos para demostrar el caso más general y recordarle el
parámetro. Namespace se establece de manera predeterminada en root/CIMV2 y
también se puede omitir. Por último, la mayoría de los cmdlets permite omitir el nombre
de los parámetros comunes. Con Get-CimInstance , si no se especifica ningún nombre
para el primer parámetro, PowerShell lo trata como el parámetro Class. Esto significa
que el último comando se podría haber emitido escribiendo:

PowerShell

Get-CimInstance Win32_OperatingSystem

La clase Win32_OperatingSystem tiene muchas más propiedades de las que se


muestran aquí. Puede usar Get-Member para ver todas las propiedades. Las
propiedades de una clase WMI están disponibles automáticamente como otras
propiedades de objeto:

PowerShell

Get-CimInstance -Class Win32_OperatingSystem | Get-Member -MemberType


Property

Output

TypeName:
Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_OperatingSy
stem
Name MemberType Definition
---- ---------- ----------
BootDevice Property string BootDevice
{get;}
BuildNumber Property string BuildNumber
{get;}
BuildType Property string BuildType {get;}
Caption Property string Caption {get;}
CodeSet Property string CodeSet {get;}
CountryCode Property string CountryCode
{get;}
CreationClassName Property string
CreationClassName {get;}
CSCreationClassName Property string
CSCreationClassName {get;}
CSDVersion Property string CSDVersion
{get;}
CSName Property string CSName {get;}
CurrentTimeZone Property int16 CurrentTimeZone
{get;}
DataExecutionPrevention_32BitApplications Property bool
DataExecutionPrevention_32BitApplications {get;}
DataExecutionPrevention_Available Property bool
DataExecutionPrevention_Available {get;}
...

Visualización de propiedades no
predeterminadas con los cmdlets Format
Si desea que la información contenida en la clase Win32_OperatingSystem que no se
muestre de forma predeterminada, puede mostrarla mediante los cmdlets Format. Por
ejemplo, si desea mostrar los datos de memoria disponible, escriba:

PowerShell

Get-CimInstance -Class Win32_OperatingSystem | Format-Table -Property


TotalVirtualMemorySize, TotalVisibleMemorySize, FreePhysicalMemory,
FreeVirtualMemory, FreeSpaceInPagingFiles

Output

TotalVirtualMemorySize TotalVisibleMemorySize FreePhysicalMemory


FreeVirtualMemory FreeSpaceInPagingFiles
---------------------- ---------------------- ------------------ -----------
------ ----------------------
41787920 16622096 9537952
33071884 25056628

7 Nota

Los caracteres comodín funcionan con nombres de propiedad de Format-Table ,


por lo que el elemento final de la canalización se puede reducir a Format-Table -
Property Total*Memory*, Free* .

Los datos de la memoria podrían ser más legibles si se formatean como una lista
escribiendo:

PowerShell

Get-CimInstance -Class Win32_OperatingSystem | Format-List Total*Memory*,


Free*
Output

TotalVirtualMemorySize : 41787920
TotalVisibleMemorySize : 16622096
FreePhysicalMemory : 9365296
FreeSpaceInPagingFiles : 25042952
FreeVirtualMemory : 33013484
Name : Microsoft Windows 11
Pro|C:\Windows|\Device\Harddisk0\Partition2

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Manipular elementos directamente
Artículo • 13/04/2023

Lo que ve en las unidades de PowerShell, como los archivos y carpetas o las caves del
Registro, se llaman elementos en PowerShell. Los cmdlets que funcionan con los
elementos contienen el término Item en sus nombres.

La salida del comando Get-Command -Noun Item indica que hay nueve cmdlets de
elemento de PowerShell.

PowerShell

Get-Command -Noun Item

Output

CommandType Name Definition


----------- ---- ----------
Cmdlet Clear-Item Clear-Item [-Path]
<String[]...
Cmdlet Copy-Item Copy-Item [-Path]
<String[]>...
Cmdlet Get-Item Get-Item [-Path] <String[]>
...
Cmdlet Invoke-Item Invoke-Item [-Path]
<String[...
Cmdlet Move-Item Move-Item [-Path]
<String[]>...
Cmdlet New-Item New-Item [-Path] <String[]>
...
Cmdlet Remove-Item Remove-Item [-Path]
<String[...
Cmdlet Rename-Item Rename-Item [-Path]
<String>...
Cmdlet Set-Item Set-Item [-Path] <String[]>
...

Creación de nuevos elementos


Para crear un nuevo elemento en el sistema de archivos, use el cmdlet New-Item . Incluya
el parámetro Path con la ruta de acceso al elemento y el parámetro ItemType con un
valor file o directory .
Por ejemplo, para crear un directorio con el nombre New.Directory en el directorio
C:\Temp , escriba:

PowerShell

New-Item -Path c:\temp\New.Directory -ItemType Directory

Output

Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp

Mode LastWriteTime Length Name


---- ------------- ------ ----
d---- 2006-05-18 11:29 AM New.Directory

Para crear un archivo, cambie el valor del parámetro ItemType por file . Por ejemplo,
para crear un archivo con el nombre file1.txt en el directorio New.Directory , escriba:

PowerShell

New-Item -Path C:\temp\New.Directory\file1.txt -ItemType file

Output

Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp\New.Directory

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 2006-05-18 11:44 AM 0 file1

Esta misma técnica se puede usar para crear una clave del Registro. De hecho, una clave
del Registro es más fácil de crear porque se trata del único tipo de elemento que hay en
el Registro de Windows. (Las entradas del Registro son propiedades de elementos). Por
ejemplo, para crear una clave llamada _Test en la subclave CurrentVersion , escriba:

PowerShell

New-Item -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\_Test

Output

Hive:
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wi
ndows\CurrentVersion
SKC VC Name Property
--- -- ---- --------
0 0 _Test {}

Cuando escriba una ruta de acceso del Registro, no olvide incluir dos puntos ( : ) en los
nombres de unidad de PowerShell, HKLM: y HKCU: . Sin los dos puntos, PowerShell no
reconoce el nombre de la unidad en la ruta de acceso.

¿Por qué los valores del Registro no son


elementos?
Si usa el cmdlet Get-ChildItem para encontrar los elementos de una clave del Registro,
nunca verá las entradas del Registro de verdad ni sus valores.

Por ejemplo, la clave del Registro


HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run suele contener

varias entradas del Registro que representan las aplicaciones que se ejecutan cuando se
inicia el sistema.

Sin embargo, si usa Get-ChildItem para buscar elementos secundarios en la clave,


solamente verá la subclave OptionalComponents de la clave:

PowerShell

Get-ChildItem HKLM:\Software\Microsoft\Windows\CurrentVersion\Run

Output

Hive:
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Wi
ndows\CurrentVersion\Run
SKC VC Name Property
--- -- ---- --------
3 0 OptionalComponents {}

Aunque sería conveniente tratar las entradas del Registro como elementos, no se puede
especificar una ruta de acceso a una entrada del Registro de una manera que garantice
que sea única. La notación de ruta de acceso no distingue entre la subclave del Registro
Run y la entrada del Registro (Default) en la subclave Run. Es más, dado que los
nombres de las entradas del Registro pueden contener el carácter de barra diagonal
inversa ( \ ), si las entradas del Registro fueran elementos, no podría usar la notación de
ruta de acceso para distinguir una entrada del Registro llamada
Windows\CurrentVersion\Run de la subclave que se encuentra en esa ruta de acceso.

Cambio de nombre de los elementos existentes


Para cambiar el nombre de un archivo o una carpeta, use el cmdlet Rename-Item . El
comando a continuación cambia el nombre del archivo file1.txt por fileOne.txt .

PowerShell

Rename-Item -Path C:\temp\New.Directory\file1.txt fileOne.txt

El cmdlet Rename-Item puede cambiar el nombre de un archivo o una carpeta, pero no


puede mover un elemento. El comando a continuación genera un error porque intenta
mover el archivo del directorio New.Directory al directorio Temp.

PowerShell

Rename-Item -Path C:\temp\New.Directory\fileOne.txt c:\temp\fileOne.txt

Output

Rename-Item : can't rename because the target specified isn't a path.


At line:1 char:12
+ Rename-Item <<<< -Path C:\temp\New.Directory\fileOne c:\temp\fileOne.txt

Movimiento de elementos
Para mover un archivo o una carpeta, use el cmdlet Move-Item .

Por ejemplo, el comando siguiente mueve el directorio New.Directory del directorio


C:\temp a la raíz de la unidad C: . Para confirmar que el elemento se ha movido, incluya

el parámetro PassThru del cmdlet Move-Item . Sin PassThru, el cmdlet Move-Item no


muestra ningún resultado.

PowerShell

Move-Item -Path C:\temp\New.Directory -Destination C:\ -PassThru

Output
Directory: Microsoft.PowerShell.Core\FileSystem::C:\

Mode LastWriteTime Length Name


---- ------------- ------ ----
d---- 2006-05-18 12:14 PM New.Directory

Copia de elementos
Si conoce las operaciones de copia de otros shells, el comportamiento del cmdlet Copy-
Item de PowerShell le resultará inusual. Al copiar un elemento de una ubicación en otra,

Copy-Item no copia el contenido de forma predeterminada.

Por ejemplo, si copia el directorio New.Directory de la unidad C: al directorio C:\temp , el


comando se ejecuta correctamente, pero los archivos del directorio New.Directory no se
copian.

PowerShell

Copy-Item -Path C:\New.Directory -Destination C:\temp

Si muestra el contenido de C:\temp\New.Directory , verá que no hay archivos:

PS> Get-ChildItem -Path C:\temp\New.Directory


PS>

¿Por qué el cmdlet Copy-Item no copia el contenido en la nueva ubicación?

El cmdlet Copy-Item está diseñado para ser genérico; no sirve para copiar archivos y
carpetas. Además, incluso cuando se copian archivos y carpetas, conviene copiar solo el
contenedor y no los elementos que hay en él.

Para copiar todo el contenido de una carpeta, incluya el parámetro Recurse del cmdlet
Copy-Item en el comando. Si ya ha copiado el directorio sin su contenido, agregue el

parámetro Force, que permite sobrescribir la carpeta vacía.

PowerShell

Copy-Item -Path C:\New.Directory -Destination C:\temp -Recurse -Force -


Passthru
Output

Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp

Mode LastWriteTime Length Name


---- ------------- ------ ----
d---- 2006-05-18 1:53 PM New.Directory

Directory: Microsoft.PowerShell.Core\FileSystem::C:\temp\New.Directory

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 2006-05-18 11:44 AM 0 file1

Eliminar elementos
Para eliminar archivos y carpetas, use el cmdlet Remove-Item . Los cmdlets de PowerShell,
como Remove-Item , que pueden realizar cambios importantes e irreversibles, suelen
pedir confirmación cuando se especifican sus comandos. Por ejemplo, si intenta quitar la
carpeta New.Directory , se le pide que confirme el comando, ya que la carpeta contiene
archivos:

PowerShell

Remove-Item C:\temp\New.Directory

Output

Confirm
The item at C:\temp\New.Directory has children and the -recurse parameter
was not
specified. If you continue, all children will be removed with the item. Are
you
sure you want to continue?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

Dado que Yes es la respuesta predeterminada, presione la tecla Entrar para eliminar la
carpeta y sus archivos. Para quitar la carpeta sin confirmar, use el parámetro Recurse.

PowerShell

Remove-Item C:\temp\New.Directory -Recurse


Ejecución de elementos
PowerShell usa el cmdlet Invoke-Item para realizar una acción predeterminada en un
archivo o una carpeta. Esta acción predeterminada viene determinada por el controlador
de aplicación predeterminado en el Registro; el efecto es el mismo que si hiciera doble
clic en el elemento en el Explorador de archivos.

Por ejemplo, suponga que ejecuta el siguiente comando:

PowerShell

Invoke-Item C:\WINDOWS

Aparece una ventana del Explorador en C:\Windows , como si hubiera hecho doble clic en
la carpeta C:\Windows .

Si invoca al archivo Boot.ini en un sistema anterior a Windows Vista:

PowerShell

Invoke-Item C:\boot.ini

Si el tipo de archivo .ini está asociado con el Bloc de notas, el archivo boot.ini se
abre en el Bloc de notas.
Cambiar el estado del equipo
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Para restablecer un equipo en PowerShell, use una herramienta de línea de comandos


estándar, WMI o una clase CIM. Aunque use PowerShell solo para ejecutar la
herramienta, aprender a cambiar el estado de energía de un equipo en PowerShell le
mostrará algunos de los detalles importantes sobre el uso de herramientas externas en
PowerShell.

Bloqueo de un equipo
La única manera de bloquear un equipo directamente con las herramientas estándar
disponibles es llamar a la función LockWorkstation() en user32.dll:

PowerShell

rundll32.exe user32.dll,LockWorkStation

Este comando bloquea inmediatamente la estación de trabajo. Se usa rundll32.exe


para llamar a la función LockWorkStation de user32.dll .

Si se bloquea una estación de trabajo mientras Cambio rápido de usuario está


habilitado, como en Windows XP, el equipo muestra la pantalla de inicio de sesión de
usuario, en lugar de iniciar el protector de pantalla del usuario actual.

Para cerrar sesiones determinadas en un servidor de Terminal Server, use la herramienta


de línea de comandos tsshutdn.exe.

Cierre de la sesión actual


Puede usar varias técnicas diferentes para cerrar una sesión en el sistema local. La
manera más sencilla es usar la herramienta de línea de comandos logoff.exe de
Escritorio remoto/Terminal Services (para obtener más información, en el símbolo del
sistema de PowerShell, escriba logoff /? ). Para cerrar la sesión activa actualmente,
escriba logoff sin argumentos.

También puede usar la herramienta shutdown.exe con su opción de cierre de sesión:


PowerShell

shutdown.exe -l

Otra opción es usar WMI. La clase Win32_OperatingSystem tiene un método


Shutdown. Al invocar el método con la marca 0 se inicia el cierre de sesión:

Para más información, consulte el método Shutdown de la clase


Win32_OperatingSystem.

PowerShell

Get-CimInstance -ClassName Win32_OperatingSystem | Invoke-CimMethod -


MethodName Shutdown

Apagado o reinicio de un equipo


Apagar y reiniciar equipos son tareas similares. La mayoría de las herramientas de línea
de comandos admiten ambas acciones. Windows incluye dos herramientas de línea de
comandos para reiniciar un equipo. Use tsshutdn.exe o shutdown.exe con los
argumentos apropiados. Puede obtener información de uso detallada en tsshutdn.exe
/? o shutdown.exe /? .

También puede realizar las operaciones de apagado y reinicio directamente desde


PowerShell.

Para apagar el equipo, use el comando Stop-Computer .

PowerShell

Stop-Computer

Para reiniciar el sistema operativo, use el comando Restart-Computer.

PowerShell

Restart-Computer

Para forzar un reinicio inmediato del equipo, use el parámetro -Force.

PowerShell

Restart-Computer -Force
Recopilar información acerca de los
equipos
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Los cmdlets del módulo CimCmdlets son los más importantes para tareas de
administración generales del sistema. Todas las opciones de configuración críticas del
subsistema se exponen a través de WMI. Además, WMI trata los datos como objetos
que están en colecciones de uno o más elementos. Dado que PowerShell también
funciona con objetos y tiene una canalización que permite tratar uno o varios objetos de
la misma manera, el acceso genérico a WMI le permite realizar algunas tareas avanzadas
con muy poco esfuerzo.

Enumeración de la configuración de escritorio


Comenzaremos con un comando que recopila información acerca de los escritorios en
el equipo local.

PowerShell

Get-CimInstance -ClassName Win32_Desktop

Se devuelve información de todos los equipos de escritorio, independientemente de si


están en uso.

7 Nota

La información devuelta por algunas clases WMI puede ser muy detallada y, a
menudo, incluir metadatos acerca de la clase WMI.

Dado que la mayoría de las propiedades de estos metadatos tienen nombres que
comienzan por Cim, puede filtrarlas mediante Select-Object . Especifique el parámetro -
ExcludeProperty con "Cim*" como valor. Por ejemplo:

PowerShell

Get-CimInstance -ClassName Win32_Desktop | Select-Object -ExcludeProperty


"CIM*"
Para filtrar los metadatos, use un operador de canalización (|) para enviar los resultados
del comando Get-CimInstance a Select-Object -ExcludeProperty "CIM*" .

Enumerar información del BIOS


La clase Win32_BIOS de WMI devuelve información bastante compacta y completa
sobre el BIOS del sistema en el equipo local:

PowerShell

Get-CimInstance -ClassName Win32_BIOS

Enumerar información del procesador


Puede recuperar información general del procesador mediante la clase
Win32_Processor de WMI, aunque probablemente desee filtrar la información:

PowerShell

Get-CimInstance -ClassName Win32_Processor | Select-Object -ExcludeProperty


"CIM*"

Para obtener una cadena descriptiva genérica de la familia del procesador, puede
devolver la propiedad SystemType:

PowerShell

Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property


SystemType

SystemType
----------
X86-based PC

Enumeración del modelo y el fabricante del


equipo
La información del modelo del equipo también está disponible en
Win32_ComputerSystem. La salida estándar mostrada no necesita ningún filtrado para
proporcionar datos de OEM:
PowerShell

Get-CimInstance -ClassName Win32_ComputerSystem

Output

Name PrimaryOwnerName Domain TotalPhysicalMemory Model


Manufacturer
---- ---------------- ------ ------------------- -----
------------
MyPC Jane Doe WORKGROUP 804765696 DA243A-ABA 6415cl NA910
Compaq Presario 06

La salida de comandos como este, que devuelven información directamente de


determinado hardware, es tan buena como los datos que posee. Los fabricantes del
hardware no configuran correctamente algunos datos, por lo que podrían no estar
disponibles.

Enumeración de las revisiones instaladas


Puede enumerar todas las revisiones instaladas mediante Win32_QuickFixEngineering:

PowerShell

Get-CimInstance -ClassName Win32_QuickFixEngineering

Esta clase devuelve una lista de revisiones que se ve así:

Output

Source Description HotFixID InstalledBy InstalledOn PSComputerName


------ ----------- -------- ----------- ----------- --------------
Security Update KB4048951 Administrator 12/16/2017 .

Para obtener una salida más concisa, puede excluir algunas propiedades. Aunque puede
usar el parámetro Property de Get-CimInstance para elegir solo HotFixID, al hacerlo se
devolverá más información, porque se muestran todos los metadatos de manera
predeterminada:

PowerShell

Get-CimInstance -ClassName Win32_QuickFixEngineering -Property HotFixID


Output

InstalledOn :
Caption :
Description :
InstallDate :
Name :
Status :
CSName :
FixComments :
HotFixID : KB4533002
InstalledBy :
ServicePackInEffect :
PSComputerName :
CimClass : root/cimv2:Win32_QuickFixEngineering
CimInstanceProperties : {Caption, Description, InstallDate, Name…}
CimSystemProperties :
Microsoft.Management.Infrastructure.CimSystemProperties
...

Se devuelven los datos adicionales, ya que el parámetro Property de Get-CimInstance


restringe las propiedades devueltas de instancias de la clase WMI, no el objeto que se
devuelve a PowerShell. Para reducir la salida, use Select-Object :

PowerShell

Get-CimInstance -ClassName Win32_QuickFixEngineering -Property HotFixId |


Select-Object -Property HotFixId

Output

HotFixId
--------
KB4048951

Enumeración de la información de versión del


sistema operativo
Las propiedades de la clase Win32_OperatingSystem incluyen información acerca de la
versión y del Service Pack. Solo puede seleccionar explícitamente estas propiedades
para obtener un resumen de la información de versión de Win32_OperatingSystem:

PowerShell

Get-CimInstance -ClassName Win32_OperatingSystem |


Select-Object -Property
BuildNumber,BuildType,OSType,ServicePackMajorVersion,ServicePackMinorVersion

También puede usar caracteres comodín con el parámetro Property. Dado que todas las
propiedades que comienzan por Build o ServicePack son importantes para usar aquí,
podemos reducirlo al formato siguiente:

PowerShell

Get-CimInstance -ClassName Win32_OperatingSystem |


Select-Object -Property Build*,OSType,ServicePack*

Output

BuildNumber : 18362
BuildType : Multiprocessor Free
OSType : 18
ServicePackMajorVersion : 0
ServicePackMinorVersion : 0

Enumeración del propietario y los usuarios


locales
Puede encontrar información general sobre los usuarios locales con una selección de las
propiedades de clase Win32_OperatingSystem. Puede seleccionar explícitamente las
propiedades para que tengan el aspecto siguiente:

PowerShell

Get-CimInstance -ClassName Win32_OperatingSystem |


Select-Object -Property NumberOfLicensedUsers, NumberOfUsers,
RegisteredUser

Una versión más concisa con caracteres comodín es:

PowerShell

Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property


*user*

Obtención del espacio en disco disponible


Para ver el espacio en disco y el espacio libre de las unidades locales, puede usar la clase
Win32_LogicalDisk. Solo necesita ver las instancias con un valor de DriveType de 3
(valor que WMI usa para los discos duros fijos).

PowerShell

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3"

Output

DeviceID DriveType ProviderName VolumeName Size FreeSpace


PSComputerName
-------- --------- ------------ ---------- ---- --------- --------
------
C: 3 Local Disk 203912880128 65541357568 .
Q: 3 New Volume 122934034432 44298250240 .

PowerShell

Get-CimInstance -ClassName Win32_LogicalDisk -Filter "DriveType=3" |


Measure-Object -Property FreeSpace,Size -Sum |
Select-Object -Property Property,Sum

Output

Property Sum
-------- ---
FreeSpace 109839607808
Size 326846914560

Obtención de información de la sesión de inicio


Puede obtener información general sobre las sesiones de inicio asociadas a los usuarios
a través de la clase Win32_LogonSession de WMI:

PowerShell

Get-CimInstance -ClassName Win32_LogonSession

Obtención del usuario que inició sesión en un


equipo
Para ver el usuario que inició sesión en un equipo concreto, use
Win32_ComputerSystem. Este comando devuelve solo el usuario que inició sesión en el
escritorio del sistema:

PowerShell

Get-CimInstance -ClassName Win32_ComputerSystem -Property UserName

Obtención de la hora local de un equipo


Puede recuperar la hora local actual en un equipo específico mediante la clase WMI
Win32_LocalTime.

PowerShell

Get-CimInstance -ClassName Win32_LocalTime

Output

Day : 23
DayOfWeek : 1
Hour : 8
Milliseconds :
Minute : 52
Month : 12
Quarter : 4
Second : 55
WeekInMonth : 4
Year : 2019
PSComputerName :

Visualización del estado del servicio


Para ver el estado de todos los servicios de un equipo concreto, puede usar el cmdlet
Get-Service localmente. Para los sistemas remotos, puede usar la clase Win32_Service

de WMI. Si también usa Select-Object para filtrar los resultados con Status, Name y
DisplayName, el formato de salida es prácticamente idéntico al de Get-Service :

PowerShell

Get-CimInstance -ClassName Win32_Service |


Select-Object -Property Status,Name,DisplayName
Para permitir que se muestren completamente los nombres de servicios que son largos,
use los parámetros AutoSize y Wrap de Format-Table . Estos parámetros optimizan el
ancho de columna y permiten que los nombres largos se encapsulen en lugar de
truncarse:

PowerShell

Get-CimInstance -ClassName Win32_Service |


Format-Table -Property Status, Name, DisplayName -AutoSize -Wrap
Creación de consultas Get-WinEvent con
FilterHashtable
Artículo • 28/06/2023

Este ejemplo solo se aplica a las plataformas Windows.

Para leer la entrada de blog original de Scripting Guy del 3 de junio de 2014, consulte
Use FilterHashTable to Filter Event Log with PowerShell (Uso de FilterHashTable para
filtrar registros de eventos con PowerShell).

Este artículo es un extracto de la entrada de blog original y se explica cómo usar el


parámetro FilterHashtable del cmdlet Get-WinEvent para filtrar registros de eventos. El
cmdlet Get-WinEvent de PowerShell es un método eficaz para filtrar registros de
diagnóstico y eventos de Windows. El rendimiento mejora cuando una consulta Get-
WinEvent utiliza el parámetro FilterHashtable.

Cuando se trabaja con registros de eventos de gran tamaño, no resulta eficaz enviar
objetos a través de la canalización hasta el comando Where-Object . Antes de PowerShell
6, el cmdlet Get-EventLog era otra alternativa para obtener datos de registro. Por
ejemplo, los comandos siguientes no son suficientes para filtrar los registros Microsoft-
Windows-Defrag:

PowerShell

Get-EventLog -LogName Application | Where-Object Source -Match defrag

Get-WinEvent -LogName Application | Where-Object { $_.ProviderName -Match


'defrag' }

El siguiente comando usa una tabla hash que mejora el rendimiento:

PowerShell

Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='*defrag'
}

Entradas de blog sobre la enumeración


En este artículo se presenta información acerca de cómo usar los valores enumerados en
una tabla hash. Para obtener más información sobre la enumeración, lea estas entradas
de blog de Scripting Guy. Para crear una función que devuelva los valores enumerados,
consulte Enumerations and Values (Enumeraciones y valores). Para obtener más
información, consulte la serie de entradas de blob de Scripting Guy sobre la
enumeración .

Pares clave-valor de tablas hash


Para generar consultas eficaces, utilice el cmdlet Get-WinEvent con el parámetro
FilterHashtable. FilterHashtable acepta una tabla hash como un filtro para obtener
información específica de los registros de eventos de Windows. Una tabla hash usa
pares clave-valor. Para obtener más información sobre las tablas hash, consulte
about_Hash_Tables.

Si los pares clave-valor se encuentran en la misma línea, se deben separar mediante


punto y coma. Si cada par clave-valor está en una línea independiente, no es necesario
usar punto y coma. Por ejemplo, en este artículo se colocan los pares clave-valor en
líneas independientes y no se usan puntos y comas.

En este ejemplo se usan varios de los pares clave-valor del parámetro FilterHashtable.
La consulta completada incluye LogName, ProviderName, Keywords, ID y Level.

Los pares clave-valor aceptados se muestran en la tabla siguiente y se incluyen en la


documentación del parámetro FilterHashtable de Get-WinEvent.

En la tabla siguiente se muestran los nombres de clave, los tipos de datos y si se


aceptan caracteres comodín para un valor de datos.

Nombre de clave Tipo de datos de valor ¿Acepta caracteres comodín?

LogName <String[]> Sí

ProviderName <String[]> Sí

Path <String[]> No

Palabras clave <Long[]> No

id <Int32[]> No

Nivel <Int32[]> No

StartTime <DateTime> No
Nombre de clave Tipo de datos de valor ¿Acepta caracteres comodín?

EndTime <DateTime> No

UserID <SID> No

data <String[]> No

<named-data> <String[]> No

La clave <named-data> representa un campo de datos de evento con nombre. Por


ejemplo, el evento 1008 de Perflib puede contener los siguientes datos de evento:

XML

<EventData>
<Data Name="Service">BITS</Data>
<Data Name="Library">C:\Windows\System32\bitsperf.dll</Data>
<Data Name="Win32Error">2</Data>
</EventData>

Puede consultar estos eventos con el comando siguiente:

PowerShell

Get-WinEvent -FilterHashtable @{LogName='Application'; 'Service'='Bits'}

7 Nota

La capacidad de consultar <named-data> se ha agregado en PowerShell 6.

Creación de una consulta con una tabla hash


Para comprobar los resultados y solucionar problemas, es de utilidad generar la tabla
hash con un par clave-valor a la vez. La consulta obtiene datos del registro Aplicación.
La tabla hash es equivalente a Get-WinEvent -LogName Application .

Para comenzar, cree la consulta Get-WinEvent . Use el par clave-valor del parámetro
FilterHashtable con la clave LogName y el valor Application.

PowerShell

Get-WinEvent -FilterHashtable @{
LogName='Application'
}

Continúe para generar la tabla hash con la clave ProviderName. Normalmente,


ProviderName es el nombre que aparece en el campo Origen del Visor de eventos de
Windows. Por ejemplo, .NET Runtime en la captura de pantalla siguiente:

Imagen de los orígenes del Visor de eventos de Windows

Actualice la tabla hash e incluya el par key-value con la clave ProviderName y el valor
.NET Runtime .

PowerShell

Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
}

7 Nota

En el caso de algunos proveedores de eventos, se puede obtener el valor de


ProviderName correcto si se busca en la pestaña Detalles de Propiedades de
evento. Por ejemplo, en los eventos cuyo campo Origen muestra Defrag , el valor
de ProviderName correcto es Microsoft-Windows-Defrag .

Si la consulta tiene que obtener datos de registros de eventos archivados, use la clave
Path. El valor Path especifica la ruta de acceso completa al archivo de registro. Para
obtener más información, consulte la entrada de blog de Scripting GuyUse PowerShell
to Parse Saved Event Logs for Errors (Uso de PowerShell para analizar registros de
eventos guardados de errores).

Uso de valores enumerados en una tabla hash


Keywords es la siguiente clave de la tabla hash. El tipo de datos Keywords es una matriz
del tipo de valor [long] que contiene una gran cantidad. Use el comando siguiente
para encontrar el valor máximo de [long] :

PowerShell

[long]::MaxValue
Output

9223372036854775807

Para la clave Keywords, PowerShell usa un número, no una cadena como Seguridad. El
Visor de eventos de Windows muestra las palabras clave como cadenas, pero son
valores enumerados. En la tabla hash, si usa la clave Keywords con un valor de cadena,
se muestra un mensaje de error.

Abra el Visor de eventos de Windows y en el panel Acciones, haga clic en Filtrar


registro actual. El menú desplegable Palabras clave muestra las palabras clave
disponibles, como se ilustra en la captura de pantalla siguiente:

Imagen de las palabras clave del Visor de eventos de Windows

Use el siguiente comando para mostrar los nombres de propiedades


StandardEventKeywords .

PowerShell

[System.Diagnostics.Eventing.Reader.StandardEventKeywords] |
Get-Member -Static -MemberType Property

Output

TypeName: System.Diagnostics.Eventing.Reader.StandardEventKeywords
Name MemberType Definition
—- ———- ———-
AuditFailure Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
AuditSuccess Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
CorrelationHint Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
CorrelationHint2 Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
EventLogClassic Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
None Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
ResponseTime Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
Sqm Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
WdiContext Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
WdiDiagnostic Property static
System.Diagnostics.Eventing.Reader.StandardEventKey…
Los valores enumerados se documentan en .NET Framework. Para obtener más
información, consulte StandardEventKeywords Enum .

Los valores enumerados y nombres de Keywords son los siguientes:

Nombre Value

AuditFailure 4503599627370496

AuditSuccess 9007199254740992

CorrelationHint2 18014398509481984

EventLogClassic 36028797018963968

Sqm 2251799813685248

WdiDiagnostic 1125899906842624

WdiContext 562949953421312

ResponseTime 281474976710656

None 0

Actualice la tabla hash e incluya el par clave-valor con la clave Keywords y el valor de
enumeración EventLogClassic, 36028797018963968.

PowerShell

Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
}

Valor de propiedad estática de palabras clave (opcional)


La clave Keywords se enumera, pero puede usar un nombre de propiedad estática en la
consulta de tabla hash. En lugar de usar la cadena devuelta, el nombre de propiedad
debe convertirse en un valor con la propiedad Value__ .

Por ejemplo, el script siguiente usa la propiedad Value__ .

PowerShell

$C =
[System.Diagnostics.Eventing.Reader.StandardEventKeywords]::EventLogClassic
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=$C.Value__
}

Filtro por identificador de evento


Para obtener datos más específicos, los resultados de la consulta se filtran por
identificador de evento. Se hace referencia al identificador de evento en la tabla hash
como la clave ID y el valor es un identificador de evento determinado. El Visor de
eventos de Windows muestra el identificador de evento. En este ejemplo se utiliza
Event Id 1023.

Actualice la tabla hash e incluya el par clave-valor con la clave ID y el valor 1023.

PowerShell

Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
ID=1023
}

Filtro por nivel


Para refinar más los resultados e incluir solo los eventos que indican errores, use la clave
Level. El Visor de eventos de Windows muestra el nivel como valores de cadena, pero
son valores enumerados. En la tabla hash, si usa la clave Level con un valor de cadena,
se muestra un mensaje de error.

Level tiene valores como Error, Advertencia o Información. Use el siguiente comando
para mostrar los nombres de propiedades StandardEventLevel .

PowerShell

[System.Diagnostics.Eventing.Reader.StandardEventLevel] |
Get-Member -Static -MemberType Property

Output

TypeName: System.Diagnostics.Eventing.Reader.StandardEventLevel
Name MemberType Definition
---- ---------- ----------
Critical Property static
System.Diagnostics.Eventing.Reader.StandardEventLevel Critical {get;}
Error Property static
System.Diagnostics.Eventing.Reader.StandardEventLevel Error {get;}
Informational Property static
System.Diagnostics.Eventing.Reader.StandardEventLevel Informational {get;}
LogAlways Property static
System.Diagnostics.Eventing.Reader.StandardEventLevel LogAlways {get;}
Verbose Property static
System.Diagnostics.Eventing.Reader.StandardEventLevel Verbose {get;}
Warning Property static
System.Diagnostics.Eventing.Reader.StandardEventLevel Warning {get;}

Los valores enumerados se documentan en .NET Framework. Para obtener más


información, consulte StandardEventLevel Enum.

Los valores enumerados y nombres de la clave Level son los siguientes:

Nombre Value

Verbose 5

Informativo 4

Advertencia 3

Error 2

Crítico 1

LogAlways 0

La tabla hash de la consulta completada incluye la clave, Level, y el valor, 2.

PowerShell

Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
ID=1023
Level=2
}

Propiedad estática de nivel en enumeración (opcional)


La clave Level se enumera, pero puede usar un nombre de propiedad estática en la
consulta de tabla hash. En lugar de usar la cadena devuelta, el nombre de propiedad
debe convertirse en un valor con la propiedad Value__ .

Por ejemplo, el script siguiente usa la propiedad Value__ .

PowerShell

$C = [System.Diagnostics.Eventing.Reader.StandardEventLevel]::Informational
Get-WinEvent -FilterHashtable @{
LogName='Application'
ProviderName='.NET Runtime'
Keywords=36028797018963968
ID=1023
Level=$C.Value__
}
Administración de procesos con cmdlets
Process
Artículo • 13/04/2023

Este ejemplo solo se aplica a Windows PowerShell 5.1.

Puede usar los cmdlets Process de PowerShell para administrar procesos locales y
remotos en PowerShell.

Obtención de procesos
Para obtener los procesos que se están ejecutando en el equipo local, ejecute Get-
Process sin parámetros.

Puede obtener determinados procesos especificando sus nombres de proceso o


identificadores de proceso. El siguiente comando obtiene el proceso inactivo:

PowerShell

Get-Process -id 0

Output

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
0 0 0 16 0 0 Idle

Aunque es normal que los cmdlets no devuelvan datos en algunas situaciones, cuando
se especifica un proceso por su valor de ProcessId, Get-Process genera un error si no se
encuentran coincidencias, porque la intención habitual consiste en recuperar un proceso
en ejecución conocido. Si no hay ningún proceso con ese identificador, es probable que
el identificador sea incorrecto o que el proceso de interés haya terminado:

PowerShell

Get-Process -Id 99

Output
Get-Process : No process with process ID 99 was found.
At line:1 char:12
+ Get-Process <<<< -Id 99

Puede usar el parámetro Name del cmdlet Get-Process para especificar un subconjunto
de procesos basado en el nombre del proceso. El parámetro Name puede tomar varios
nombres de una lista de nombres separados por comas y admite el uso de caracteres
comodín, para que pueda escribir patrones de nombre.

Por ejemplo, el siguiente comando obtiene el proceso cuyos nombres comienzan por
"ex".

PowerShell

Get-Process -Name ex*

Output

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
234 7 5572 12484 134 2.98 1684 EXCEL
555 15 34500 12384 134 105.25 728 explorer

Dado que la clase System.Diagnostics.Process de .NET es la base de los procesos de


PowerShell, sigue algunas de las convenciones usadas por System.Diagnostics.Process.
Una de estas convenciones es que el nombre de proceso de un archivo ejecutable
nunca incluya .exe al final del nombre del ejecutable.

Get-Process también acepta varios valores para el parámetro Name.

PowerShell

Get-Process -Name exp*,power*

Output

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
540 15 35172 48148 141 88.44 408 explorer
605 9 30668 29800 155 7.11 3052 powershell

Puede usar el parámetro ComputerName de Get-Process para obtener procesos en


equipos remotos. Por ejemplo, el comando siguiente obtiene los procesos de
PowerShell en el equipo local (representado por "localhost") y en dos equipos remotos.

PowerShell

Get-Process -Name PowerShell -ComputerName localhost, Server01, Server02

Output

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
258 8 29772 38636 130 3700 powershell
398 24 75988 76800 572 5816 powershell
605 9 30668 29800 155 7.11 3052 powershell

Los nombres de equipo no son evidentes en esta pantalla, pero se almacenan en la


propiedad MachineName de los objetos de proceso que devuelve Get-Process . El
siguiente comando usa el cmdlet Format-Table para mostrar el identificador de proceso
y las propiedades ProcessName y MachineName (ComputerName) de los objetos de
proceso.

PowerShell

Get-Process -Name PowerShell -ComputerName localhost, Server01, Server01 |


Format-Table -Property ID, ProcessName, MachineName

Output

Id ProcessName MachineName
-- ----------- -----------
3700 powershell Server01
3052 powershell Server02
5816 powershell localhost

Este comando más complejo agrega la propiedad MachineName a la presentación


estándar de Get-Process .

PowerShell

Get-Process powershell -ComputerName localhost, Server01, Server02 |


Format-Table -Property Handles,
@{Label="NPM(K)";Expression={[int]($_.NPM/1024)}},
@{Label="PM(K)";Expression={[int]($_.PM/1024)}},
@{Label="WS(K)";Expression={[int]($_.WS/1024)}},
@{Label="VM(M)";Expression={[int]($_.VM/1MB)}},
@{Label="CPU(s)";Expression={if ($_.CPU -ne $())
{$_.CPU.ToString("N")}}},
Id, ProcessName, MachineName -auto

Output

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName MachineName


------- ------ ----- ----- ----- ------ -- ----------- -----------
258 8 29772 38636 130 3700 powershell Server01
398 24 75988 76800 572 5816 powershell localhost
605 9 30668 29800 155 7.11 3052 powershell Server02

Detención de procesos
PowerShell ofrece flexibilidad para enumerar procesos, pero ¿qué hay de detenerlos?

El cmdlet Stop-Process toma un valor de Name o Id para especificar un proceso que


quiere detener. Su capacidad para detener procesos dependerá de sus permisos.
Algunos procesos no se pueden detener. Por ejemplo, si intenta detener el proceso
inactivo, obtendrá un error:

PowerShell

Stop-Process -Name Idle

Output

Stop-Process : Process 'Idle (0)' cannot be stopped due to the following


error:
Access is denied
At line:1 char:13
+ Stop-Process <<<< -Name Idle

También puede forzar la solicitud con el parámetro Confirm. Este parámetro es


especialmente útil si se usa un carácter comodín al especificar el nombre del proceso, ya
que accidentalmente podría coincidir con algunos procesos que no quiere detener:

PowerShell

Stop-Process -Name t*,e* -Confirm

Output

Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Process" on Target "explorer (408)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):n
Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Process" on Target "taskmgr (4072)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):n

La manipulación de procesos complejos es posible si se usan algunos cmdlets de


filtrado de objetos. Dado que un objeto Process tiene una propiedad Responding que
es true cuando ya no responde, puede detener todas las aplicaciones que no respondan
con el comando siguiente:

PowerShell

Get-Process | Where-Object -FilterScript {$_.Responding -eq $false} | Stop-


Process

Puede usar el mismo enfoque en otras situaciones. Por ejemplo, supongamos que una
aplicación de área de notificaciones secundaria se ejecuta automáticamente cuando los
usuarios inician otra aplicación. Es posible que esto no funcione correctamente en las
sesiones de Terminal Services, pero lo quiera seguir manteniendo en las sesiones que se
ejecutan en la consola del equipo físico. Las sesiones conectadas en el escritorio del
equipo físico siempre tienen un identificador de la sesión 0, por lo que puede detener
todas las instancias del proceso que están en otras sesiones mediante Where-Object y el
proceso, SessionId:

PowerShell

Get-Process -Name BadApp | Where-Object -FilterScript {$_.SessionId -neq 0}


| Stop-Process

El cmdlet Stop-Process no tiene un parámetro ComputerName. Por lo tanto, para


ejecutar un comando para detener un proceso en un equipo remoto, debe usar el
cmdlet Invoke-Command . Por ejemplo, para detener el proceso de PowerShell en el
equipo remoto Server01, escriba:

PowerShell

Invoke-Command -ComputerName Server01 {Stop-Process Powershell}


Detención de todas las demás sesiones de
PowerShell
En ocasiones puede ser útil poder detener todas las sesiones de PowerShell que se están
ejecutando, excepto la sesión actual. Si una sesión usa demasiados recursos o es
inaccesible (quizás se esté ejecutando de forma remota o en otra sesión de escritorio),
es posible que no pueda detenerla directamente. Si intenta detener todas las sesiones
que se están ejecutando, la sesión actual podría finalizar en su lugar.

Cada sesión de PowerShell tiene un PID de variable de entorno que contiene el valor de
Id del proceso de Windows PowerShell. Puede comprobar el $PID con el identificador
de cada sesión y finalizar solo las sesiones de Windows PowerShell que tengan un
identificador diferente. El siguiente comando de canalización realiza esta acción y
devuelve la lista de las sesiones finalizadas (debido al uso del parámetro PassThru):

PowerShell

Get-Process -Name powershell | Where-Object -FilterScript {$_.Id -ne $PID} |


Stop-Process -PassThru

Output

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
334 9 23348 29136 143 1.03 388 powershell
304 9 23152 29040 143 1.03 632 powershell
302 9 20916 26804 143 1.03 1116 powershell
335 9 25656 31412 143 1.09 3452 powershell
303 9 23156 29044 143 1.05 3608 powershell
287 9 21044 26928 143 1.02 3672 powershell

Inicio, depuración y espera de procesos


PowerShell también incluye cmdlets para iniciar (o reiniciar) y depurar un proceso, así
como para esperar a que un proceso se complete antes de ejecutar un comando. Para
obtener información acerca de estos cmdlets, vea el tema de ayuda de cada cmdlet.

Consulte también
Get-Process
Stop-Process
Start-Process
Wait-Process
Debug-Process
Invoke-Command
Administración de servicios
Artículo • 13/04/2023

Este ejemplo solo se aplica a Windows PowerShell 5.1.

Existen ocho cmdlets Service principales, diseñados para una amplia variedad de tareas
de servicio. En este artículo solo se examina la enumeración y el cambio del estado de
ejecución de los servicios. Puede obtener una lista de cmdlets de servicio mediante Get-
Command *-Service . Puede encontrar información sobre cada cmdlet mediante Get-Help

<Cmdlet-Name> , como Get-Help New-Service .

Obtención de servicios
Puede obtener los servicios en un equipo local o remoto mediante el cmdlet Get-
Service . Del mismo modo que ocurre con Get-Process , si usa el comando Get-Service
sin parámetros, se devolverán todos los servicios. Puede filtrar por nombre, incluso con
un asterisco como carácter comodín:

PowerShell

PS> Get-Service -Name se*

Status Name DisplayName


------ ---- -----------
Running seclogon Secondary Logon
Running SENS System Event Notification
Stopped ServiceLayer ServiceLayer

Dado que no siempre es evidente cuál es el nombre real del servicio, es posible que
necesite buscar servicios por el nombre para mostrar. Puede buscar por el nombre
específico, usar caracteres comodín o proporcionar una lista de nombres para mostrar:

PowerShell

PS> Get-Service -DisplayName se*

Status Name DisplayName


------ ---- -----------
Running lanmanserver Server
Running SamSs Security Accounts Manager
Running seclogon Secondary Logon
Stopped ServiceLayer ServiceLayer
Running wscsvc Security Center
PS> Get-Service -DisplayName ServiceLayer, Server

Status Name DisplayName


------ ---- -----------
Running lanmanserver Server
Stopped ServiceLayer ServiceLayer

Obtención de servicios remotos


Con Windows PowerShell, puede usar el parámetro ComputerName del cmdlet Get-
Service para obtener los servicios en equipos remotos. El parámetro ComputerName

acepta varios valores y caracteres comodín, por lo que puede obtener los servicios en
varios equipos con un solo comando. Por ejemplo, el siguiente comando obtiene los
servicios en el equipo remoto Server01.

PowerShell

Get-Service -ComputerName Server01

A partir de PowerShell 6.0, los cmdlets *-Service no tienen el parámetro


ComputerName. Puede seguir obteniendo servicios en equipos remotos con la
comunicación remota de PowerShell. Por ejemplo, el siguiente comando obtiene los
servicios en el equipo remoto Server02.

PowerShell

Invoke-Command -ComputerName Server02 -ScriptBlock { Get-Service }

También puede administrar los servicios con los otros cmdlets *-Service . Para más
información sobre la comunicación remota de PowerShell, consulte about_Remote.

Obtención de servicios necesarios y


dependientes
El cmdlet Get-Service tiene dos parámetros que son muy útiles para la administración
de servicios. El parámetro DependentServices obtiene servicios que dependen del
servicio.

El parámetro RequiredServices obtiene servicios de los que depende este servicio el


servicio LanmanWorkstation.
PowerShell

PS> Get-Service -Name LanmanWorkstation -RequiredServices

Status Name DisplayName


------ ---- -----------
Running MRxSmb20 SMB 2.0 MiniRedirector
Running bowser Bowser
Running MRxSmb10 SMB 1.x MiniRedirector
Running NSI Network Store Interface Service

El parámetro DependentServices obtiene el servicio LanmanWorkstation necesario.

PowerShell

PS> Get-Service -Name LanmanWorkstation -DependentServices

Status Name DisplayName


------ ---- -----------
Running SessionEnv Terminal Services Configuration
Running Netlogon Netlogon
Stopped Browser Computer Browser
Running BITS Background Intelligent Transfer Ser...

El siguiente comando obtiene todos los servicios que tienen dependencias. El cmdlet
Format-Table para mostrar las propiedades Status, Name, RequiredServices y
DependentServices de los servicios.

PowerShell

Get-Service -Name * | Where-Object {$_.RequiredServices -or


$_.DependentServices} |
Format-Table -Property Status, Name, RequiredServices, DependentServices -
auto

Detención, inicio, suspensión y reinicio de los


servicios
Todos los cmdlets Service tienen el mismo formato general. Los servicios pueden
especificarse por el nombre común o el nombre para mostrar, y toman listas y
caracteres comodín como valores. Para detener el administrador de trabajos de
impresión, use:

PowerShell
Stop-Service -Name spooler

Para iniciar el administrador de trabajos de impresión una vez detenido, use:

PowerShell

Start-Service -Name spooler

Para suspender el administrador de trabajos de impresión, use:

PowerShell

Suspend-Service -Name spooler

El cmdlet Restart-Service funciona de la misma manera que los otros cmdlets Service:

PowerShell

PS> Restart-Service -Name spooler

WARNING: Waiting for service 'Print Spooler (Spooler)' to finish starting...


WARNING: Waiting for service 'Print Spooler (Spooler)' to finish starting...
PS>

Observará que obtiene un mensaje de advertencia repetido sobre el inicio del


administrador de trabajos de impresión. Si realiza una operación de servicio que tarda
bastante tiempo, PowerShell le notifica que todavía está intentando realizar la tarea.

Si desea reiniciar varios servicios, puede obtener una lista de estos, filtrarlos y, después,
ejecutar el reinicio:

PowerShell

PS> Get-Service | Where-Object -FilterScript {$_.CanStop} | Restart-Service

WARNING: Waiting for service 'Computer Browser (Browser)' to finish


stopping...
WARNING: Waiting for service 'Computer Browser (Browser)' to finish
stopping...
Restart-Service : can't stop service 'Logical Disk Manager (dmserver)'
because
it has dependent services. It can only be stopped if the Force flag is set.
At line:1 char:57
+ Get-Service | Where-Object -FilterScript {$_.CanStop} | Restart-Service
<<<<
WARNING: Waiting for service 'Print Spooler (Spooler)' to finish starting...
WARNING: Waiting for service 'Print Spooler (Spooler)' to finish starting...

Estos cmdlets Service no tienen un parámetro ComputerName, pero se pueden ejecutar


en un equipo remoto mediante el cmdlet Invoke-Command . Por ejemplo, el siguiente
comando reinicia el servicio de administrador de trabajos en cola en el equipo remoto
Server01.

PowerShell

Invoke-Command -ComputerName Server01 {Restart-Service Spooler}

Establecimiento de las propiedades del servicio


El cmdlet Set-Service cambia las propiedades de un servicio en un equipo local o
remoto. Dado que el estado del servicio es una propiedad, puede usar este cmdlet para
iniciar, detener y suspender un servicio. El cmdlet Set-Service también tiene un
parámetro StartupType que permite cambiar el tipo de inicio del servicio.

Para usar Set-Service en Windows Vista y en versiones posteriores de Windows, abra


PowerShell con la opción Ejecutar como administrador.

Para obtener más información, consulte Set-Service

Consulte también
about_Remote
Get-Service
Set-Service
Restart-Service
Suspend-Service
Trabajar con impresoras en Windows
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Puede usar PowerShell para administrar impresoras mediante WMI y el objeto COM
WScript.Network de WSH.

Enumeración de las conexiones de impresora


La manera más sencilla de enumerar las impresoras instaladas en un equipo es usar la
clase WMI Win32_Printer:

PowerShell

Get-CimInstance -Class Win32_Printer

También puede enumerar las impresoras mediante el objeto COM WScript.Network que
suele usarse en los scripts de WSH:

PowerShell

(New-Object -ComObject WScript.Network).EnumPrinterConnections()

Dado que este comando devuelve una colección de cadenas simple de nombres de
puerto y nombres de dispositivo de impresión sin ninguna etiqueta distintiva, no es fácil
de interpretar.

Adición de una impresora de red


Para agregar una nueva impresora de red, use WScript.Network:

PowerShell

(New-Object -ComObject
WScript.Network).AddWindowsPrinterConnection("\\Printserver01\Xerox5")
Establecimiento de una impresora
predeterminada
Para usar WMI para establecer la impresora predeterminada, busque la impresora en la
colección Win32_Printer y luego invoque el método SetDefaultPrinter:

PowerShell

$printer = Get-CimInstance -Class Win32_Printer -Filter "Name='HP LaserJet


5Si'"
Invoke-CimMethod -InputObject $printer -MethodName SetDefaultPrinter

WScript.Network es un poco más fácil de usar, porque tiene un método


SetDefaultPrinter que toma el nombre de la impresora como argumento:

PowerShell

(New-Object -ComObject WScript.Network).SetDefaultPrinter('HP LaserJet 5Si')

Eliminación de una conexión de impresora


Para quitar una conexión de impresora, use el método WScript.Network
RemovePrinterConnection:

PowerShell

(New-Object -ComObject
WScript.Network).RemovePrinterConnection("\\Printserver01\Xerox5")
Realizar tareas de redes
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Dado que TCP/IP es el protocolo de red más usado, la mayoría de las tareas de
administración de protocolo de red de bajo nivel implican TCP/IP. En esta sección, se
usan PowerShell y WMI para realizar estas tareas.

Enumeración de las direcciones IP de un


equipo
Para obtener todas las direcciones IP en uso en el equipo local, use el siguiente
comando:

PowerShell

Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter


IPEnabled=$true |
Select-Object -ExpandProperty IPAddress

Puesto que la propiedad IPAddress de un objeto Win32_NetworkAdapterConfiguration


es una matriz, debe usar el parámetro ExpandProperty de Select-Object para ver toda
la lista de direcciones.

Output

10.0.0.1
fe80::60ea:29a7:a233:7cb7
2601:600:a27f:a470:f532:6451:5630:ec8b
2601:600:a27f:a470:e167:477d:6c5c:342d
2601:600:a27f:a470:b021:7f0d:eab9:6299
2601:600:a27f:a470:a40e:ebce:1a8c:a2f3
2601:600:a27f:a470:613c:12a2:e0e0:bd89
2601:600:a27f:a470:444f:17ec:b463:7edd
2601:600:a27f:a470:10fd:7063:28e9:c9f3
2601:600:a27f:a470:60ea:29a7:a233:7cb7
2601:600:a27f:a470::2ec1

Con el cmdlet Get-Member puede ver que la propiedad IPAddress es una matriz:

PowerShell
Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter
IPEnabled=$true |
Get-Member -Name IPAddress

Output

TypeName:
Microsoft.Management.Infrastructure.CimInstance#root/cimv2/Win32_NetworkAdap
terConfiguration

Name MemberType Definition


---- ---------- ----------
IPAddress Property string[] IPAddress {get;}

La propiedad IPAddress de cada adaptador de red es en realidad una matriz. Las llaves
de la definición indican que IPAddress no es un valor System.String, sino una matriz de
valores System.String.

Enumeración de datos de configuración IP


Para mostrar datos detallados de configuración de IP de cada adaptador de red, use el
siguiente comando:

PowerShell

Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter


IPEnabled=$true

La visualización predeterminada del objeto de configuración del adaptador de red es un


conjunto muy reducido de datos disponibles. Para la inspección en profundidad y la
solución de problemas, use Select-Object o un cmdlet de formato, como Format-List ,
para especificar las propiedades que se mostrarán.

En redes TCP/IP modernas, probablemente no le interesan las propiedades IPX o WINS.


Puede usar el parámetro ExcludeProperty de Select-Object para ocultar las
propiedades con nombres que comienzan por "WINS" o "IPX".

PowerShell

Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter


IPEnabled=$true |
Select-Object -ExcludeProperty IPX*,WINS*
Este comando devuelve información detallada acerca de DHCP, DNS, el enrutamiento y
otras propiedades de configuración de IP secundarias.

Hacer ping a los equipos


Puede hacer ping simplemente en un equipo mediante Win32_PingStatus. El comando
siguiente hace ping, pero devuelve una salida larga:

PowerShell

Get-CimInstance -Class Win32_PingStatus -Filter "Address='127.0.0.1'"

Un formato más útil de información resumida de la presentación de las propiedades


Address, ResponseTime y StatusCode, como el que genera el siguiente comando. El
parámetro Autosize de Format-Table cambia el tamaño de las columnas de la tabla para
que se muestren correctamente en PowerShell.

PowerShell

Get-CimInstance -Class Win32_PingStatus -Filter "Address='127.0.0.1'" |


Format-Table -Property Address,ResponseTime,StatusCode -Autosize

Output

Address ResponseTime StatusCode


------- ------------ ----------
127.0.0.1 0 0

Un StatusCode de 0 indica un ping correcto.

Puede usar una matriz para hacer ping a varios equipos con un solo comando. Dado
que hay más de una dirección, use ForEach-Object para hacer ping a cada dirección por
separado:

PowerShell

'127.0.0.1','localhost','bing.com' |
ForEach-Object -Process {
Get-CimInstance -Class Win32_PingStatus -Filter ("Address='$_'") |
Select-Object -Property Address,ResponseTime,StatusCode
}
Puede usar el mismo formato de comando para hacer ping a todas las direcciones de
una subred, como una red privada que use el número de red 192.168.1.0 y una máscara
de subred de clase C estándar (255.255.255.0). Solo las direcciones del intervalo de
192.168.1.1 a 192.168.1.254 son direcciones locales legítimas (0 se reserva siempre al
número de red y 255 es una dirección de difusión de subred).

Para representar una matriz de los números del 1 al 254 en PowerShell, use la expresión
1..254 . Para hacer ping a una subred completa, se puede agregar cada valor del rango
a una dirección parcial de la instrucción ping:

PowerShell

1..254| ForEach-Object -Process {


Get-CimInstance -Class Win32_PingStatus -Filter ("Address='192.168.1.$_'")
} |
Select-Object -Property Address,ResponseTime,StatusCode

Tenga en cuenta que esta técnica para generar un intervalo de direcciones puede usarse
también en otras ubicaciones. Puede generar un conjunto completo de direcciones de
esta manera:

PowerShell

$ips = 1..254 | ForEach-Object -Process {'192.168.1.' + $_}

Recuperación de las propiedades del adaptador


de red
Anteriormente, mencionamos que podía recuperar las propiedades de configuración
general mediante la clase Win32_NetworkAdapterConfiguration. Aunque no sea
estrictamente información de TCP/IP, la información del adaptador de red, como las
direcciones MAC y los tipos de adaptador, puede ser útil para comprender lo que ocurre
con un equipo. Para obtener un resumen de esta información, use el siguiente comando:

PowerShell

Get-CimInstance -Class Win32_NetworkAdapter -ComputerName .

Asignación del dominio DNS de un adaptador


de red
Para asignar el dominio DNS para la resolución de nombres automática, use el método
SetDNSDomain de Win32_NetworkAdapterConfiguration. El parámetro Query de
Invoke-CimMethod toma una cadena de consulta de WQL. El cmdlet llama al método

especificado en cada instancia devuelta por la consulta.

PowerShell

$wql = 'SELECT * FROM Win32_NetworkAdapterConfiguration WHERE


IPEnabled=True'
$args = @{ DnsDomain = 'fabrikam.com'}
Invoke-CimMethod -MethodName SetDNSDomain -Arguments $args -Query $wql

El filtrado por IPEnabled=True es necesario, porque incluso en una red que usa solo
TCP/IP, varias de las configuraciones del adaptador de red de un equipo no son
verdaderos adaptadores TCP/IP. Son elementos de software generales que admiten RAS,
VPN, QoS y otros servicios para todos los adaptadores y, por tanto, no tienen una
dirección propia.

Realización de tareas de configuración de


DHCP
La modificación de detalles de DHCP implica trabajar con un conjunto de adaptadores
de red, igual que en la configuración de DNS. Hay varias acciones distintas que puede
realizar mediante WMI.

Búsqueda de adaptadores habilitados para DHCP


Para buscar los adaptadores con DHCP habilitado en un equipo, use el siguiente
comando:

PowerShell

Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter


"DHCPEnabled=$true"

Para excluir los adaptadores con problemas de configuración de IP, puede recuperar
solo los adaptadores con IP habilitada:

PowerShell

Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter


"IPEnabled=$true and DHCPEnabled=$true"
Recuperación de propiedades de DHCP
Dado que las propiedades relacionadas con DHCP de un adaptador suelen empezar por
DHCP , puede usar el parámetro Property de Format-Table para mostrar solo esas

propiedades:

PowerShell

Get-CimInstance -Class Win32_NetworkAdapterConfiguration -Filter


"IPEnabled=$true and DHCPEnabled=$true" |
Format-Table -Property DHCP*

Habilitación de DHCP en cada adaptador


Para habilitar DHCP en todos los adaptadores, use el siguiente comando:

PowerShell

$wql = 'SELECT * from Win32_NetworkAdapterConfiguration WHERE IPEnabled=True


and DHCPEnabled=False'
Invoke-CimMethod -MethodName ReleaseDHCPLease -Query $wql

El uso de la instrucción de filtrado IPEnabled=True and DHCPEnabled=False evita habilitar


DHCP cuando ya está habilitado.

Liberación y renovación de las concesiones DHCP en


adaptadores específicos
Las instancias de la clase Win32_NetworkAdapterConfiguration tienen métodos
ReleaseDHCPLease y RenewDHCPLease . Ambos se usan de la misma manera. En general,
use estos métodos si solo necesita liberar o renovar direcciones de un adaptador en una
subred específica. La manera más fácil de filtrar adaptadores en una subred es elegir
solo las configuraciones de adaptador que usen la puerta de enlace para esa subred. Por
ejemplo, el comando siguiente libera todas las concesiones DHCP de los adaptadores en
el equipo local que obtienen concesiones DHCP de 192.168.1.254:

PowerShell

$wql = 'SELECT * from Win32_NetworkAdapterConfiguration WHERE


DHCPServer="192.168.1.1"'
Invoke-CimMethod -MethodName ReleaseDHCPLease -Query $wql
El único cambio en la renovación de una concesión DHCP es que se usa el método
RenewDHCPLease en lugar de ReleaseDHCPLease :

PowerShell

$wql = 'SELECT * from Win32_NetworkAdapterConfiguration WHERE


DHCPServer="192.168.1.1"'
Invoke-CimMethod -MethodName RenewDHCPLease -Query $wql

7 Nota

Al usar estos métodos en un equipo remoto, tenga en cuenta que puede perder el
acceso al sistema remoto si está conectados a este a través del adaptador con la
concesión liberada o renovada.

Liberación y renovación de las concesiones DHCP en


todos los adaptadores
Puede realizar liberaciones o renovaciones de direcciones DHCP globales en todos los
adaptadores mediante los métodos de Win32_NetworkAdapterConfiguration,
ReleaseDHCPLeaseAll y RenewDHCPLeaseAll . Sin embargo, el comando se debe aplicar a

la clase WMI, en lugar de a un adaptador determinado, porque liberar y renovar


concesiones globalmente se realiza en la clase, no en un adaptador específico. El cmdlet
Invoke-CimMethod puede llamar a los métodos de una clase.

PowerShell

Invoke-CimMethod -ClassName Win32_NetworkAdapterConfiguration -MethodName


ReleaseDHCPLeaseAll

Puede usar el mismo formato de comando para invocar el método


RenewDHCPLeaseAll:

PowerShell

Invoke-CimMethod -ClassName Win32_NetworkAdapterConfiguration -MethodName


RenewDHCPLeaseAll

Creación de un recurso compartido de red


Para crear un recurso compartido de red, use el método Create de Win32_Share:

PowerShell

Invoke-CimMethod -ClassName Win32_Share -MethodName Create -Arguments @{


Path = 'C:\temp'
Name = 'TempShare'
Type = [uint32]0 #Disk Drive
MaximumAllowed = [uint32]25
Description = 'test share of the temp folder'
}

Es equivalente al siguiente comando net share en Windows:

PowerShell

net share tempshare=c:\temp /users:25 /remark:"test share of the temp


folder"

Para llamar a un método de una clase WMI que toma parámetros, debe saber qué
parámetros hay disponibles y sus tipos. Por ejemplo, puede enumerar los métodos de
Win32_Class con los siguientes comandos:

PowerShell

(Get-CimClass -ClassName Win32_Share).CimClassMethods

Output

Name ReturnType Parameters


Qualifiers
---- ---------- ---------- ------
----
Create UInt32 {Access, Description, MaximumAllowed, Name…}
{Constructor, Implemented, MappingStrings, Stati…
SetShareInfo UInt32 {Access, Description, MaximumAllowed}
{Implemented, MappingStrings}
GetAccessMask UInt32 {}
{Implemented, MappingStrings}
Delete UInt32 {}
{Destructor, Implemented, MappingStrings}

Use el comando siguiente para enumerar los parámetros del método Create .

PowerShell

(Get-CimClass -ClassName Win32_Share).CimClassMethods['Create'].Parameters


Output

Name CimType Qualifiers


ReferenceClassName
---- ------- ---------- --------
----------
Access Instance {EmbeddedInstance, ID, In, MappingStrings…}
Description String {ID, In, MappingStrings, Optional}
MaximumAllowed UInt32 {ID, In, MappingStrings, Optional}
Name String {ID, In, MappingStrings}
Password String {ID, In, MappingStrings, Optional}
Path String {ID, In, MappingStrings}
Type UInt32 {ID, In, MappingStrings}

También puede leer la documentación del método Create de la clase Win32_Share.

Eliminación de un recurso compartido de red


Puede quitar un recurso compartido de red con Win32_Share, pero el proceso es
ligeramente diferente al de creación, porque debe recuperar la instancia específica que
se va a quitar en lugar de la clase Win32_Share. En el ejemplo siguiente se elimina el
recurso compartido TempShare:

PowerShell

$wql = 'SELECT * from Win32_Share WHERE Name="TempShare"'


Invoke-CimMethod -MethodName Delete -Query $wql

Conexión a una unidad de red accesible de


Windows
El cmdlet New-PSDrive puede crear una unidad de PowerShell que esté asignada a un
recurso compartido de red.

PowerShell

New-PSDrive -Name "X" -PSProvider "FileSystem" -Root "\\Server01\Public"

Sin embargo, las unidades creadas de esta forma solo están disponibles para la sesión
de PowerShell donde se crean. Para asignar una unidad que esté disponible fuera de
PowerShell (o a otras sesiones de PowerShell), debe usar el parámetro Persist.
PowerShell

New-PSDrive -Persist -Name "X" -PSProvider "FileSystem" -Root


"\\Server01\Public"

7 Nota

Es posible que las unidades asignadas de forma permanente no estén disponibles


cuando se ejecutan en un contexto con privilegios elevados. Este es el
comportamiento predeterminado de UAC de Windows. Para obtener más
información, consulte el artículo siguiente:

Las unidades asignadas no están disponibles desde un símbolo del sistema


con privilegios elevados cuando UAC está configurado para solicitar
credenciales
Trabajar con instalaciones de software
Artículo • 20/03/2023

Las aplicaciones que se han instalado con Windows Installer se pueden encontrar
mediante consultas de WMI, pero no todas las aplicaciones usan Windows Installer. Las
técnicas específicas para buscar aplicaciones instaladas con otras herramientas
dependen del software del instalador.

Por ejemplo, las aplicaciones que se instalan copiando los archivos a una carpeta del
equipo no se pueden administrar normalmente con las técnicas aquí descritas. Puede
administrar estas aplicaciones como archivos y carpetas recurriendo a las técnicas
descritas en Trabajar con archivos y carpetas.

En el caso de software instalado mediante un paquete de instalador, Windows Installer


se puede encontrar mediante las clases Win32Reg_AddRemovePrograms o
Win32_Product, pero ambas plantean problemas. Win32Reg_AddRemovePrograms
solo está disponible si se usa System Center Configuration Manager (SCCM), mientras
que la clase Win32_Product puede ser lenta y tiene efectos secundarios.

U Precaución

La clase Win32_Product no está optimizada para consultas. Las consultas que


utilizan filtros con caracteres comodín provocan que WMI utilice el proveedor MSI
para enumerar todos los productos instalados y, a continuación, analice la lista
completa de forma secuencial para controlar el filtro. Esto también inicia una
comprobación de coherencia de los paquetes instalados, verificando y reparando la
instalación. La validación es un proceso lento y puede provocar errores en los
registros de eventos. Para obtener más información, consulte el artículo de KB
974524 .

En este artículo se proporciona un método alternativo para buscar software instalado.

Consulta de la clave del Registro Uninstall para


buscar el software instalado
La mayoría de las aplicaciones estándar registran un desinstalador con Windows, por lo
que podemos trabajar con ellas localmente buscándolas en el Registro de Windows. No
hay ninguna manera garantizada de encontrar todas las aplicaciones en un sistema. Sin
embargo, es posible encontrar todos los programas con las listas que se muestran en
Agregar o quitar programas en la clave del Registro siguiente:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall .

Podemos encontrar el número de aplicaciones instaladas si contamos el número de


claves del Registro:

PowerShell

$UninstallPath = 'HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall'
(Get-ChildItem -Path $UninstallPath).Count

Output

459

Podemos realizar más búsquedas en esta lista de aplicaciones mediante varias técnicas.
Para ver los valores del Registro en las claves del Registro bajo Uninstall , use el
método GetValue() en las claves del Registro. El valor del método es el nombre de la
entrada del Registro. Por ejemplo, use el comando siguiente a fin de buscar los nombres
para mostrar de las aplicaciones en la clave Uninstall :

PowerShell

Get-ChildItem -Path $UninstallPath |


ForEach-Object -Process { $_.GetValue('DisplayName') } |
Sort-Object

7 Nota

No hay ninguna garantía de que los valores DisplayName sean únicos.

En el ejemplo siguiente se genera una salida similar a la de la clase


Win32Reg_AddRemovePrograms:

PowerShell

Get-ChildItem $UninstallPath |
ForEach-Object {
$ProdID = ($_.Name -split '\\')[-1]
Get-ItemProperty -Path "$UninstallPath\$ProdID" -ea SilentlyContinue
|
Select-Object -Property DisplayName, InstallDate, @{n='ProdID'; e=
{$ProdID}}, Publisher, DisplayVersion
} | Select-Object -First 3

Por motivos de brevedad, en este ejemplo se usa Select-Object para limitar a tres el
número de elementos devueltos.

Output

DisplayName : 7-Zip 22.01 (x64)


InstallDate :
ProdID : 7-Zip
Publisher : Igor Pavlov
DisplayVersion : 22.01

DisplayName : AutoHotkey 1.1.33.10


InstallDate :
ProdID : AutoHotkey
Publisher : Lexikos
DisplayVersion : 1.1.33.10

DisplayName : Beyond Compare 4.4.6


InstallDate : 20230310
ProdID : BeyondCompare4_is1
Publisher : Scooter Software
DisplayVersion : 4.4.6.27483
Descodificación de un comando de
PowerShell desde un proceso en
ejecución
Artículo • 13/04/2023

Este ejemplo solo se ejecuta en plataformas Windows.

En ocasiones, puede tener un proceso de PowerShell en ejecución que ocupa una gran
cantidad de recursos. Este proceso podría ejecutarse en el contexto de un trabajo del
Programador de tareas o el Agente SQL Server. Cuando hay varios procesos de
PowerShell en ejecución, puede ser difícil saber qué proceso representa el problema. En
este artículo se muestra cómo descodificar un bloque de script que se está ejecutando
un proceso de PowerShell.

Creación de un proceso de larga duración


Para demostrar este escenario, abra una nueva ventana de PowerShell y ejecute el
siguiente código. Ejecuta un comando de PowerShell que da como resultado un número
cada minuto durante 10 minutos.

PowerShell

powershell.exe -Command {
$i = 1
while ( $i -le 10 )
{
Write-Output -InputObject $i
Start-Sleep -Seconds 60
$i++
}
}

Visualización del proceso


El cuerpo del comando que PowerShell está ejecutando se almacena en la propiedad
CommandLine de la clase Win32_Process. Si el comando es un comando codificado, la
propiedad CommandLine contiene la cadena "EncodedCommand". Con esta
información, el comando codificado puede ser desofuscado mediante el siguiente
proceso.
Inicie PowerShell como administrador. Es vital que PowerShell se ejecute como
administrador; de lo contrario, no se obtienen resultados al consultar los procesos en
ejecución.

Ejecute el siguiente comando para obtener todos los procesos de PowerShell que tienen
un comando codificado:

PowerShell

$powerShellProcesses = Get-CimInstance -ClassName Win32_Process -Filter


'CommandLine LIKE "%EncodedCommand%"'

El siguiente comando crea un objeto de PowerShell personalizado que contiene el


identificador de proceso y el comando codificado.

PowerShell

$commandDetails = $powerShellProcesses | Select-Object -Property ProcessId,


@{
name = 'EncodedCommand'
expression = {
if ( $_.CommandLine -match 'encodedCommand (.*) -inputFormat' )
{
return $matches[1]
}
}
}

Ahora se puede descodificar el comando codificado. El fragmento de código siguiente


recorre en iteración el objeto de detalles del comando, descodifica el comando
codificado y agrega de nuevo el comando descodificado al objeto para seguir
investigándolo.

PowerShell

$commandDetails | ForEach-Object -Process {


# Get the current process
$currentProcess = $_

# Convert the Base 64 string to a Byte Array


$commandBytes =
[System.Convert]::FromBase64String($currentProcess.EncodedCommand)

# Convert the Byte Array to a string


$decodedCommand =
[System.Text.Encoding]::Unicode.GetString($commandBytes)

# Add the decoded command back to the object


$commandDetails |
Where-Object -FilterScript { $_.ProcessId -eq
$currentProcess.processId } |
Add-Member -MemberType NoteProperty -Name DecodedCommand -Value
$decodedCommand
}
$commandDetails[0] | Format-List -Property *

Ahora se puede revisar el comando descodificado seleccionando la propiedad del


comando descodificado.

Output

ProcessId : 8752
EncodedCommand :
IAAKAAoACgAgAAoAIAAgACAAIAAkAGkAIAA9ACAAMQAgAAoACgAKACAACgAgACAAIAAgAHcAaABp
AGwAZQAgACgAIAAkAGkAIAAtAG

wAZQAgADEAMAAgACkAIAAKAAoACgAgAAoAIAAgACAAIAB7ACAACgAKAAoAIAAKACAAIAAgACAAIA
AgACAAIABXAHIAaQB0AGUALQBP

AHUAdABwAHUAdAAgAC0ASQBuAHAAdQB0AE8AYgBqAGUAYwB0ACAAJABpACAACgAKAAoAIAAKACAA
IAAgACAAIAAgACAAIABTAHQAYQ

ByAHQALQBTAGwAZQBlAHAAIAAtAFMAZQBjAG8AbgBkAHMAIAA2ADAAIAAKAAoACgAgAAoAIAAgAC
AAIAAgACAAIAAgACQAaQArACsA
IAAKAAoACgAgAAoAIAAgACAAIAB9ACAACgAKAAoAIAAKAA==
DecodedCommand :
$i = 1
while ( $i -le 10 )
{
Write-Output -InputObject $i
Start-Sleep -Seconds 60
$i++
}
Redirección de la salida
Artículo • 13/04/2023

PowerShell ofrece varios cmdlets que permiten controlar la salida de datos


directamente. Estos cmdlets comparten dos características importantes.

En primer lugar, suelen transformar datos a algún formato de texto. Lo hacen para
aplicar la salida de datos a componentes del sistema que la entrada de texto. Esto
significa que deben representar los objetos como texto. Por lo tanto, el texto tiene el
formato que puede ver en la ventana de la consola de PowerShell.

En segundo lugar, estos cmdlets usan el verbo Out de PowerShell porque envían
información fuera de Windows PowerShell a alguna otra ubicación.

Salida de consola
De manera predeterminada, PowerShell envía datos a la ventana de host, que es
exactamente lo que hace el cmdlet Out-Host . El uso principal del cmdlet Out-Host es la
paginación. Por ejemplo, el comando siguiente usa Out-Host para paginar la salida del
cmdlet Get-Command :

PowerShell

Get-Command | Out-Host -Paging

La pantalla de la ventana de host se encuentra fuera de PowerShell. Esto es importante


porque los datos se eliminan realmente cuando se envían fuera de PowerShell. Puede
verlo si intenta crear una canalización que pagine los datos en la ventana host y, luego,
intenta formatearla como una lista, tal como se muestra aquí:

PowerShell

Get-Process | Out-Host -Paging | Format-List

Es de esperar que el comando muestre páginas de información de proceso en formato


de lista. En su lugar, muestra la lista tabular predeterminada:

Resultados

Handles NPM(K) PM(K) WS(K) VM(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
101 5 1076 3316 32 0.05 2888 alg
...
618 18 39348 51108 143 211.20 740 explorer
257 8 9752 16828 79 3.02 2560 explorer
...
<SPACE> next page; <CR> next line; Q quit
...

El cmdlet Out-Host envía los datos directamente a la consola, de modo que el comando
Format-List nunca recibe nada a lo que aplicar formato.

La forma correcta de estructurar este comando es colocar el cmdlet Out-Host al final de


la canalización, como se muestra a continuación. Esto hace que los datos de proceso se
formateen en una lista antes de paginarse y mostrarse.

PowerShell

Get-Process | Format-List | Out-Host -Paging

Output

Id : 2888
Handles : 101
CPU : 0.046875
Name : alg
...

Id : 740
Handles : 612
CPU : 211.703125
Name : explorer

Id : 2560
Handles : 257
CPU : 3.015625
Name : explorer
...
<SPACE> next page; <CR> next line; Q quit
...

Esto se aplica a todos los cmdlets Out. Un cmdlet Out siempre debe aparecer al final de
la canalización.

7 Nota

Todos los cmdlets Out representan la salida como texto, con el formato vigente
para la ventana de consola, incluidos los límites de longitud de línea.
Descartar la salida
El cmdlet Out-Null está diseñado para descartar de inmediato cualquier entrada que
reciba. Esto es útil para descartar los datos innecesarios que obtiene como efecto
secundario de la ejecución de un comando. Si escribe el comando siguiente, no se
obtienen resultados:

PowerShell

Get-Command | Out-Null

El cmdlet Out-Null no descarta una salida de error. Por ejemplo, si escribe el comando
siguiente, se muestra un mensaje que le informa de que PowerShell no reconoce Is-
NotACommand :

PS> Get-Command Is-NotACommand | Out-Null


Get-Command : 'Is-NotACommand' isn't recognized as a cmdlet, function,
operable program, or script file.
At line:1 char:12
+ Get-Command <<<< Is-NotACommand | Out-Null

Impresión de datos
Out-Printer solo está disponible en plataformas Windows.

Puede imprimir datos mediante el cmdlet Out-Printer . Si no se proporciona un nombre


de impresora, el cmdlet Out-Printer usa la impresora predeterminada. Puede usar
cualquier impresora basada en Windows especificando su nombre para mostrar. No se
requiere ningún tipo de asignación de puerto de impresora ni una impresora física real.
Por ejemplo, si tiene las herramientas de creación de imágenes de documentos de
Microsoft Office instaladas, puede enviar los datos a un archivo de imagen. Para ello,
escriba:

PowerShell

Get-Command Get-Command | Out-Printer -Name 'Microsoft Office Document Image


Writer'
Guardado de datos
Puede enviar la salida a un archivo en lugar de a la ventana de la consola mediante el
cmdlet Out-File . La línea de comandos siguiente envía una lista de procesos al archivo
C:\temp\processlist.txt :

PowerShell

Get-Process | Out-File -FilePath C:\temp\processlist.txt

Los resultados del uso del cmdlet Out-File pueden no ser los esperados si se está
acostumbrado al redireccionamiento de salida tradicional. Para entender su
comportamiento, se debe tener en cuenta el contexto en el que opera el cmdlet Out-
File .

En Windows PowerShell 5.1, el cmdlet Out-File crea un archivo Unicode. Algunas


herramientas, que esperan archivos ASCII, no funcionan correctamente con el formato
de salida predeterminado. Puede cambiar el formato de salida predeterminado a ASCII
mediante el parámetro Encoding:

PowerShell

Get-Process | Out-File -FilePath C:\temp\processlist.txt -Encoding ASCII

Out-file aplica formato al contenido del archivo para que se parezca a la salida de la

consola. Esto hace que, en la mayoría de las circunstancias, la salida se trunque igual
que en una ventana de la consola. Por ejemplo, si ejecuta el siguiente comando:

PowerShell

Get-Command | Out-File -FilePath c:\temp\output.txt

El resultado tendrá un aspecto similar al siguiente:

Resultados

CommandType Name Definition


----------- ---- ----------
Cmdlet Add-Content Add-Content [-Path]
<String[...
Cmdlet Add-History Add-History [[-InputObject]
...
...
Para obtener una salida que no fuerce ajustes de línea para coincidir con el ancho de
pantalla, puede usar el parámetro Width para especificar el ancho de línea. Dado que
Width es un parámetro entero de 32 bits, el valor máximo que puede tener es
2147483647. Escriba lo siguiente para establecer el ancho de línea en este valor máximo:

PowerShell

Get-Command | Out-File -FilePath c:\temp\output.txt -Width 2147483647

El cmdlet Out-File resulta especialmente útil cuando se quiere guardar la salida tal
como se ha mostrado en la consola.
Uso de comandos de formato para
cambiar la vista de salida
Artículo • 13/04/2023

PowerShell tiene un conjunto de cmdlets que permite controlar cómo se muestran las
propiedades para determinados objetos. Los nombres de todos los cmdlets empiezan
con el verbo Format . Permiten seleccionar las propiedades que se quieren mostrar.

PowerShell

Get-Command -Verb Format -Module Microsoft.PowerShell.Utility

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Format-Custom 6.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Format-Hex 6.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Format-List 6.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Format-Table 6.1.0.0 Microsoft.PowerShell.Utility
Cmdlet Format-Wide 6.1.0.0 Microsoft.PowerShell.Utility

En este artículo se describen los cmdlets Format-Wide , Format-List y Format-Table .

Cada tipo de objeto de PowerShell tiene propiedades predeterminadas que se usan si


no se seleccionan las propiedades que se van a mostrar. Cada cmdlet usa el mismo
parámetro Property para especificar las propiedades que se quieren mostrar. Como
Format-Wide solo muestra una única propiedad, su parámetro Property solo toma un
único valor, pero los parámetros de propiedad de Format-List y Format-Table aceptan
una lista de nombres de propiedades.

En este ejemplo, la salida predeterminada del cmdlet Get-Process muestra que hay dos
instancias de Internet Explorer en ejecución.

PowerShell

Get-Process -Name iexplore

El formato predeterminado de los objetos Process muestra estas propiedades:

Output
NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName
------ ----- ----- ------ -- -- -----------
32 25.52 10.25 13.11 12808 1 iexplore
52 11.46 26.46 3.55 21748 1 iexplore

Uso de Format-Wide para la salida de un solo


elemento
De manera predeterminada, el cmdlet Format-Wide solo muestra la propiedad
predeterminada de un objeto. La información asociada a cada objeto se muestra en una
sola columna:

PowerShell

Get-Command -Verb Format | Format-Wide

Output

Format-Custom Format-Hex
Format-List Format-Table
Format-Wide

También puede especificar una propiedad no predeterminada:

PowerShell

Get-Command -Verb Format | Format-Wide -Property Noun

Output

Custom Hex
List Table
Wide

Control de la presentación de Format-Wide con columnas


Con el cmdlet Format-Wide , no se pueden varias propiedades a la vez. Esto resulta útil
para mostrar listas grandes en varias columnas.

PowerShell
Get-Command -Verb Format | Format-Wide -Property Noun -Column 3

Output

Custom Hex List


Table Wide

Uso de Format-List para obtener una vista de


lista
El cmdlet Format-List muestra un objeto en forma de lista, donde cada propiedad
aparece etiquetada en una línea distinta:

PowerShell

Get-Process -Name iexplore | Format-List

Output

Id : 12808
Handles : 578
CPU : 13.140625
SI : 1
Name : iexplore

Id : 21748
Handles : 641
CPU : 3.59375
SI : 1
Name : iexplore

Puede especificar tantas propiedades como desee:

PowerShell

Get-Process -Name iexplore | Format-List -Property


ProcessName,FileVersion,StartTime,Id

Output

ProcessName : iexplore
FileVersion : 11.00.18362.1 (WinBuild.160101.0800)
StartTime : 10/22/2019 11:23:58 AM
Id : 12808

ProcessName : iexplore
FileVersion : 11.00.18362.1 (WinBuild.160101.0800)
StartTime : 10/22/2019 11:23:57 AM
Id : 21748

Obtención de información detallada mediante Format-


List con caracteres comodín
El cmdlet Format-List permite usar un carácter comodín como valor de su parámetro
Property. Esto le permite visualizar información detallada. A menudo, los objetos
incluyen más información de la necesaria, por lo que PowerShell no muestra todos los
valores de propiedad de forma predeterminada. Para mostrar todas las propiedades de
un objeto, use el comando Format-List -Property * . El siguiente comando genera más
de 60 líneas de salida para un único proceso:

PowerShell

Get-Process -Name iexplore | Format-List -Property *

Aunque el comando Format-List resulta útil para mostrar detalles, si quiere una visión
general de la salida que incluya muchos elementos, una vista tabular más sencilla suele
ser más conveniente.

Uso de Format-Table para la salida tabular


Si usa el cmdlet Format-Table sin nombres de propiedades especificados para dar
formato a la salida del comando Get-Process , obtendrá exactamente la misma salida
que sin un cmdlet Format . De forma predeterminada, PowerShell muestra los objetos
Process en formato tabular.

PowerShell

Get-Service -Name win* | Format-Table

Output

Status Name DisplayName


------ ---- -----------
Running WinDefend Windows Defender Antivirus Service
Running WinHttpAutoProx... WinHTTP Web Proxy Auto-Discovery Se...
Running Winmgmt Windows Management Instrumentation
Running WinRM Windows Remote Management (WS-Manag...

7 Nota

Get-Service solo está disponible en plataformas Windows.

Mejora de la salida de Format-Table


Aunque una vista tabular resulta útil para mostrar mucha información, puede ser difícil
de interpretar si la pantalla es demasiado estrecha para los datos. En el ejemplo anterior,
el resultado se trunca. Si especifica el parámetro AutoSize al ejecutar el comando
Format-Table , PowerShell calcula los anchos de columna en función de los datos reales
que se muestran. Esto hace que las columnas sean legibles.

PowerShell

Get-Service -Name win* | Format-Table -AutoSize

Output

Status Name DisplayName


------ ---- -----------
Running WinDefend Windows Defender Antivirus Service
Running WinHttpAutoProxySvc WinHTTP Web Proxy Auto-Discovery Service
Running Winmgmt Windows Management Instrumentation
Running WinRM Windows Remote Management (WS-Management)

Es posible que el cmdlet Format-Table todavía trunque los datos, pero solo al final de la
pantalla. Las propiedades distintas de la última que se muestra obtienen el tamaño que
necesitan para que su elemento de datos más largo se muestre correctamente.

PowerShell

Get-Service -Name win* |


Format-Table -Property Name, Status, StartType, DisplayName,
DependentServices -AutoSize

Output

Name Status StartType DisplayName


DependentServi
ces
---- ------ --------- -----------
--------------
WinDefend Running Automatic Windows Defender Antivirus Service
{}
WinHttpAutoProxySvc Running Manual WinHTTP Web Proxy Auto-Discovery
Service {NcaSvc, iphl…
Winmgmt Running Automatic Windows Management Instrumentation
{vmms, TPHKLO…
WinRM Running Automatic Windows Remote Management (WS-
Management) {}

El comando Format-Table asume que las propiedades se enumeran por orden de


importancia. El cmdlet intenta mostrar de forma completa las propiedades lo más cerca
posible del principio. Si el comando Format-Table no puede mostrar todas las
propiedades, quita algunas columnas de la pantalla. Puede ver este comportamiento en
el ejemplo anterior de la propiedad DependentServices.

Encapsulado de la salida de Format-Table en columnas


Puede forzar que los datos de Format-Table largos se encapsulen dentro de la columna
de presentación mediante el parámetro Wrap. Es posible que el parámetro Wrap no
realice la acción prevista, ya que usa la configuración predeterminada si no se especifica
también AutoSize:

PowerShell

Get-Service -Name win* |


Format-Table -Property Name, Status, StartType, DisplayName,
DependentServices -Wrap

Output

Name Status StartType DisplayName


DependentServi

ces
---- ------ --------- -----------
--------------
WinDefend Running Automatic Windows Defender Antivirus Service
{}
WinHttpAutoProxySvc Running Manual WinHTTP Web Proxy Auto-Discovery
Service {NcaSvc,

iphlpsvc}
Winmgmt Running Automatic Windows Management Instrumentation
{vmms,
TPHKLOAD,

SUService,

smstsmgr…}
WinRM Running Automatic Windows Remote Management (WS-
Management) {}

El uso del parámetro Wrap por sí solo no ralentiza en exceso el procesamiento. Sin
embargo, el uso de AutoSize para dar formato a una lista de archivos recursiva de una
estructura de directorios de gran tamaño puede tardar mucho tiempo y consumir una
gran cantidad de memoria antes de que se muestren los primeros elementos de la
salida.

Si no le preocupa la carga del sistema, AutoSize funciona bien con el parámetro Wrap.
Las columnas iniciales siguen usando todo el ancho necesario para mostrar los
elementos en una línea, pero la columna final se ajusta, si es necesario.

7 Nota

Es posible que algunas columnas no se muestren si se especifican primero las más


anchas. Para obtener los mejores resultados, especifique primero los elementos de
datos más pequeños.

En el ejemplo siguiente, primero se especifican las propiedades más anchas.

PowerShell

Get-Process -Name iexplore |


Format-Table -Wrap -AutoSize -Property FileVersion, Path, Name, Id

Incluso con el ajuste, se omite la columna Id final:

Output

FileVersion Path
Nam

e
----------- ----
---
11.00.18362.1 (WinBuild.160101.0800) C:\Program Files (x86)\Internet
Explorer\IEXPLORE.EXE iex

plo
re
11.00.18362.1 (WinBuild.160101.0800) C:\Program Files\Internet
Explorer\iexplore.exe iex

plo

re

Organización de la salida de la tabla


Otro parámetro útil para el control de la salida tabular es GroupBy. Las listas tabulares
largas pueden ser especialmente difíciles de comparar. El parámetro GroupBy agrupa la
salida según un valor de propiedad. Por ejemplo, los servicios se pueden agrupar por
valor StartType para facilitar la inspección y omitir el valor StartType de la lista de
propiedades:

PowerShell

Get-Service -Name win* | Sort-Object StartType | Format-Table -GroupBy


StartType

Output

StartType: Automatic
Status Name DisplayName
------ ---- -----------
Running WinDefend Windows Defender Antivirus Service
Running Winmgmt Windows Management Instrumentation
Running WinRM Windows Remote Management (WS-Managem…

StartType: Manual
Status Name DisplayName
------ ---- -----------
Running WinHttpAutoProxyS… WinHTTP Web Proxy Auto-Discovery Serv…
Administrar la ubicación actual
Artículo • 13/04/2023

Al navegar por los sistemas de carpeta en el Explorador de archivos, normalmente tiene


una ubicación de trabajo específica; es decir, la carpeta abierta actual. Los elementos de
la carpeta actual se pueden manipular fácilmente haciendo clic en ellos. En las interfaces
de línea de comandos como Cmd.exe, si está en la misma carpeta que un archivo
determinado, puede tener acceso a él especificando un nombre relativamente corto. No
será necesario especificar la ruta de acceso completa al archivo. El directorio actual se
conoce como el directorio de trabajo.

PowerShell usa el término ubicación para referirse al directorio de trabajo, e implementa


una familia de cmdlets para examinar y manipular la ubicación.

Obtención de la ubicación actual (Get-Location)


Para averiguar la ruta de acceso de su ubicación de directorio actual, escriba el comando
Get-Location :

PowerShell

Get-Location

Output

Path
----
C:\Documents and Settings\PowerUser

7 Nota

El cmdlet Get-Location es similar al comando pwd en el shell de BASH. El cmdlet


Set-Location es similar al comando cd en Cmd.exe.

Configuración de la ubicación actual (Set-


Location)
El comando Get-Location se usa con el comando Set-Location . El comando Set-
Location permite especificar su ubicación de directorio actual.

PowerShell

Set-Location -Path C:\Windows

Después de escribir el comando, observará que no recibe ningún tipo de información


directa sobre el efecto del comando. Casi todos los comandos de PowerShell que
realizan una acción apenas si generan resultados, ya que no siempre son útiles. Para
comprobar que se ha producido un cambio de directorio correcto al indicar el comando
Set-Location , incluya el parámetro -PassThru cuando escriba el comando Set-Location :

PowerShell

Set-Location -Path C:\Windows -PassThru

Output

Path
----
C:\WINDOWS

El parámetro PassThru se puede usar con muchos comandos Set en PowerShell para
devolver información sobre el resultado en aquellos casos en que no haya ninguna
salida predeterminada.

Puede especificar rutas relativas a la ubicación actual de la misma manera en que lo


haría en la mayoría de los shells de comandos de UNIX y Windows. En la notación
estándar de las rutas de acceso relativas, un punto ( . ) representa la carpeta actual y dos
puntos ( .. ), el directorio principal de su ubicación actual.

Así, si está en la carpeta C:\Windows , un punto ( . ) representa a C:\Windows y dos puntos


( .. ), a C: . Puede cambiar su ubicación actual por la raíz de la unidad C: ; para ello,
escriba:

PowerShell

Set-Location -Path .. -PassThru

Output
Path
----
C:\

Esta misma técnica funciona en unidades de PowerShell que no son unidades del
sistema de archivos, como HKLM: . Puede establecer su ubicación en la clave
HKLM\Software en el registro escribiendo lo siguiente:

PowerShell

Set-Location -Path HKLM:\SOFTWARE -PassThru

Output

Path
----
HKLM:\SOFTWARE

Luego, puede cambiar la ubicación del directorio por la del directorio principal,
mediante una ruta de acceso relativa:

PowerShell

Set-Location -Path .. -PassThru

Output

Path
----
HKLM:\

Puede escribir Set-Location o usar cualquiera de los alias de PowerShell integrados


para Set-Location ( cd , chdir , sl ). Por ejemplo:

PowerShell

cd -Path C:\Windows

PowerShell

chdir -Path .. -PassThru


PowerShell

sl -Path HKLM:\SOFTWARE -PassThru

Guardado y recuperación de ubicaciones


recientes (Push-Location y Pop-Location)
Al cambiar de ubicación, es útil realizar un seguimiento de dónde ha estado y poder
volver a la ubicación anterior. El cmdlet Push-Location de PowerShell crea un historial
ordenado (una "pila") de las rutas de acceso de directorio donde ha estado, mientras
que el cmdlet Pop-Location sirve para ir hacia atrás en el historial de las rutas de acceso
de directorio.

Por ejemplo, PowerShell suele iniciarse en el directorio principal del usuario.

PowerShell

Get-Location

Path
----
C:\Documents and Settings\PowerUser

7 Nota

La palabra pila tiene un significado especial en muchas configuraciones de


programación, incluido .NET Framework. Al igual que sucede con una pila física de
elementos, el último elemento que se coloca en la pila es el primer elemento que
se puede extraer de ella. Agregar un elemento a una pila se conoce coloquialmente
como "insertar" el elemento en la pila, mientras que extraer un elemento de la pila
se suele conocer como "retirar" el elemento de la pila.

Escriba lo siguiente para insertar la ubicación actual en la pila y, después, ir a la carpeta


Configuración local:

PowerShell

Push-Location -Path "Local Settings"

Tras ello, puede escribir lo siguiente para insertar la ubicación de Configuración local en
la pila y moverse a la carpeta Temp:
PowerShell

Push-Location -Path Temp

Si quiere confirmar que ha cambiado de directorio, escriba el comando Get-Location :

PowerShell

Get-Location

Output

Path
----
C:\Documents and Settings\PowerUser\Local Settings\Temp

Tras ello, puede regresar al último directorio en el que ha estado escribiendo el


comando Pop-Location , así como comprobar el cambio especificando el comando Get-
Location :

PowerShell

Pop-Location
Get-Location

Output

Path
----
C:\Documents and Settings\me\Local Settings

Al igual que ocurre con el cmdlet Set-Location , puede incluir el parámetro PassThru
cuando escribe el cmdlet Pop-Location para mostrar el directorio que ingresó:

PowerShell

Pop-Location -PassThru

Output

Path
----
C:\Documents and Settings\PowerUser
Los cmdlets Location también se pueden usar con rutas de acceso de red. Si tiene un
servidor denominado FS01 con un recurso compartido denominado Public, puede
cambiar la ubicación escribiendo:

PowerShell

Set-Location \\FS01\Public

PowerShell

Push-Location \\FS01\Public

Puede usar los comandos Push-Location y Set-Location para cambiar la ubicación a


cualquier unidad que haya disponible. Por ejemplo, si tiene una unidad de CD-ROM
local con la letra de unidad D que contiene un CD de datos, puede cambiar la ubicación
a dicha unidad de CD escribiendo el comando Set-Location D: .

Si la unidad está vacía, obtendrá el siguiente mensaje de error:

PowerShell

Set-Location D:

Output

Set-Location : Cannot find path 'D:\' because it does not exist.

Cuando se usa una interfaz de línea de comandos, no conviene usar el Explorador de


archivos para examinar las unidades físicas disponibles. Además, el Explorador de
archivos no le mostrará todas las unidades de PowerShell. PowerShell proporciona un
conjunto de comandos para manipular unidades de PowerShell.
Administración de unidades de
PowerShell
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Una unidad de PowerShell es una ubicación de almacén de datos a la que se puede


acceder como una unidad del sistema de archivos en PowerShell. Los proveedores de
PowerShell crean algunas unidades automáticamente, como las unidades de sistema de
archivos ( C: y D: ), las unidades del Registro ( HKCU: y HKLM: ) y la unidad de certificado
( Cert: ). También puede crear sus propias unidades de PowerShell. Estas unidades son
muy útiles, pero solo están disponibles en PowerShell. No se puede tener acceso a ellas
con otras herramientas de Windows, como el Explorador de archivos o Cmd.exe .

PowerShell usa el término PSDrive en los comandos que funcionan con las unidades de
PowerShell. Para ver una lista de las unidades de PowerShell en la sesión de PowerShell,
use el cmdlet Get-PSDrive .

PowerShell

Get-PSDrive

Output

Name Provider Root


CurrentLocation
---- -------- ---- ------------
---
A FileSystem A:\
Alias Alias
C FileSystem C:\ ...And
Settings\me
cert Certificate \
D FileSystem D:\
Env Environment
Function Function
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE
Variable Variable

Aunque las unidades que aparecen en pantalla varían con respecto a las unidades de
disco en el sistema, la lista tendrá un aspecto similar al resultado del comando Get-
PSDrive mostrado anteriormente.

Las unidades del sistema de archivos son un subconjunto de las unidades de


PowerShell. Puede identificar las unidades del sistema de archivos por la entrada
FileSystem en la columna Provider. El proveedor FileSystem de PowerShell admite las
unidades del sistema de archivos de PowerShell.

Para ver la sintaxis del cmdlet Get-PSDrive , escriba un comando Get-Command con el
parámetro Syntax:

PowerShell

Get-Command -Name Get-PSDrive -Syntax

Output

Get-PSDrive [[-Name] <String[]>] [-Scope <String>] [-PSProvider <String[]>]


[-V
erbose] [-Debug] [-ErrorAction <ActionPreference>] [-ErrorVariable <String>]
[-
OutVariable <String>] [-OutBuffer <Int32>]

El parámetro PSProvider permite mostrar únicamente las unidades de PowerShell


compatibles con un proveedor determinado. Por ejemplo, para mostrar solo las
unidades de PowerShell compatibles con el proveedor FileSystem de PowerShell, escriba
un comando Get-PSDrive con el parámetro PSProvider y el valor FileSystem:

PowerShell

Get-PSDrive -PSProvider FileSystem

Output

Name Provider Root


CurrentLocation
---- -------- ---- ------------
---
A FileSystem A:\
C FileSystem C:\ ...nd
Settings\PowerUser
D FileSystem D:\

Para ver las unidades de PowerShell que representan los subárboles del Registro, use el
parámetro PSProvider para mostrar solo las unidades de PowerShell compatibles con el
proveedor de Registro de PowerShell:
PowerShell

Get-PSDrive -PSProvider Registry

Output

Name Provider Root


CurrentLocation
---- -------- ---- ------------
---
HKCU Registry HKEY_CURRENT_USER
HKLM Registry HKEY_LOCAL_MACHINE

También puede usar los cmdlets Location estándar con las unidades de disco de
PowerShell:

PowerShell

Set-Location HKLM:\SOFTWARE
Push-Location .\Microsoft
Get-Location

Output

Path
----
HKLM:\SOFTWARE\Microsoft

Adición de nuevas unidades de PowerShell


Puede usar el comando New-PSDrive para agregar sus propias unidades de PowerShell.
Para obtener la sintaxis del cmdlet New-PSDrive , escriba un comando Get-Command con el
parámetro Syntax:

PowerShell

Get-Command -Name New-PSDrive -Syntax

Output

New-[-Description <String>] [-Scope <String>] [-Credential <PSCredential>]


[-Verbose] [-Debug ]
[-ErrorAction <ActionPreference>] [-ErrorVariable <String>] [-OutVariable
<St ring>]
[-OutBuffer <Int32>] [-WhatIf] [-Confirm]

Para crear una nueva unidad de PowerShell, debe proporcionar tres parámetros:

Un nombre de unidad (puede usar cualquier nombre válido de PowerShell)


PSProvider: se usa FileSystem para las ubicaciones del sistema de archivos y
Registry para las ubicaciones del Registro.
La raíz; es decir, la ruta de acceso a la raíz de la nueva unidad

Por ejemplo, puede crear una unidad llamada Office que esté asignada a la carpeta que
contiene las aplicaciones de Microsoft Office del equipo, como C:\Program
Files\MicrosoftOffice\OFFICE11 . Para crear la unidad, escriba el siguiente comando:

PowerShell

New-PSDrive -Name Office -PSProvider FileSystem -Root "C:\Program


Files\Microsoft Office\OFFICE11"

Output

Name Provider Root


CurrentLocation
---- -------- ---- ------------
---
Office FileSystem C:\Program Files\Microsoft Offic...

7 Nota

Por lo general, las rutas de acceso no distinguen mayúsculas de minúsculas.

Se tiene acceso a una unidad de PowerShell con su nombre seguido de dos puntos ( : ).

Una unidad de PowerShell puede hacer que muchas tareas sean mucho más sencillas de
realizar. Por ejemplo, algunas de las claves más importantes en el Registro de Windows
tienen rutas de acceso muy largas, lo que las hace complicadas de acceder y difíciles de
recordar. La información de configuración crítica reside en
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion . Si quiere ver y cambiar
elementos en la clave del Registro CurrentVersion, puede escribir lo siguiente para crear
una unidad de PowerShell que se base en esa clave:

PowerShell
New-PSDrive -Name cvkey -PSProvider Registry -Root
HKLM\Software\Microsoft\Windows\CurrentVersion

Output

Name Provider Root


CurrentLocation
---- -------- ---- ------------
---
cvkey Registry HKLM\Software\Microsoft\Windows\...

Luego, puede cambiar la ubicación a la unidad cvkey:, como lo haría con cualquier otra
unidad:

PowerShell

cd cvkey:

O bien

PowerShell

Set-Location cvkey: -PassThru

Output

Path
----
cvkey:\

El cmdlet New-PSDrive agrega la nueva unidad solo en la sesión actual de PowerShell. Si


cierra la ventana de PowerShell, la nueva unidad se perderá. Para guardar una unidad de
PowerShell, use el cmdlet Export-Console para exportar la sesión actual de PowerShell y,
luego, use el parámetro PowerShell.exe PSConsoleFile para importarla. También puede
agregar la nueva unidad al perfil de Windows PowerShell.

Eliminación de unidades de PowerShell


Puede usar el cmdlet Remove-PSDrive para eliminar unidades de PowerShell. Por
ejemplo, si agregó la unidad de PowerShell Office: , como se indica en el tema New-
PSDrive , puede eliminarla escribiendo lo siguiente:
PowerShell

Remove-PSDrive -Name Office

Para eliminar la unidad de PowerShell cvkey: , use el comando siguiente:

PowerShell

Remove-PSDrive -Name cvkey

Sin embargo, no puede eliminarla mientras esté en la unidad. Por ejemplo:

PowerShell

cd office:
Remove-PSDrive -Name office

Output

Remove-PSDrive : Cannot remove drive 'Office' because it is in use.


At line:1 char:15
+ remove-psdrive <<<< -name office

Adición y eliminación de unidades fuera de


PowerShell
PowerShell detecta unidades del sistema de archivos que se agregan o quitan en
Windows, entre las que se incluyen:

Unidades de red asignadas


Unidades USB conectadas
Unidades que se eliminan mediante el comando net use o desde un script de
Windows Script Host (WSH)
Trabajar con archivos y carpetas
Artículo • 13/04/2023

Navegar por las unidades de PowerShell y manipular los elementos son procesos
similares al de manipular los archivos y carpetas en unidades de disco de Windows. En
este artículo se describe cómo usar PowerShell para abordar tareas específicas de
manipulación de archivos y carpetas.

Enumeración de todos los archivos y carpetas


dentro de una carpeta
Para obtener todos los elementos directamente dentro de una carpeta, use Get-
ChildItem . Agregue el parámetro Force opcional para mostrar elementos ocultos o del
sistema. Por ejemplo, este comando muestra el contenido directo de la unidad C: de
PowerShell.

PowerShell

Get-ChildItem -Path C:\ -Force

El comando muestra solo los elementos contenidos directamente, de forma muy


parecida al comando cmd.exe de dir o ls en un shell de UNIX. Para mostrar los
elementos de una subcarpeta, debe especificar el parámetro Recurse. El siguiente
comando muestra todo el contenido de la unidad C: :

PowerShell

Get-ChildItem -Path C:\ -Force -Recurse

Get-ChildItem puede filtrar elementos con sus parámetros Path, Filter, Include y
Exclude, pero estos suelen basarse solo en el nombre. Puede realizar un filtrado
complejo basado en otras propiedades de los elementos mediante Where-Object .

El siguiente comando encuentra todos los ejecutables de la carpeta Archivos de


programa que se modificaron por última vez después del 1 de octubre de 2005, cuyo
tamaño no es inferior a 1 megabyte ni superior a 10 megabytes:

PowerShell
Get-ChildItem -Path $env:ProgramFiles -Recurse -Include *.exe |
Where-Object -FilterScript {
($_.LastWriteTime -gt '2005-10-01') -and ($_.Length -ge 1mb) -and
($_.Length -le 10mb)
}

Copia de archivos y carpetas


La copia se realiza con Copy-Item . El comando siguiente hace una copia de seguridad de
C:\boot.ini en C:\boot.bak :

PowerShell

Copy-Item -Path C:\boot.ini -Destination C:\boot.bak

Si el archivo de destino ya existe, se produce un error en el intento de copia. Para


sobrescribir un destino preexistente, use el parámetro Force:

PowerShell

Copy-Item -Path C:\boot.ini -Destination C:\boot.bak -Force

Este comando funciona aunque el destino sea de solo lectura.

La copia de carpetas funciona del mismo modo. Este comando copia la carpeta
C:\temp\test1 en la nueva carpeta C:\temp\DeleteMe de forma recursiva:

PowerShell

Copy-Item C:\temp\test1 -Recurse C:\temp\DeleteMe

También puede copiar una selección de elementos. El siguiente comando copia todos
los archivos .txt contenidos en cualquier parte de C:\data en C:\temp\text :

PowerShell

Copy-Item -Filter *.txt -Path c:\data -Recurse -Destination C:\temp\text

Todavía puede usar otras herramientas para realizar copias del sistema de archivos.
Todos los objetos XCOPY, ROBOCOPY y COM, como Scripting.FileSystemObject,
funcionan en PowerShell. Por ejemplo, puede usar la clase COM Scripting.FileSystem
COM de Windows Script Host para realizar una copia de seguridad de C:\boot.ini en
C:\boot.bak :

PowerShell

(New-Object -ComObject Scripting.FileSystemObject).CopyFile('C:\boot.ini',


'C:\boot.bak')

Creación de archivos y carpetas


La creación de nuevos elementos funciona igual en todos los proveedores de
PowerShell. Si un proveedor de PowerShell tiene más de un tipo de elemento (por
ejemplo, el proveedor FileSystem de PowerShell distingue entre directorios y archivos),
debe especificar el tipo de elemento.

Este comando crea una carpeta nueva C:\temp\New Folder :

PowerShell

New-Item -Path 'C:\temp\New Folder' -ItemType Directory

Este comando crea un nuevo archivo vacío C:\temp\New Folder\file.txt .

PowerShell

New-Item -Path 'C:\temp\New Folder\file.txt' -ItemType File

) Importante

Al usar el modificador Force con el comando New-Item para crear una carpeta y la
carpeta ya existe, no sobrescribirá ni reemplazará la carpeta. Simplemente
devolverá el objeto de carpeta existente. Sin embargo, si usa New-Item -Force en
un archivo que ya existe, el archivo se sobrescribe.

Eliminación de todos los archivos y carpetas de


una carpeta
Los elementos contenidos se pueden quitar mediante Remove-Item , pero se pedirá que
se confirme la eliminación si el elemento contiene algo más. Por ejemplo, si intenta
eliminar la carpeta C:\temp\DeleteMe que contiene otros elementos, PowerShell le pide
confirmación antes de eliminar la carpeta:

Remove-Item -Path C:\temp\DeleteMe

Confirm
The item at C:\temp\DeleteMe has children and the Recurse parameter wasn't
specified. If you continue, all children will be removed with the item. Are
you
sure you want to continue?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

Si no quiere que se le solicite confirmación por cada elemento contenido, especifique el


parámetro Recurse:

PowerShell

Remove-Item -Path C:\temp\DeleteMe -Recurse

Asignación de una carpeta local como unidad


También puede asignar una carpeta local mediante el comando New-PSDrive . El
siguiente comando crea una unidad local P: con raíz en el directorio local Archivos de
programa, visible solo desde la sesión de PowerShell:

PowerShell

New-PSDrive -Name P -Root $env:ProgramFiles -PSProvider FileSystem

Al igual que con las unidades de red, las unidades asignadas dentro de PowerShell son
visibles inmediatamente en el shell de PowerShell. Para crear una unidad asignada
visible desde el Explorador de archivos, use el parámetro Persist. Sin embargo, solo se
pueden usar rutas de acceso remotas con Persist.

Lectura de un archivo de texto en una matriz


Uno de los formatos de almacenamiento más comunes para los datos de texto es en un
archivo con líneas separadas que se tratan como elementos de datos distintos. El cmdlet
Get-Content se puede usar para leer un archivo completo en un solo paso, como se

muestra aquí:

PS> Get-Content -Path C:\boot.ini


[boot loader]
timeout=5
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP
Professional"
/noexecute=AlwaysOff /fastdetect
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS=" Microsoft Windows XP
Professional
with Data Execution Prevention" /noexecute=optin /fastdetect

Get-Content trata los datos leídos del archivo como una matriz, con un elemento por

línea de contenido del archivo. Para confirmarlo, compruebe la longitud del contenido
devuelto:

PS> (Get-Content -Path C:\boot.ini).Length


6

Este comando es más útil para obtener listas de información en PowerShell


directamente. Por ejemplo, podría almacenar una lista de nombres de equipo o
direcciones IP en el archivo C:\temp\domainMembers.txt , con un nombre en cada línea
del archivo. Puede usar Get-Content para recuperar el contenido del archivo y colocarlo
en la variable $Computers :

PowerShell

$Computers = Get-Content -Path C:\temp\DomainMembers.txt

$Computers es ahora una matriz que contiene un nombre de equipo en cada elemento.
Trabajar con archivos, carpetas y claves
del Registro
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

En PowerShell se usa el término Item para hacer referencia a los elementos contenidos
en una unidad de PowerShell. Cuando se trabaja con el proveedor FileSystem de
PowerShell, un elemento Item puede ser un archivo, una carpeta o la unidad de
PowerShell. Enumerar estos elementos y trabajar con ellos son tareas críticas básicas en
la mayoría de las configuraciones administrativas, de modo que conviene abordar estas
tareas en profundidad.

Enumeración de archivos, carpetas y claves del


Registro
Dado que la obtención de una colección de elementos desde una ubicación
determinada es una tarea común, el cmdlet Get-ChildItem está diseñado
específicamente para devolver todos los elementos que se encuentren dentro de un
contenedor, por ejemplo, una carpeta.

Si desea que se devuelvan todos los archivos y carpetas contenidos directamente dentro
de la carpeta C:\Windows , escriba:

PS> Get-ChildItem -Path C:\Windows


Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 2006-05-16 8:10 AM 0 0.log
-a--- 2005-11-29 3:16 PM 97 acc1.txt
-a--- 2005-10-23 11:21 PM 3848 actsetup.log
...

La lista es similar a lo que se obtendría si se especificara el comando dir en cmd.exe o


el comando ls en un shell de comandos de UNIX.
Puede confeccionar listas complejas mediante los parámetros del cmdlet Get-ChildItem .
La sintaxis del cmdlet Get-ChildItem se puede ver escribiendo lo siguiente:

PowerShell

Get-Command -Name Get-ChildItem -Syntax

Estos parámetros se pueden mezclar y relacionar para obtener resultados muy


personalizados.

Enumeración de todos los elementos contenidos


Para ver tanto los elementos que hay dentro de una carpeta de Windows como todos
los elementos de sus subcarpetas, use el parámetro Recurse de Get-ChildItem . La lista
muestra todos los elementos dentro de la carpeta de Windows y los elementos de sus
subcarpetas. Por ejemplo:

PS> Get-ChildItem -Path C:\WINDOWS -Recurse

Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS
Directory: Microsoft.PowerShell.Core\FileSystem::C:\WINDOWS\AppPatch
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a--- 2004-08-04 8:00 AM 1852416 AcGenral.dll
...

Filtrado de elementos por nombre


Para mostrar solo los nombres de los elementos, use el parámetro Name de Get-
Childitem :

PS> Get-ChildItem -Path C:\WINDOWS -Name


addins
AppPatch
assembly
...

Enumeración forzosa de los elementos ocultos


Los elementos que están ocultos en el Explorador de archivos o cmd.exe no se muestran
en la salida de un comando Get-ChildItem . Para mostrar los elementos ocultos, use el
parámetro Force de Get-ChildItem . Por ejemplo:

PowerShell

Get-ChildItem -Path C:\Windows -Force

Este parámetro se llama Force porque permite anular de manera forzada el


comportamiento normal del comando Get-ChildItem . Force es un parámetro muy
usado que fuerza una acción que un cmdlet normalmente no realizaría, si bien no puede
llevar a cabo ninguna acción que ponga en peligro la seguridad del sistema.

Coincidencia de nombres de elementos con caracteres


comodín
El comando Get-ChildItem acepta caracteres comodín en la ruta de acceso de los
elementos que se van a enumerar.

Dado que las coincidencias con caracteres comodín se controla mediante el motor de
PowerShell, todos los cmdlets que acepten caracteres comodín usan la misma notación
y tienen el mismo comportamiento de búsqueda de coincidencias. La notación de
caracteres comodín de PowerShell incluye:

El asterisco ( * ) coincide con cero o más repeticiones de cualquier carácter.


El signo de interrogación ( ? ) coincide exactamente con un carácter.
Los caracteres de corchete de apertura ( [ ) y de cierre ( ] ) rodean un juego de
caracteres que debe coincidir.

A continuación presentamos algunos ejemplos de cómo funciona la especificación de


caracteres comodín.

Escriba el siguiente comando para encontrar todos los archivos en el directorio de


Windows con el sufijo .log y exactamente cinco caracteres en el nombre base:

PS> Get-ChildItem -Path C:\Windows\?????.log

Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows
Mode LastWriteTime Length Name
---- ------------- ------ ----
...
-a--- 2006-05-11 6:31 PM 204276 ocgen.log
-a--- 2006-05-11 6:31 PM 22365 ocmsn.log
...
-a--- 2005-11-11 4:55 AM 64 setup.log
-a--- 2005-12-15 2:24 PM 17719 VxSDM.log
...

Escriba lo siguiente para encontrar todos los archivos que comienzan por la letra x en el
directorio de Windows:

PowerShell

Get-ChildItem -Path C:\Windows\x*

Escriba lo siguiente para encontrar todos los archivos cuyos nombres comienzan por "x"
o "z":

PowerShell

Get-ChildItem -Path C:\Windows\[xz]*

Para obtener más información sobre los caracteres comodín, vea el artículo Caracteres
comodín.

Exclusión de elementos
Puede excluir elementos concretos mediante el parámetro Exclude de Get-ChildItem .
Esto le permite realizar filtrados complejos en una sola instrucción.

Por ejemplo, imagine que está buscando el archivo .dll del servicio de hora de Windows
en la carpeta System32 y solo recuerda que el nombre del archivo .dll comienza por "W"
y contiene "32".

Una expresión como w*32*.dll buscará todos los archivos .dll que cumplan las
condiciones, pero es posible que quiera filtrar aún más los archivos y omitir los archivos
Win32. Puede omitir estos archivos mediante el parámetro Exclude con el patrón win* :

PS> Get-ChildItem -Path C:\WINDOWS\System32\w*32*.dll -Exclude win*

Directory: C:\WINDOWS\System32

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 3/18/2019 9:43 PM 495616 w32time.dll
-a--- 3/18/2019 9:44 PM 35328 w32topl.dll
-a--- 1/24/2020 5:44 PM 401920 Wldap32.dll
-a--- 10/10/2019 5:40 PM 442704 ws2_32.dll
-a--- 3/18/2019 9:44 PM 66048 wsnmp32.dll
-a--- 3/18/2019 9:44 PM 18944 wsock32.dll
-a--- 3/18/2019 9:44 PM 64792 wtsapi32.dll

Mezcla de parámetros Get-ChildItem


Puede usar varios parámetros del cmdlet Get-ChildItem en el mismo comando. Antes
de mezclar parámetros, asegúrese de que comprende el concepto de búsqueda de
coincidencias con caracteres comodín. Por ejemplo, el siguiente comando no devuelve
ningún resultado:

PowerShell

Get-ChildItem -Path C:\Windows\*.dll -Recurse -Exclude [a-y]*.dll

No hay ningún resultado, a pesar de que hay dos archivos DLL que comienzan por la
letra "z" en la carpeta de Windows.

No se devolvieron resultados porque hemos especificado el carácter comodín como


parte de la ruta de acceso. Aunque el comando es recursivo, el cmdlet Get-ChildItem ha
restringido los elementos a aquellos que están en la carpeta de Windows y cuyos
nombres terminan en .dll .

Para especificar una búsqueda recursiva de archivos cuyos nombres coinciden con un
patrón especial, use el parámetro Include.

PS> Get-ChildItem -Path C:\Windows -Include *.dll -Recurse -Exclude [a-


y]*.dll

Directory:
Microsoft.PowerShell.Core\FileSystem::C:\Windows\System32\Setup

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 2004-08-04 8:00 AM 8261 zoneoc.dll

Directory: Microsoft.PowerShell.Core\FileSystem::C:\Windows\System32

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 2004-08-04 8:00 AM 337920 zipfldr.dll
Trabajar con entradas del Registro
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Las entradas del Registro son propiedades de claves y, como tales, no se pueden
examinar de forma directa, de modo que es preciso adoptar un enfoque ligeramente
diferente al trabajar con ellas.

Enumeración de entradas del Registro


Existen muchas formas de examinar entradas del Registro. La más sencilla consiste en
obtener los nombres de propiedad asociados a una clave. Por ejemplo, para ver los
nombres de las entradas en la clave de Registro
HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion , utilice Get-Item . Las
claves del Registro tienen una propiedad con el nombre genérico "Property" que es una
lista de entradas del Registro en la clave. Con el siguiente comando se selecciona la
propiedad Property y se expanden los elementos de forma que se muestran en una lista:

PowerShell

Get-Item -Path
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion |
Select-Object -ExpandProperty Property

Output

DevicePath
MediaPathUnexpanded
ProgramFilesDir
CommonFilesDir
ProductId

Para ver las entradas del Registro en un formato más legible, use Get-ItemProperty :

PowerShell

Get-ItemProperty -Path
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion

Output
ProgramFilesDir : C:\Program Files
CommonFilesDir : C:\Program Files\Common Files
ProgramFilesDir (x86) : C:\Program Files (x86)
CommonFilesDir (x86) : C:\Program Files (x86)\Common Files
CommonW6432Dir : C:\Program Files\Common Files
DevicePath : C:\WINDOWS\inf
MediaPathUnexpanded : C:\WINDOWS\Media
ProgramFilesPath : C:\Program Files
ProgramW6432Dir : C:\Program Files
SM_ConfigureProgramsName : Set Program Access and Defaults
SM_GamesName : Games
PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWA
RE\Microsoft\Windows\CurrentVersion
PSParentPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWA
RE\Microsoft\Windows
PSChildName : CurrentVersion
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry

Las propiedades relativas a Windows PowerShell de la clave tienen antepuesto el prefijo


"PS", como PSPath, PSParentPath, PSChildName y PSProvider.

Puede usar la notación *.* para hacer referencia a la ubicación actual. Puede usar Set-
Location para cambiar al contenedor del Registro CurrentVersion en primer lugar:

PowerShell

Set-Location -Path
Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion

Otra opción consiste en usar el elemento integrado HKLM: PSDrive con Set-Location :

PowerShell

Set-Location -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion

Luego, puede usar la notación . de la ubicación actual para enumerar las propiedades
sin especificar una ruta de acceso completa:

PowerShell

Get-ItemProperty -Path .

Output
...
DevicePath : C:\WINDOWS\inf
MediaPathUnexpanded : C:\WINDOWS\Media
ProgramFilesDir : C:\Program Files
...

La expansión de la ruta de acceso funciona igual que lo hace en el sistema de archivos,


así que desde esta ubicación se puede obtener la lista ItemProperty para
HKLM:\SOFTWARE\Microsoft\Windows\Help mediante Get-ItemProperty -Path ..\Help .

Obtención de una sola entrada del Registro


Si quiere recuperar una entrada específica de una clave del Registro, puede usar uno de
los diversos métodos posibles existentes. Este ejemplo busca el valor de DevicePath en
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion .

Con Get-ItemProperty , use el parámetro Path para especificar el nombre de la clave y el


parámetro Name para especificar el nombre de la entrada DevicePath.

PowerShell

Get-ItemProperty -Path HKLM:\Software\Microsoft\Windows\CurrentVersion -Name


DevicePath

Output

DevicePath : C:\WINDOWS\inf
PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Wi
ndows\CurrentVersion
PSParentPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\Software\Microsoft\Wi
ndows
PSChildName : CurrentVersion
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry

Este comando devuelve las propiedades estándar de Windows PowerShell, así como la
propiedad DevicePath.

7 Nota

Aunque Get-ItemProperty tiene los parámetros Filter, Include y Exclude, no se


pueden usar para filtrar por nombre de propiedad. Estos parámetros hacen
referencia a claves del Registro (que son rutas de acceso de los elementos) y no a
entradas del Registro (que son propiedades de los elementos).

Otra opción sería usar la herramienta de línea de comandos reg.exe . Para obtener
ayuda con reg.exe , escriba reg.exe /? en un símbolo del sistema. Para encontrar la
entrada DevicePath, use reg.exe tal y como se muestra en el siguiente comando:

PowerShell

reg query HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion /v DevicePath

Output

! REG.EXE VERSION 3.0

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion
DevicePath REG_EXPAND_SZ %SystemRoot%\inf

También puede usar el objeto COM WshShell para encontrar algunas entradas del
Registro, aunque este método no funciona con datos binarios de gran tamaño o con
nombres de entradas del Registro que contengan caracteres como una barra diagonal
inversa ( \ ). Anexe el nombre de la propiedad a la ruta de acceso de elemento con un
separador \ :

PowerShell

(New-Object -ComObject
WScript.Shell).RegRead("HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Devic
ePath")

Output

%SystemRoot%\inf

Establecimiento de una sola entrada del


Registro
Si quiere cambiar una entrada específica de una clave del Registro, puede usar uno de
los diversos métodos posibles existentes. En este ejemplo, se modifica la entrada Path
bajo HKEY_CURRENT_USER\Environment . La entrada Path especifica dónde encontrar los
archivos ejecutables.
1. Recupere el valor actual de la entrada Path mediante Get-ItemProperty .
2. Agregue el nuevo valor y sepárelo con un ; .
3. Use Set-ItemProperty con la clave especificada, el nombre de la entrada y el valor
para modificar la entrada del Registro.

PowerShell

$value = Get-ItemProperty -Path HKCU:\Environment -Name Path


$newpath = $value.Path += ";C:\src\bin\"
Set-ItemProperty -Path HKCU:\Environment -Name Path -Value $newpath

7 Nota

Aunque Set-ItemProperty tiene los parámetros Filter, Include y Exclude, no se


pueden usar para filtrar por nombre de propiedad. Estos parámetros hacen
referencia a claves del Registro (que son rutas de acceso de los elementos) y no a
entradas del Registro (que son propiedades de los elementos).

Otra opción sería usar la herramienta de línea de comandos Reg.exe. Para obtener
ayuda con reg.exe, escriba reg.exe /? en un símbolo del sistema.

En el ejemplo siguiente se cambia la entrada Path mediante la eliminación de la ruta de


acceso que se agregó en el ejemplo anterior. Get-ItemProperty aún se utiliza para
recuperar el valor actual para evitar tener que analizar la cadena devuelta desde reg
query . Los métodos SubString y LastIndexOf se usan para recuperar la última ruta de

acceso que se agrega a la entrada Path.

PowerShell

$value = Get-ItemProperty -Path HKCU:\Environment -Name Path


$newpath = $value.Path.SubString(0, $value.Path.LastIndexOf(';'))
reg add HKCU\Environment /v Path /d $newpath /f

Output

The operation completed successfully.

Creación de entradas del Registro


Para agregar una nueva entrada denominada "PowerShellPath" a la clave
CurrentVersion, use New-ItemProperty con la ruta de acceso a la clave, el nombre de la
entrada y el valor de la entrada. En este ejemplo, tomaremos el valor de la variable de
Windows PowerShell $PSHome , que almacena la ruta de acceso al directorio de
instalación de Windows PowerShell.

Puede agregar la nueva entrada a la clave usando el siguiente comando; este comando
también devolverá información sobre la nueva entrada:

PowerShell

New-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -Name


PowerShellPath -PropertyType String -Value $PSHome

Output

PSPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wi
ndows\CurrentVersion
PSParentPath :
Microsoft.PowerShell.Core\Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Wi
ndows
PSChildName : CurrentVersion
PSDrive : HKLM
PSProvider : Microsoft.PowerShell.Core\Registry
PowerShellPath : C:\Program Files\Windows PowerShell\v1.0

PropertyType debe ser el nombre de un miembro de la enumeración


Microsoft.Win32.RegistryValueKind en la siguiente tabla:

Valor de Significado
PropertyType

Binary Datos binarios

DWord Un número que es un valor UInt32 válido.

ExpandString Una cadena que puede contener variables de entorno que se expanden
dinámicamente

MultiString Una cadena de varias líneas

String Cualquier valor de cadena

QWord 8 bytes de datos binarios

Una entrada del Registro se puede agregar a varias ubicaciones si se especifica una
matriz de valores para el parámetro Path:

PowerShell
New-ItemProperty -Name PowerShellPath -PropertyType String -Value $PSHome `
-Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion,
HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion

Un valor de entrada del Registro preexistente también se puede sobrescribir si se


agrega el parámetro Force a cualquier comando New-ItemProperty .

Cambio del nombre de entradas del Registro


Para cambiar el nombre de la entrada PowerShellPath a "PSHome," use Rename-
ItemProperty :

PowerShell

Rename-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -


Name PowerShellPath -NewName PSHome

Para mostrar el valor cuyo nombre ha cambiado, agregue el parámetro PassThru al


comando.

PowerShell

Rename-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -


Name PowerShellPath -NewName PSHome -passthru

Eliminación de entradas del Registro


Para eliminar las entradas del Registro PSHome y PowerShellPath, use Remove-
ItemProperty :

PowerShell

Remove-ItemProperty -Path HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion -


Name PSHome
Remove-ItemProperty -Path HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion -
Name PowerShellPath
Trabajar con claves del Registro
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Dado que las claves del Registro son elementos en unidades de PowerShell, trabajar con
ellas es muy similar a trabajar con archivos y carpetas. Una diferencia fundamental es
que todos los elementos en una unidad de PowerShell basada en el Registro es un
contenedor, como una carpeta en una unidad del sistema de archivos. Sin embargo, las
entradas del Registro y sus valores asociados son propiedades de los elementos, no
elementos distintos.

Enumeración de todas las subclaves de una


clave del Registro
Puede mostrar todos los elementos directamente dentro de una clave del Registro con
Get-ChildItem . Agregue el parámetro Force opcional para mostrar elementos ocultos o
del sistema. Por ejemplo, este comando muestra los elementos directamente en la
unidad HKCU: de PowerShell que se corresponde con el subárbol HKEY_CURRENT_USER del
Registro:

PowerShell

Get-ChildItem -Path HKCU:\ | Select-Object Name

Output

Hive: Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER

Name
----
HKEY_CURRENT_USER\AppEvents
HKEY_CURRENT_USER\Console
HKEY_CURRENT_USER\Control Panel
HKEY_CURRENT_USER\DirectShow
HKEY_CURRENT_USER\dummy
HKEY_CURRENT_USER\Environment
HKEY_CURRENT_USER\EUDC
HKEY_CURRENT_USER\Keyboard Layout
HKEY_CURRENT_USER\MediaFoundation
HKEY_CURRENT_USER\Microsoft
HKEY_CURRENT_USER\Network
HKEY_CURRENT_USER\Printers
HKEY_CURRENT_USER\Software
HKEY_CURRENT_USER\System
HKEY_CURRENT_USER\Uninstall
HKEY_CURRENT_USER\WXP
HKEY_CURRENT_USER\Volatile Environment

Estas son las claves de nivel superior visibles en HKEY_CURRENT_USER en el Editor del
Registro ( regedit.exe ).

Para especificar esta ruta de acceso del Registro también puede especificar el nombre
del proveedor del Registro, seguido de :: . El nombre completo del proveedor del
registro es Microsoft.PowerShell.Core\Registry , pero se puede acortar a simplemente
Registry . Cualquiera de los siguientes comandos enumerará el contenido directamente
en HKCU: .

PowerShell

Get-ChildItem -Path Registry::HKEY_CURRENT_USER


Get-ChildItem -Path Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER
Get-ChildItem -Path Registry::HKCU
Get-ChildItem -Path Microsoft.PowerShell.Core\Registry::HKCU
Get-ChildItem HKCU:

Estos comandos muestran solo los elementos contenidos directamente, lo que se


parece a usar DIR en cmd.exe o ls en un shell de UNIX. Para mostrar los elementos
contenidos, debe especificar el parámetro Recurse. Para enumerar todas las claves del
Registro en HKCU: , use el comando siguiente.

PowerShell

Get-ChildItem -Path HKCU:\ -Recurse

Get-ChildItem puede realizar funcionalidades de filtrado complejas a través de sus

parámetros Path, Filter, Include y Exclude, pero dichos parámetros suelen basarse solo
en el nombre. Con el cmdlet Where-Object puede realizar un filtrado complejo basado
en otras propiedades de los elementos. El siguiente comando busca en HKCU:\Software
todas las claves que no tengan más de una subclave y que tengan exactamente cuatro
valores:

PowerShell

Get-ChildItem -Path HKCU:\Software -Recurse |


Where-Object {($_.SubKeyCount -le 1) -and ($_.ValueCount -eq 4) }
Copia de claves
La copia se realiza con Copy-Item . En el ejemplo siguiente se copia la subclave
CurrentVersion de HKLM:\SOFTWARE\Microsoft\Windows\ y todas sus propiedades en

HKCU:\ .

PowerShell

Copy-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion' -


Destination HKCU:

Si examina esta nueva clave en el Editor del Registro o mediante Get-ChildItem ,


observará que no tiene copias de las subclaves contenidas en la nueva ubicación. Para
copiar todo el contenido de un contenedor, debe especificar el parámetro Recurse. Para
hacer que el comando de copia anterior sea recursivo, debe usar este comando:

PowerShell

Copy-Item -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion' -


Destination HKCU: -Recurse

Puede seguir usando otras herramientas que tiene a su disposición para realizar copias
del sistema de archivos. Todas las herramientas de edición del Registro, incluidas
reg.exe , regini.exe , regedit.exe y los objetos COM que admiten la edición del
Registro, como WScript.Shell y la clase StdRegProv de WMI, pueden usarse desde
PowerShell.

Creación de claves
Crear nuevas claves en el Registro es más sencillo que crear un nuevo elemento en un
sistema de archivos. Dado que todas las claves del Registro son contenedores, no es
necesario especificar el tipo de elemento. Solo tiene que proporcionar una ruta de
acceso explícita, como:

PowerShell

New-Item -Path HKCU:\Software_DeleteMe

También puede usar una ruta de acceso basada en el proveedor para especificar una
clave:

PowerShell
New-Item -Path Registry::HKCU\Software_DeleteMe

Eliminación de claves
El proceso de eliminación de elementos es básicamente igual para todos los
proveedores. Los siguientes comandos quitan elementos de forma automática:

PowerShell

Remove-Item -Path HKCU:\Software_DeleteMe


Remove-Item -Path 'HKCU:\key with spaces in the name'

Eliminación de todas las claves bajo una clave


específica
Los elementos contenidos se pueden quitar mediante Remove-Item , pero se pedirá que
se confirme la eliminación si el elemento contiene algo más. Por ejemplo, si se intenta
eliminar la subclave HKCU:\CurrentVersion creada, se muestra lo siguiente:

PowerShell

Remove-Item -Path HKCU:\CurrentVersion

Output

Confirm
The item at HKCU:\CurrentVersion\AdminDebug has children and the -recurse
parameter was not specified. If you continue, all children will be removed
with
the item. Are you sure you want to continue?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

Para eliminar los elementos contenidos sin preguntar, especifique el parámetro Recurse:

PowerShell

Remove-Item -Path HKCU:\CurrentVersion -Recurse

Si quiere quitar todos los elementos de HKCU:\CurrentVersion , pero no del


HKCU:\CurrentVersion mismo, podría usar en su lugar:
PowerShell

Remove-Item -Path HKCU:\CurrentVersion\* -Recurse


Crear un cuadro de entrada
personalizado
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Cree un script de un cuadro de entrada gráfico personalizado usando las características


de creación de formularios de Microsoft .NET Framework de Windows PowerShell 3.0 (y
versiones posteriores).

Crear un cuadro de entrada gráfico


personalizado
Copie y pegue lo siguiente en Windows PowerShell ISE y, después, guárdelo como un
archivo de script de Windows PowerShell ( .ps1 ).

PowerShell

Add-Type -AssemblyName System.Windows.Forms


Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form


$form.Text = 'Data Entry Form'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$okButton = New-Object System.Windows.Forms.Button


$okButton.Location = New-Object System.Drawing.Point(75,120)
$okButton.Size = New-Object System.Drawing.Size(75,23)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)

$cancelButton = New-Object System.Windows.Forms.Button


$cancelButton.Location = New-Object System.Drawing.Point(150,120)
$cancelButton.Size = New-Object System.Drawing.Size(75,23)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

$label = New-Object System.Windows.Forms.Label


$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Please enter the information in the space below:'
$form.Controls.Add($label)

$textBox = New-Object System.Windows.Forms.TextBox


$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)

$form.Topmost = $true

$form.Add_Shown({$textBox.Select()})
$result = $form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK)


{
$x = $textBox.Text
$x
}

El script comienza con la carga de dos clases de .NET Framework: System.Drawing y


System.Windows.Forms. A continuación, inicie una nueva instancia de la clase
System.Windows.Forms.Form de .NET Framework. De esta forma, tendrá una ventana o
formulario en blanco donde puede empezar a agregar controles.

PowerShell

$form = New-Object System.Windows.Forms.Form

Tras crear una instancia de la clase Form, asigne valores a las tres propiedades de esta
clase.

Texto. Es el título de la ventana.


Tamaño Es el tamaño del formulario en píxeles. El script anterior crea un
formulario de 300 píxeles de ancho y 200 píxeles de alto.
StartingPosition. Esta propiedad opcional está establecida en CenterScreen en el
script anterior. Si no agrega esta propiedad, Windows selecciona una ubicación
cuando el formulario se abre. Cuando StartingPosition se establece en
CenterScreen, el formulario aparece automáticamente en el centro de la pantalla
cada vez que se carga.

PowerShell

$form.Text = 'Data Entry Form'


$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'
A continuación, cree un botón Aceptar para el formulario. Indique un tamaño y el
comportamiento del botón Aceptar. En este ejemplo, la posición del botón es de
120 píxeles desde el borde superior del formulario y de 75 píxeles desde el borde
izquierdo. La altura del botón es 23 píxeles y la longitud, 75 píxeles. El script usa tipos
predefinidos de Windows Forms para definir el comportamiento del botón.

PowerShell

$okButton = New-Object System.Windows.Forms.Button


$okButton.Location = New-Object System.Drawing.Point(75,120)
$okButton.Size = New-Object System.Drawing.Size(75,23)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)

De manera similar, cree un botón Cancelar. El botón Cancelar está a 120 píxeles de la
parte superior, pero a 150 píxeles del borde izquierdo de la ventana.

PowerShell

$cancelButton = New-Object System.Windows.Forms.Button


$cancelButton.Location = New-Object System.Drawing.Point(150,120)
$cancelButton.Size = New-Object System.Drawing.Size(75,23)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

A continuación, escriba texto de etiqueta en la ventana para describir la información que


quiera que los usuarios proporcionen.

PowerShell

$label = New-Object System.Windows.Forms.Label


$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Please enter the information in the space below:'
$form.Controls.Add($label)

Agregue el control (en este caso, un cuadro de texto) que permita a los usuarios
proporcionar la información descrita en el texto de etiqueta. Hay muchos otros
controles que puede aplicar además de los cuadros de texto. Para más controles,
consulte Espacio de nombres System.Windows.Forms.

PowerShell
$textBox = New-Object System.Windows.Forms.TextBox
$textBox.Location = New-Object System.Drawing.Point(10,40)
$textBox.Size = New-Object System.Drawing.Size(260,20)
$form.Controls.Add($textBox)

Establezca la propiedad Topmost en $True para forzar que la ventana se abra encima
del resto de ventanas y cuadros de diálogo abiertos.

PowerShell

$form.Topmost = $true

A continuación, agregue esta línea de código para activar el formulario y establezca el


foco en el cuadro de texto que ha creado.

PowerShell

$form.Add_Shown({$textBox.Select()})

Agregue la siguiente línea de código para mostrar el formulario en Windows.

PowerShell

$result = $form.ShowDialog()

Por último, el código del bloque If indica a Windows qué hacer con el formulario
después de que los usuarios proporcionen el texto en el cuadro de texto y hagan clic en
Aceptar o presionen la tecla Entrar.

PowerShell

if ($result -eq [System.Windows.Forms.DialogResult]::OK) {


$x = $textBox.Text
$x
}

Consulte también
GitHub: Dave Wyatt's WinFormsExampleUpdates )
Windows PowerShell Tip of the Week: Creating a Custom Input Box (Sugerencia de
la semana de Windows PowerShell: Creación de un cuadro de entrada
personalizado)
Crear un selector de fecha gráfico
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Use Windows PowerShell 3.0 (y versiones posteriores) para crear un formulario con un
control gráfico de estilo de calendario que permita a los usuarios seleccionar un día del
mes.

Crear un control gráfico de selector de fecha


Copie y pegue lo siguiente en Windows PowerShell ISE y, después, guárdelo como un
archivo de script de Windows PowerShell ( .ps1 ).

PowerShell

Add-Type -AssemblyName System.Windows.Forms


Add-Type -AssemblyName System.Drawing

$form = New-Object Windows.Forms.Form -Property @{


StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen
Size = New-Object Drawing.Size 243, 230
Text = 'Select a Date'
Topmost = $true
}

$calendar = New-Object Windows.Forms.MonthCalendar -Property @{


ShowTodayCircle = $false
MaxSelectionCount = 1
}
$form.Controls.Add($calendar)

$okButton = New-Object Windows.Forms.Button -Property @{


Location = New-Object Drawing.Point 38, 165
Size = New-Object Drawing.Size 75, 23
Text = 'OK'
DialogResult = [Windows.Forms.DialogResult]::OK
}
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)

$cancelButton = New-Object Windows.Forms.Button -Property @{


Location = New-Object Drawing.Point 113, 165
Size = New-Object Drawing.Size 75, 23
Text = 'Cancel'
DialogResult = [Windows.Forms.DialogResult]::Cancel
}
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

$result = $form.ShowDialog()

if ($result -eq [Windows.Forms.DialogResult]::OK) {


$date = $calendar.SelectionStart
Write-Host "Date selected: $($date.ToShortDateString())"
}

El script comienza con la carga de dos clases de .NET Framework: System.Drawing y


System.Windows.Forms. A continuación, inicie una nueva instancia de la clase
Windows.Forms.Form de .NET Framework. De esta forma, tendrá una ventana o
formulario en blanco donde puede empezar a agregar controles.

PowerShell

$form = New-Object Windows.Forms.Form -Property @{


StartPosition = [Windows.Forms.FormStartPosition]::CenterScreen
Size = New-Object Drawing.Size 243, 230
Text = 'Select a Date'
Topmost = $true
}

En este ejemplo se asignan valores a cuatro propiedades de esta clase mediante la


propiedad Property y la tabla hash.

1. StartPosition: Si no agrega esta propiedad, Windows selecciona una ubicación


cuando el formulario se abre. Al establecer esta propiedad en CenterScreen, el
formulario aparece automáticamente en el centro de la pantalla cada vez que se
carga.

2. Size: Es el tamaño del formulario en píxeles. El script anterior crea un formulario de


243 píxeles de ancho y 230 píxeles de alto.

3. Text: Es el título de la ventana.

4. Topmost: Al establecer esta propiedad en $true , puede forzar a que la ventana se


abra encima del resto de ventanas y cuadros de diálogo abiertos.

A continuación, cree un control de calendario y agréguelo al formulario. En este


ejemplo, el día actual no está resaltado ni dentro de un círculo. Los usuarios pueden
seleccionar un solo día en el calendario cada vez.

PowerShell
$calendar = New-Object Windows.Forms.MonthCalendar -Property @{
ShowTodayCircle = $false
MaxSelectionCount = 1
}
$form.Controls.Add($calendar)

A continuación, cree un botón Aceptar para el formulario. Indique un tamaño y el


comportamiento del botón Aceptar. En este ejemplo, la posición del botón es de
165 píxeles desde el borde superior del formulario y de 38 píxeles desde el borde
izquierdo. La altura del botón es 23 píxeles y la longitud, 75 píxeles. El script usa tipos
predefinidos de Windows Forms para definir el comportamiento del botón.

PowerShell

$okButton = New-Object Windows.Forms.Button -Property @{


Location = New-Object Drawing.Point 38, 165
Size = New-Object Drawing.Size 75, 23
Text = 'OK'
DialogResult = [Windows.Forms.DialogResult]::OK
}
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)

De manera similar, cree un botón Cancelar. El botón Cancelar está a 165 píxeles de la
parte superior, pero a 113 píxeles del borde izquierdo de la ventana.

PowerShell

$cancelButton = New-Object Windows.Forms.Button -Property @{


Location = New-Object Drawing.Point 113, 165
Size = New-Object Drawing.Size 75, 23
Text = 'Cancel'
DialogResult = [Windows.Forms.DialogResult]::Cancel
}
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

Agregue la siguiente línea de código para mostrar el formulario en Windows.

PowerShell

$result = $form.ShowDialog()

Por último, el código del bloque if indica a Windows qué hacer con el formulario
después de que los usuarios seleccionen un día en el calendario y hagan clic en el botón
Aceptar o presionen la tecla Entrar. Windows PowerShell muestra la fecha seleccionada
a los usuarios.

PowerShell

if ($result -eq [Windows.Forms.DialogResult]::OK) {


$date = $calendar.SelectionStart
Write-Host "Date selected: $($date.ToShortDateString())"
}

Consulte también
GitHub: Dave Wyatt's WinFormsExampleUpdates (GitHub:
WinFormsExampleUpdates de Dave Wyatt)
Sugerencia de la semana de Windows PowerShell: creación de un selector de fecha
gráfico
Cuadros de lista de selección múltiple
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Use Windows PowerShell 3.0 (y versiones posteriores) para crear un control de cuadro
de lista de selección múltiple en un formulario de Windows Forms personalizado.

Crear controles de cuadro de lista que permiten


selecciones múltiples
Copie y pegue lo siguiente en Windows PowerShell ISE y, después, guárdelo como un
archivo de script de Windows PowerShell ( .ps1 ).

PowerShell

Add-Type -AssemblyName System.Windows.Forms


Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form


$form.Text = 'Data Entry Form'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$OKButton = New-Object System.Windows.Forms.Button


$OKButton.Location = New-Object System.Drawing.Point(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)

$CancelButton = New-Object System.Windows.Forms.Button


$CancelButton.Location = New-Object System.Drawing.Point(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)

$label = New-Object System.Windows.Forms.Label


$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Please make a selection from the list below:'
$form.Controls.Add($label)

$listBox = New-Object System.Windows.Forms.Listbox


$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)

$listBox.SelectionMode = 'MultiExtended'

[void] $listBox.Items.Add('Item 1')


[void] $listBox.Items.Add('Item 2')
[void] $listBox.Items.Add('Item 3')
[void] $listBox.Items.Add('Item 4')
[void] $listBox.Items.Add('Item 5')

$listBox.Height = 70
$form.Controls.Add($listBox)
$form.Topmost = $true

$result = $form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK)


{
$x = $listBox.SelectedItems
$x
}

El script comienza con la carga de dos clases de .NET Framework: System.Drawing y


System.Windows.Forms. A continuación, inicie una nueva instancia de la clase
System.Windows.Forms.Form de .NET Framework. De esta forma, tendrá una ventana o
formulario en blanco donde puede empezar a agregar controles.

PowerShell

$form = New-Object System.Windows.Forms.Form

Tras crear una instancia de la clase Form, asigne valores a las tres propiedades de esta
clase.

Texto. Es el título de la ventana.


Tamaño Es el tamaño del formulario en píxeles. El script anterior crea un
formulario de 300 píxeles de ancho y 200 píxeles de alto.
StartingPosition. Esta propiedad opcional está establecida en CenterScreen en el
script anterior. Si no agrega esta propiedad, Windows selecciona una ubicación
cuando el formulario se abre. Cuando StartingPosition se establece en
CenterScreen, el formulario aparece automáticamente en el centro de la pantalla
cada vez que se carga.

PowerShell

$form.Text = 'Data Entry Form'


$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

A continuación, cree un botón Aceptar para el formulario. Indique un tamaño y el


comportamiento del botón Aceptar. En este ejemplo, la posición del botón es de
120 píxeles desde el borde superior del formulario y de 75 píxeles desde el borde
izquierdo. La altura del botón es 23 píxeles y la longitud, 75 píxeles. El script usa tipos
predefinidos de Windows Forms para definir el comportamiento del botón.

PowerShell

$OKButton = New-Object System.Windows.Forms.Button


$OKButton.Location = New-Object System.Drawing.Size(75,120)
$OKButton.Size = New-Object System.Drawing.Size(75,23)
$OKButton.Text = 'OK'
$OKButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $OKButton
$form.Controls.Add($OKButton)

De manera similar, cree un botón Cancelar. El botón Cancelar está a 120 píxeles de la
parte superior, pero a 150 píxeles del borde izquierdo de la ventana.

PowerShell

$CancelButton = New-Object System.Windows.Forms.Button


$CancelButton.Location = New-Object System.Drawing.Point(150,120)
$CancelButton.Size = New-Object System.Drawing.Size(75,23)
$CancelButton.Text = 'Cancel'
$CancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $CancelButton
$form.Controls.Add($CancelButton)

A continuación, escriba texto de etiqueta en la ventana para describir la información que


quiera que los usuarios proporcionen.

PowerShell

$label = New-Object System.Windows.Forms.Label


$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Please make a selection from the list below:'
$form.Controls.Add($label)

Agregue el control (en este caso, un cuadro de lista) que permita a los usuarios
proporcionar la información descrita en el texto de etiqueta. Aparte de los cuadros de
texto, hay otros muchos controles que se pueden aplicar; para conocerlos, vea el tema
sobre el espacio de nombres System.Windows.Forms.
PowerShell

$listBox = New-Object System.Windows.Forms.Listbox


$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)

Aquí indicamos cómo especificar que se quiere permitir a los usuarios seleccionar varios
valores en la lista.

PowerShell

$listBox.SelectionMode = 'MultiExtended'

En la sección siguiente, hay que especificar los valores que quiere que el cuadro de lista
muestre a los usuarios.

PowerShell

[void] $listBox.Items.Add('Item 1')


[void] $listBox.Items.Add('Item 2')
[void] $listBox.Items.Add('Item 3')
[void] $listBox.Items.Add('Item 4')
[void] $listBox.Items.Add('Item 5')

Especifique el alto máximo del control de cuadro de lista.

PowerShell

$listBox.Height = 70

Agregue el control de cuadro de lista al formulario e indique a Windows que, cuando el


formulario se abra, lo haga encima del resto de ventanas y cuadros de diálogo abiertos.

PowerShell

$form.Controls.Add($listBox)
$form.Topmost = $true

Agregue la siguiente línea de código para mostrar el formulario en Windows.

PowerShell

$result = $form.ShowDialog()
Por último, el código del bloque if indica a Windows qué hacer con el formulario
después de que los usuarios seleccionen una o varias opciones en el cuadro de lista y
hagan clic en el botón Aceptar o presionen la tecla Entrar.

PowerShell

if ($result -eq [System.Windows.Forms.DialogResult]::OK)


{
$x = $listBox.SelectedItems
$x
}

Consulte también
Weekend Scripter: corrección de ejemplos de la GUI de PowerShell
GitHub: Dave Wyatt's WinFormsExampleUpdates (GitHub:
WinFormsExampleUpdates de Dave Wyatt)
Sugerencia de Windows PowerShell de la semana: cuadros de lista de selección
múltiple y mucho más
Seleccionar elementos de un cuadro de
lista
Artículo • 13/04/2023

Este ejemplo solo se aplica a las plataformas Windows.

Use Windows PowerShell 3.0 (y versiones posteriores) para crear un cuadro de diálogo
donde los usuarios puedan seleccionar elementos de un control de cuadro de lista.

Crear un control de cuadro de lista y


seleccionar elementos en él
Copie y pegue lo siguiente en Windows PowerShell ISE y, después, guárdelo como un
archivo de script de Windows PowerShell ( .ps1 ).

PowerShell

Add-Type -AssemblyName System.Windows.Forms


Add-Type -AssemblyName System.Drawing

$form = New-Object System.Windows.Forms.Form


$form.Text = 'Select a Computer'
$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

$okButton = New-Object System.Windows.Forms.Button


$okButton.Location = New-Object System.Drawing.Point(75,120)
$okButton.Size = New-Object System.Drawing.Size(75,23)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)

$cancelButton = New-Object System.Windows.Forms.Button


$cancelButton.Location = New-Object System.Drawing.Point(150,120)
$cancelButton.Size = New-Object System.Drawing.Size(75,23)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

$label = New-Object System.Windows.Forms.Label


$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Please select a computer:'
$form.Controls.Add($label)

$listBox = New-Object System.Windows.Forms.ListBox


$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)
$listBox.Height = 80

[void] $listBox.Items.Add('atl-dc-001')
[void] $listBox.Items.Add('atl-dc-002')
[void] $listBox.Items.Add('atl-dc-003')
[void] $listBox.Items.Add('atl-dc-004')
[void] $listBox.Items.Add('atl-dc-005')
[void] $listBox.Items.Add('atl-dc-006')
[void] $listBox.Items.Add('atl-dc-007')

$form.Controls.Add($listBox)

$form.Topmost = $true

$result = $form.ShowDialog()

if ($result -eq [System.Windows.Forms.DialogResult]::OK)


{
$x = $listBox.SelectedItem
$x
}

El script comienza con la carga de dos clases de .NET Framework: System.Drawing y


System.Windows.Forms. A continuación, inicie una nueva instancia de la clase
System.Windows.Forms.Form de .NET Framework. De esta forma, tendrá una ventana o
formulario en blanco donde puede empezar a agregar controles.

PowerShell

Add-Type -AssemblyName System.Windows.Forms


Add-Type -AssemblyName System.Drawing

Después de crear una instancia de la clase Form, asigne valores a tres propiedades de
esta clase.

Texto. Es el título de la ventana.


Tamaño Es el tamaño del formulario en píxeles. El script anterior crea un
formulario de 300 píxeles de ancho y 200 píxeles de alto.
StartingPosition. Esta propiedad opcional está establecida en CenterScreen en el
script anterior. Si no agrega esta propiedad, Windows selecciona una ubicación
cuando el formulario se abre. Cuando StartingPosition se establece en
CenterScreen, el formulario aparece automáticamente en el centro de la pantalla
cada vez que se carga.
PowerShell

$form.Text = 'Select a Computer'


$form.Size = New-Object System.Drawing.Size(300,200)
$form.StartPosition = 'CenterScreen'

A continuación, cree un botón Aceptar para el formulario. Indique un tamaño y el


comportamiento del botón Aceptar. En este ejemplo, la posición del botón es de
120 píxeles desde el borde superior del formulario y de 75 píxeles desde el borde
izquierdo. La altura del botón es 23 píxeles y la longitud, 75 píxeles. El script usa tipos
predefinidos de Windows Forms para definir el comportamiento del botón.

PowerShell

$okButton = New-Object System.Windows.Forms.Button


$okButton.Location = New-Object System.Drawing.Point(75,120)
$okButton.Size = New-Object System.Drawing.Size(75,23)
$okButton.Text = 'OK'
$okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK
$form.AcceptButton = $okButton
$form.Controls.Add($okButton)

De manera similar, cree un botón Cancelar. El botón Cancelar está a 120 píxeles de la
parte superior, pero a 150 píxeles del borde izquierdo de la ventana.

PowerShell

$cancelButton = New-Object System.Windows.Forms.Button


$cancelButton.Location = New-Object System.Drawing.Point(150,120)
$cancelButton.Size = New-Object System.Drawing.Size(75,23)
$cancelButton.Text = 'Cancel'
$cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
$form.CancelButton = $cancelButton
$form.Controls.Add($cancelButton)

A continuación, escriba texto de etiqueta en la ventana para describir la información que


quiera que los usuarios proporcionen. En este caso, lo que se pretende es que los
usuarios seleccionen un equipo.

PowerShell

$label = New-Object System.Windows.Forms.Label


$label.Location = New-Object System.Drawing.Point(10,20)
$label.Size = New-Object System.Drawing.Size(280,20)
$label.Text = 'Please select a computer:'
$form.Controls.Add($label)
Agregue el control (en este caso, un cuadro de lista) que permita a los usuarios
proporcionar la información descrita en el texto de etiqueta. Aparte de los cuadros de
lista, hay otros muchos controles que se pueden aplicar; para conocerlos, vea el tema
sobre el espacio de nombres System.Windows.Forms.

PowerShell

$listBox = New-Object System.Windows.Forms.ListBox


$listBox.Location = New-Object System.Drawing.Point(10,40)
$listBox.Size = New-Object System.Drawing.Size(260,20)
$listBox.Height = 80

En la sección siguiente, hay que especificar los valores que quiere que el cuadro de lista
muestre a los usuarios.

7 Nota

El cuadro de lista creado con este script solo permite realizar una selección. Para
crear un control de cuadro de lista que permita selecciones múltiples, especifique
un valor para la propiedad SelectionMode, como aquí: $listBox.SelectionMode =
'MultiExtended' . Para más información, consulte Cuadros de lista de selección
múltiple.

PowerShell

[void] $listBox.Items.Add('atl-dc-001')
[void] $listBox.Items.Add('atl-dc-002')
[void] $listBox.Items.Add('atl-dc-003')
[void] $listBox.Items.Add('atl-dc-004')
[void] $listBox.Items.Add('atl-dc-005')
[void] $listBox.Items.Add('atl-dc-006')
[void] $listBox.Items.Add('atl-dc-007')

Agregue el control de cuadro de lista al formulario e indique a Windows que, cuando el


formulario se abra, lo haga encima del resto de ventanas y cuadros de diálogo abiertos.

PowerShell

$form.Controls.Add($listBox)
$form.Topmost = $true

Agregue la siguiente línea de código para mostrar el formulario en Windows.

PowerShell
$result = $form.ShowDialog()

Por último, el código del bloque If indica a Windows qué hacer con el formulario
después de que los usuarios seleccionen una opción en el cuadro de lista y hagan clic
en Aceptar o presionen la tecla Entrar.

PowerShell

if ($result -eq [System.Windows.Forms.DialogResult]::OK) {


$x = $listBox.SelectedItem
$x
}

Consulte también
GitHub: Dave Wyatt's WinFormsExampleUpdates (GitHub:
WinFormsExampleUpdates de Dave Wyatt)
Windows PowerShell Tip of the Week: Selecting Items from a List Box (Sugerencia
de la semana de Windows PowerShell: seleccionar elementos de un cuadro de
lista)
Just Enough Administration (JEA)
Artículo • 13/04/2023

Just Enough Administration (JEA) es una tecnología de seguridad que permite la


administración delegada de todo lo que administra PowerShell. Con JEA, se puede hacer
lo siguiente:

Reducir el número de administradores de las máquinas mediante cuentas


virtuales o cuentas de servicio administradas por grupos para realizar acciones con
privilegios en nombre de usuarios normales.
Limitar lo que pueden hacer los usuarios especificando qué cmdlets, funciones y
comandos externos pueden ejecutar.
Entender mejor lo que hacen los usuarios con transcripciones y registros que
muestran exactamente qué comandos ha ejecutado un usuario durante su sesión.

¿Por qué es importante JEA?

Las cuentas con muchos privilegios usadas para administrar los servidores suponen un
grave riesgo de seguridad. Si un atacante compromete una de estas cuentas, podría
iniciar ataques laterales en toda la organización. Cada cuenta comprometida puede
dar a un atacante acceso incluso a más cuentas y recursos, y ponerle un paso más cerca
de robar secretos de la empresa, iniciar un ataque por denegación de servicio y mucho
más.

No siempre es fácil quitar privilegios administrativos. Tenga en cuenta el escenario


común en que el rol DNS está instalado en el mismo equipo que el controlador de
dominio de Active Directory. Los administradores de DNS necesitan privilegios de
administrador local para solucionar problemas con el servidor DNS. Pero para ello, debe
convertirlos en miembros del grupo de seguridad con privilegios elevados Admins. del
dominio. Este enfoque proporciona a los administradores de DNS el control sobre todo
el dominio y les permite acceder a todos los recursos de la máquina.

JEA resuelve este problema a través del principio de privilegios mínimos. Con JEA,
puede configurar un punto de conexión de administración para los administradores de
DNS que les proporcione acceso solo a los comandos de PowerShell que necesitan para
realizar su trabajo. Esto significa que puede proporcionar el acceso adecuado para
reparar una caché DNS dañada o reiniciar el servidor DNS sin concederles
involuntariamente derechos en Active Directory, para examinar el sistema de archivos o
para ejecutar scripts potencialmente peligrosos. Y lo que es mejor, cuando la sesión de
JEA está configurada para usar cuentas virtuales con privilegios temporales, los
administradores de DNS pueden conectarse al servidor mediante credenciales que no
sean de administrador y seguir ejecutando comandos que normalmente requieren
privilegios de administrador. JEA permite quitar usuarios de roles de administrador local
o de dominio con muchos privilegios, y controlar cuidadosamente qué pueden hacer en
cada equipo.

Pasos siguientes
Para obtener más información sobre los requisitos para usar JEA, vea el artículo de
requisitos previos.

Ejemplos y recurso de DSC


En el repositorio de GitHub de JEA puede encontrar configuraciones de JEA de
ejemplo y el recurso de DSC de JEA.
Requisitos previos de JEA
Artículo • 13/04/2023

Just Enough Administration es una característica incluida en PowerShell 5.0 y versiones


posteriores. En este artículo se describen los requisitos previos que se deben cumplir
para empezar a usar JEA.

Comprobar qué versión de PowerShell está


instalada
Para comprobar qué versión de PowerShell está instalada en el sistema, compruebe la
variable $PSVersionTable en un símbolo del sistema de Windows PowerShell.

PowerShell

$PSVersionTable.PSVersion

Output

Major Minor Build Revision


----- ----- ----- --------
5 1 14393 1000

JEA está disponible con PowerShell 5.0 y versiones posteriores. Para obtener la
funcionalidad completa, se recomienda instalar la versión más reciente de PowerShell
disponible para el sistema. En la tabla siguiente, se describe la disponibilidad de JEA en
Windows Server:

Sistema operativo de servidor Disponibilidad de JEA

Windows Server 2016+ Preinstalado

Windows Server 2012 R2 Funcionalidad completa con WMF 5.1

Windows Server 2012 Funcionalidad completa con WMF 5.1

Windows Server 2008 R2 Funcionalidad reducida1 con WMF 5.1

También puede usar JEA en el equipo de casa o del trabajo:

Sistema operativo de cliente Disponibilidad de JEA


Sistema operativo de cliente Disponibilidad de JEA

Windows 10 1607+ Preinstalado

Windows 10 1603, 1511 Preinstalado, con funcionalidad reducida2

Windows 10 1507 No disponible

Windows 8, 8.1 Funcionalidad completa con WMF 5.1

Windows 7 Funcionalidad reducida1 con WMF 5.1

1 JEA no se puede configurar para usar cuentas de servicio administradas de grupo


en Windows Server 2008 R2 o Windows 7. Las cuentas virtuales y otras
características de JEA sí se admiten.

2
Las características de JEA siguientes no se admiten en las versiones 1511 y 1603
de Windows 10:
Ejecución como una cuenta de servicio administrada de grupo
Reglas de acceso condicional en configuraciones de sesión
Unidad de usuario
Concesión de acceso a cuentas de usuario locales

Para obtener compatibilidad con estas características, actualice Windows a la


versión 1607 (actualización de aniversario) o a una versión superior.

Instalar Windows Management Framework


Si ejecuta una versión anterior de PowerShell, es posible que tenga que actualizar el
sistema con la actualización más reciente de Windows Management Framework (WMF).
Para obtener más información, vea la documentación de WMF.

Se recomienda probar la compatibilidad de la carga de trabajo con WMF antes de


actualizar todos los servidores.

Los usuarios de Windows 10 deben instalar las actualizaciones más recientes de las
características para obtener la versión actual de Windows PowerShell.

Habilitar Comunicación remota con PowerShell


La comunicación remota de PowerShell proporciona la base sobre la que se compila JEA.
Es necesario garantizar que la comunicación remota de PowerShell está habilitada y
protegida de forma adecuada antes de poder usar JEA. Para obtener más información,
vea Seguridad de WinRM.
La comunicación remota de PowerShell está habilitada de manera predeterminada en
Windows Server 2012, 2012 R2 y 2016. Puede habilitar la comunicación remota de
PowerShell si ejecuta el siguiente comando en una ventana de PowerShell con
privilegios elevados.

PowerShell

Enable-PSRemoting

Habilitar el registro de bloques de script y


módulos de PowerShell (opcional)
En los siguientes pasos se habilita el registro para todas las acciones de PowerShell del
sistema. El registro de módulos de PowerShell no es necesario para JEA, pero se
recomienda activarlo para asegurarse de que los comandos que ejecutan los usuarios se
registran en una ubicación central.

Puede configurar la directiva de registro de módulos de PowerShell mediante la


directiva de grupo.

1. Abra el Editor de directivas de grupo local en una estación de trabajo o un objeto


de directiva de grupo en la consola de administración de directivas de grupo en un
controlador de dominio de Active Directory.
2. Vaya a Configuración del equipo\Plantillas administrativas\Componentes de
Windows\Windows PowerShell
3. Haga doble clic en Activar registro de módulos.
4. Haga clic en Habilitado.
5. En la sección Opciones, haga clic en Mostrar junto a Nombres de módulos.
6. Escriba * en la ventana emergente para registrar comandos de todos los módulos.
7. Haga clic en Aceptar para establecer la directiva.
8. Haga doble clic en Activar el registro de bloque de script de PowerShell.
9. Haga clic en Habilitado.
10. Haga clic en Aceptar para establecer la directiva.
11. (Solo en equipos unidos a un dominio) Ejecute gpupdate o espere a que la
directiva de grupo procese la directiva actualizada y aplique la configuración.

También puede habilitar la transcripción de PowerShell de todo el sistema a través de la


directiva de grupo.

Pasos siguientes
Crear un archivo de funcionalidad de rol
Crear un archivo de configuración de sesión

Consulte también
Seguridad de WinRM
PowerShell ♥ the Blue Team
Funcionalidades de rol de JEA
Artículo • 13/04/2023

Al crear un punto de conexión de JEA, tiene que definir una o varias funcionalidades de
rol que describan lo que puede hacer un usuario en una sesión de JEA. Una
funcionalidad de rol es un archivo de datos de PowerShell con la extensión .psrc que
enumera los cmdlets, las funciones, los proveedores y los programas externos que se
ponen a disposición de los usuarios que se conectan.

Determinar los comandos permitidos


El primer paso al crear un archivo de funcionalidad de rol es tener en cuenta a qué
necesitan acceso los usuarios. El proceso de recopilación de requisitos puede tardar un
tiempo, pero es importante. Conceder acceso a los usuarios a muy pocos cmdlets y
funciones puede impedirles llevar a cabo su trabajo. Permitir el acceso a demasiados
cmdlets y funciones puede permitir que los usuarios realicen más operaciones de las
previstas y debilitar la posición en materia de seguridad.

La manera de realizar este proceso depende de la organización y los objetivos. Las


sugerencias siguientes pueden ayudarle a asegurarse de tomar el camino correcto.

1. Identifique los comandos que usan los usuarios para realizar su trabajo. Esto
puede implicar encuestar al personal de TI, comprobar los scripts de
automatización o analizar registros y transcripciones de sesión de PowerShell.
2. Actualice el uso de herramientas de línea de comandos por equivalentes de
PowerShell, siempre que sea posible, para tener la mejor experiencia de
personalización de JEA y auditoría. En JEA, los programas externos no se pueden
restringir con la misma minuciosidad que los cmdlets y las funciones nativos de
PowerShell.
3. Restrinja el ámbito de los cmdlets para permitir solo parámetros o valores de
parámetro específicos. Esto es especialmente importante si los usuarios solo deben
administrar una parte de un sistema.
4. Cree funciones personalizadas para reemplazar comandos complejos o que son
difíciles de restringir en JEA. Una función sencilla que encapsule un comando
complejo o aplique lógica de validación adicional puede ofrecer un mayor control
para simplificar los administradores y usuarios finales.
5. Pruebe la lista con ámbito de los comandos permitidos con los usuarios o los
servicios de automatización, y ajústela según sea necesario.
Ejemplos de comandos potencialmente peligrosos
Es importante seleccionar los comandos para asegurarse de que el punto de conexión
de JEA no permita que el usuario eleve sus permisos.

) Importante

La información esencial necesaria para successCommands de usuario en una sesión


de JEA se suele ejecutar con privilegios elevados.

La lista siguiente contiene ejemplos de comandos que se pueden usar de forma


malintencionada si se permiten en un estado sin restricciones. Esta lista no es exhaustiva
y solo se debe usar como punto inicial de advertencia.

Riesgo: Concesión de privilegios de administrador de usuario de conexión para


omitir JEA

Ejemplo:

PowerShell

Add-LocalGroupMember -Member 'CONTOSO\jdoe' -Group 'Administrators'

Comandos relacionados:
Add-ADGroupMember

Add-LocalGroupMember
net.exe

dsadd.exe

Riesgo: Ejecución de código arbitrario, como malware, vulnerabilidades de


seguridad o scripts personalizados para omitir las protecciones

Ejemplo:

PowerShell

Start-Process -FilePath '\\san\share\malware.exe'

Comandos relacionados:
Start-Process
New-Service

Invoke-Item
Invoke-WmiMethod

Invoke-CimMethod
Invoke-Expression

Invoke-Command
New-ScheduledTask

Register-ScheduledJob

Crear un archivo de funcionalidad de rol


Puede crear un archivo de funcionalidad de rol de PowerShell con el cmdlet New-
PSRoleCapabilityFile.

PowerShell

New-PSRoleCapabilityFile -Path .\MyFirstJEARole.psrc

Debe editar el archivo de funcionalidad de rol creado para permitir solo los comandos
necesarios para el rol. La documentación de ayuda de PowerShell contiene varios
ejemplos de cómo configurar el archivo.

Permitir funciones y cmdlets de PowerShell


Para autorizar a los usuarios a ejecutar cmdlets o funciones de PowerShell, agregue el
nombre del cmdlet o de la función a los campos VisibleCmdlets o VisibleFunctions . Si
no está seguro de si un comando es un cmdlet o una función, puede ejecutar Get-
Command <name> y comprobar la propiedad CommandType en la salida.

PowerShell

VisibleCmdlets = @('Restart-Computer', 'Get-NetIPAddress')

A veces, el ámbito de un cmdlet o una función específicos es demasiado amplio para las
necesidades de los usuarios. Un administrador dns, por ejemplo, puede que solo
necesite acceso para reiniciar el servicio DNS. En entornos multiinquilino, los inquilinos
tienen acceso a herramientas de administración de autoservicio. Los inquilinos se deben
limitar a la administración de sus propios recursos. En estos casos, puede restringir los
parámetros que se exponen mediante la función o el cmdlet.

PowerShell
VisibleCmdlets = @{
Name = 'Restart-Computer'
Parameters = @{ Name = 'Name' }
}

En escenarios más avanzados, es posible que también tenga que restringir los valores
que un usuario puede utilizar con estos parámetros. Las funcionalidades de rol permiten
definir un conjunto de valores o un patrón de expresión regular para determinar qué
entrada se permite.

PowerShell

VisibleCmdlets = @(
@{
Name = 'Restart-Service'
Parameters = @{ Name = 'Name'; ValidateSet = @('Dns', 'Spooler') }
}
@{
Name = 'Start-Website'
Parameters = @{ Name = 'Name'; ValidatePattern = 'HR_*' }
}
)

7 Nota

Los parámetros comunes de PowerShell se permiten siempre, incluso si restringe


los parámetros disponibles. No debe enumerarlos explícitamente en el campo
Parámetros.

En la lista siguiente se describen las distintas formas en que puede personalizar un


cmdlet o una función visibles. Puede combinar cualquiera de los siguientes en el campo
VisibleCmdlets.

Caso de uso: Permitir que el usuario se ejecute My-Func sin restricciones en los
parámetros.

PowerShell

@{ Name = 'My-Func' }

Caso de uso: Permitir que el usuario se ejecute My-Func desde el módulo


MyModule sin restricciones en los parámetros.
PowerShell

@{ Name = 'MyModule\My-Func' }

Caso de uso: Permita al usuario ejecutar cualquier cmdlet o función con el verbo
My .

PowerShell

@{ Name = 'My-*' }

Caso de uso: Permita al usuario ejecutar cualquier cmdlet o función con el nombre
Func .

PowerShell

@{ Name = '*-Func' }

Caso de uso: Permitir que el usuario se ejecute My-Func con los Param1 parámetros
y Param2 . Para estos parámetros, se puede proporcionar cualquier valor.

PowerShell

@{ Name = 'My-Func'; Parameters = @{ Name = 'Param1'}, @{ Name =


'Param2' }}

Caso de uso: Permitir que el usuario se ejecute My-Func con el Param1 parámetro .
Solo Value1 y Value2 se pueden proporcionar al parámetro .

PowerShell

@{
Name = 'My-Func'
Parameters = @{ Name = 'Param1'; ValidateSet = @('Value1',
'Value2') }
}

Caso de uso: Permitir que el usuario se ejecute My-Func con el Param1 parámetro .
Cualquier valor que comience por contoso se puede proporcionar al parámetro .

PowerShell

@{
Name = 'My-Func'
Parameters = @{ Name = 'Param1'; ValidatePattern = 'contoso.*' }
}

2 Advertencia

En el caso de los procedimientos de seguridad recomendados, no se recomienda


usar caracteres comodín al definir cmdlets o funciones visibles. En su lugar, debe
enumerar de forma explícita cada comando de confianza para asegurarse de que
ningún otro comando que comparta el mismo esquema de nombre se autorice de
forma involuntaria.

No se pueden aplicar ValidatePattern y ValidateSet al mismo cmdlet o función.

Si lo hace, ValidatePattern invalidará a ValidateSet.

Para obtener más información sobre ValidatePattern, consulte esta publicación de Hey,
Scripting Guy! y el contenido de referencia de expresiones regulares de PowerShell.

Permitir comandos externos y scripts de PowerShell


Para permitir que los usuarios ejecuten ejecutables y scripts de PowerShell ( .ps1 ) en una
sesión de JEA, debe agregar la ruta de acceso completa a cada programa en el campo
VisibleExternalCommands .

PowerShell

VisibleExternalCommands = @(
'C:\Windows\System32\whoami.exe'
'C:\Program Files\Contoso\Scripts\UpdateITSoftware.ps1'
)

Siempre que sea posible, use el cmdlet de PowerShell o los equivalentes de función para
cualquier archivo ejecutable externo que autorice, ya que tiene control sobre los
parámetros permitidos con cmdlets y funciones de PowerShell.

Muchos ejecutables permiten leer el estado actual y, después, proporcionar otros


parámetros para cambiarlo.

Por ejemplo, considere la función de un administrador de servidor de archivos que


administra recursos compartidos de red hospedados en un sistema. Una manera de
administrar los recursos compartidos consiste en usar net share . Sin embargo, permitir
net.exe es peligroso porque el usuario podría usar el comando para obtener privilegios
de administrador con el comando net group Administrators unprivilegedjeauser /add .
Una opción más segura es permitir el cmdlet Get-SmbShare , que logra el mismo
resultado, pero tiene un ámbito mucho más limitado.

Al poner comandos externos a disposición de los usuarios en una sesión de JEA,


especifique siempre la ruta de acceso completa al archivo ejecutable. Esto impide la
ejecución de programas con nombres similares y potencialmente malintencionados
ubicados en otro lugar en el sistema.

Permitir el acceso a proveedores de PowerShell


De manera predeterminada, no hay ningún proveedor de PowerShell disponible en las
sesiones de JEA. Esto reduce el riesgo de que se revele información confidencial y
opciones de configuración al usuario que se conecta.

Cuando sea necesario, puede permitir el acceso a los proveedores de PowerShell


mediante el comando VisibleProviders . Para obtener una lista completa de
proveedores, ejecute Get-PSProvider .

PowerShell

VisibleProviders = 'Registry'

Para realizar tareas sencillas que requieren acceso al sistema de archivos, el Registro, el
almacén de certificados u otros proveedores de información confidencial, considere la
posibilidad de escribir una función personalizada que funcione con el proveedor en
nombre del usuario. Los cmdlets, las funciones y los programas externos disponibles en
una sesión de JEA no están sujetos a las mismas restricciones que JEA. Pueden acceder a
cualquier proveedor de manera predeterminada. Considere también la posibilidad de
usar la unidad de usuario cuando los usuarios necesiten copiar archivos hacia o desde
un punto de conexión de JEA.

Crear funciones personalizadas


Puede crear funciones personalizadas en un archivo de funcionalidad de rol para
simplificar tareas complejas para los usuarios finales. Las funciones personalizadas
también son útiles cuando se requiere una lógica de validación avanzada para los
valores de parámetros de cmdlet. Puede escribir funciones simples en el campo
FunctionDefinitions:

PowerShell
VisibleFunctions = 'Get-TopProcess'

FunctionDefinitions = @{
Name = 'Get-TopProcess'
ScriptBlock = {
param($Count = 10)

Get-Process |
Sort-Object -Property CPU -Descending |
Microsoft.PowerShell.Utility\Select-Object -First $Count
}
}

) Importante

No olvide agregar el nombre de las funciones personalizadas en el campo


VisibleFunctions para que las puedan ejecutar los usuarios de JEA.

El cuerpo (bloque de script) de las funciones personalizadas se ejecuta en el modo de


lenguaje predeterminado del sistema y no está sujeto a las restricciones de lenguaje de
JEA. Esto significa que las funciones pueden acceder al sistema de archivos y al Registro,
y ejecutar comandos que no se han hecho visibles en el archivo de funcionalidad de rol.
Al usar parámetros, tenga cuidado para evitar la ejecución de código arbitrario. Evite
canalizar la entrada del usuario directamente a cmdlets como Invoke-Expression .

En el ejemplo anterior, observe que se ha usado el nombre de módulo completo


(FQMN) Microsoft.PowerShell.Utility\Select-Object en lugar de la forma abreviada
Select-Object . Las funciones definidas en los archivos de funcionalidad de función

siguen dependiendo del ámbito de las sesiones de JEA, que incluye las funciones de
proxy que crea JEA para restringir comandos existentes.

De forma predeterminada, Select-Object es un cmdlet restringido en todas las sesiones


de JEA que no permite la selección de propiedades arbitrarias en objetos. Para usar
Select-Object sin restricciones en las funciones, debe solicitar de forma explícita la

implementación completa mediante el FQMN. Cualquier cmdlet sin restricciones en una


sesión de JEA tiene las mismas restricciones cuando se invoca desde una función. Para
obtener más información, vea about_Command_Precedence.

Si va a escribir varias funciones personalizadas, resulta más cómodo colocarlas en un


módulo de script de PowerShell. Puede hacer visibles esas funciones en la sesión de JEA
mediante el campo VisibleFunctions como lo haría con módulos integrados y de
terceros.
Para que la finalización con tabulación funcione correctamente en las sesiones de JEA,
debe incluir la función integrada tabexpansion2 en la lista VisibleFunctions.

Poner las funcionalidades de rol a disposición


de una configuración
Antes de PowerShell 6, para que PowerShell encuentre un archivo de funcionalidad de
rol, debe almacenarse en una RoleCapabilities carpeta de un módulo de PowerShell. El
módulo se puede almacenar en cualquier carpeta incluida en la variable de entorno
$env:PSModulePath , pero no se debe colocar en $env:SystemRoot\System32 ni en una

carpeta donde los usuarios que no sean de confianza puedan modificar los archivos.

En el siguiente ejemplo se crea un módulo de script de PowerShell llamado ContosoJEA


en la ruta de acceso $env:ProgramFiles para hospedar el archivo de funcionalidades de
rol.

PowerShell

# Create a folder for the module


$modulePath = Join-Path $env:ProgramFiles
"WindowsPowerShell\Modules\ContosoJEA"
New-Item -ItemType Directory -Path $modulePath

# Create an empty script module and module manifest.


# At least one file in the module folder must have the same name as the
folder itself.
$rootModulePath = Join-Path $modulePath "ContosoJEAFunctions.psm1"
$moduleManifestPath = Join-Path $modulePath "ContosoJEA.psd1"
New-Item -ItemType File -Path $RootModulePath
New-ModuleManifest -Path $moduleManifestPath -RootModule
"ContosoJEAFunctions.psm1"

# Create the RoleCapabilities folder and copy in the PSRC file


$rcFolder = Join-Path $modulePath "RoleCapabilities"
New-Item -ItemType Directory $rcFolder
Copy-Item -Path .\MyFirstJEARole.psrc -Destination $rcFolder

Para obtener más información sobre los módulos de PowerShell, vea Descripción de un
módulo de PowerShell.

A partir de PowerShell 6, la propiedad RoleDefinitions se agregó al archivo de


configuración de sesión. Esta propiedad le permite especificar la ubicación de un archivo
de configuración de sesión para su definición de roles. Consulte los ejemplos en New-
PSSessionConfigurationFile.
Actualizar funcionalidades de rol
Puede editar un archivo de funcionalidad de rol para actualizar la configuración en
cualquier momento. Cualquier sesión de JEA nueva iniciada después de que se haya
actualizado la funcionalidad de rol reflejará las funcionalidades revisadas.

Por esto es tan importante controlar el acceso a la carpeta de funcionalidades de rol.


Solo los administradores de plena confianza deberían tener permiso para cambiar los
archivos de funcionalidad de rol. Si un usuario que no sea de confianza puede cambiar
los archivos de funcionalidad de rol, puede proporcionarse acceso fácilmente a cmdlets
que le permitan elevar sus privilegios.

Para los administradores que buscan bloquear el acceso a las funcionalidades de rol,
asegúrese de que el sistema local tiene acceso de solo lectura a los archivos de
funcionalidad de rol y contiene módulos.

Cómo se combinan las funcionalidades de rol


A los usuarios se les concede acceso a todas las funcionalidades de rol que coinciden en
el archivo de configuración de sesión cuando entran en una sesión de JEA. JEA intenta
proporcionar al usuario el conjunto de comandos más permisivo permitido por
cualquiera de los roles.

VisibleCmdlets y VisibleFunctions
La lógica de combinación más compleja afecta a los cmdlets y funciones, que pueden
tener sus parámetros y valores de parámetro limitados en JEA.

Estas son las reglas:

1. Si un cmdlet solo se hace visible en un rol, es visible para el usuario con cualquier
restricción de parámetro aplicable.
2. Si un cmdlet está visible en más de un rol, y todos los roles tienen las mismas
restricciones en el cmdlet, el cmdlet es visible para el usuario con esas
restricciones.
3. Si un cmdlet está visible en más de un rol, y todos los roles permiten otro conjunto
de parámetros, el cmdlet y todos los parámetros definidos en cada rol son visibles
para el usuario. Si un rol no tiene restricciones en los parámetros, se permiten
todos los parámetros.
4. Si un rol define un conjunto de validación o un patrón de validación para un
parámetro de cmdlet, y el otro rol permite el parámetro, pero no restringe los
valores de parámetro, se omite el conjunto de validación o el patrón.
5. Si se define un conjunto validado para el mismo parámetro de cmdlet en más de
un rol, se permiten todos los valores de todos los conjuntos validados.
6. Si se define un patrón validado para el mismo parámetro de cmdlet en más de un
rol, se permiten todos los valores que coincidan con cualquiera de los patrones.
7. Si se define un conjunto validado en uno o varios roles y se define un patrón
validado en otro rol para el mismo parámetro de cmdlet, se omite el conjunto
validado y se aplica la regla (6) a los demás patrones validados.

A continuación se muestra un ejemplo de cómo se combinan los roles según estas


reglas:

PowerShell

# Role A Visible Cmdlets


$roleA = @{
VisibleCmdlets = @(
'Get-Service'
@{
Name = 'Restart-Service'
Parameters = @{ Name = 'DisplayName'; ValidateSet = 'DNS Client'
}
}
)
}

# Role B Visible Cmdlets


$roleB = @{
VisibleCmdlets = @(
@{
Name = 'Get-Service';
Parameters = @{ Name = 'DisplayName'; ValidatePattern = 'DNS.*'
}
}
@{
Name = 'Restart-Service'
Parameters = @{ Name = 'DisplayName'; ValidateSet = 'DNS Server'
}
}
)
}

# Resulting permissions for a user who belongs to both role A and B


# - The constraint in role B for the DisplayName parameter on Get-Service
# is ignored because of rule #4
# - The ValidateSets for Restart-Service are merged because both roles use
# ValidateSet on the same parameter per rule #5
$mergedAandB = @{
VisibleCmdlets = @(
'Get-Service'
@{
Name = 'Restart-Service';
Parameters = @{
Name = 'DisplayName'
ValidateSet = 'DNS Client', 'DNS Server'
}
}
)
}

VisibleExternalCommands, VisibleAliases,
VisibleProviders, ScriptsToProcess
Todos los demás campos del archivo de funcionalidad de rol se agregan a un conjunto
acumulativo de alias, proveedores, scripts de inicio y comandos externos permitidos.
Cualquier comando, alias, proveedor o script disponible en una funcionalidad de rol está
disponible para el usuario de JEA.

Asegúrese de que el conjunto combinado de proveedores de una funcionalidad de rol y


los cmdlets, funciones y comandos de otra no permitan que los usuarios accedan de
forma involuntaria a recursos del sistema. Por ejemplo, si un rol permite el cmdlet
Remove-Item y otro permite el proveedor FileSystem , corre el riesgo de que un usuario
de JEA elimine archivos arbitrarios de su equipo. Puede encontrar información adicional
sobre cómo identificar los permisos efectivos de los usuarios en el artículo sobre
auditoría de JEA.

Pasos siguientes
Crear un archivo de configuración de sesión
Configuraciones de sesión de JEA
Artículo • 13/04/2023

Un punto de conexión de JEA se registra en un sistema mediante la creación y el


registro de un archivo de configuración de sesión de PowerShell. Las configuraciones de
sesión definen quién puede usar el punto de conexión de JEA y qué roles tienen acceso
a él. También definen la configuración global que se aplica a todos los usuarios de la
sesión de JEA.

Crear un archivo de configuración de sesión


Para registrar un punto de conexión de JEA, debe especificar cómo se configura ese
punto de conexión. Hay muchas opciones que tener en cuenta. Las más importantes son
las siguientes:

Quién tiene acceso al punto de conexión de JEA


Qué roles se les ha asignado
Qué identidad de JEA se usa en segundo plano
El nombre del punto de conexión de JEA

Estas opciones se definen en un archivo de datos de PowerShell con una extensión


.pssc , denominado archivo de configuración de sesión de PowerShell. El archivo de

configuración de sesión se puede modificar en cualquier editor de texto.

Ejecute el comando siguiente para crear un archivo de configuración de plantilla en


blanco.

PowerShell

New-PSSessionConfigurationFile -SessionType RestrictedRemoteServer -Path


.\MyJEAEndpoint.pssc

 Sugerencia

De forma predeterminada, en el archivo de plantilla solo se incluyen las opciones


de configuración más comunes. Use el conmutador -Full para incluir todas las
opciones aplicables en el PSSC generado.

El campo -SessionType RestrictedRemoteServer indica que JEA usa la configuración de


sesión para la administración segura. Las sesiones de este tipo funcionan en modo
NoLanguage y solo tienen acceso a los comandos (y alias) predeterminados siguientes:

Clear-Host ( cls , clear )


Exit-PSSession ( exsn , exit )

Get-Command ( gcm )
Get-FormatData

Get-Help

Measure-Object ( measure )
Out-Default

Select-Object ( select )

No hay ningún proveedor de PowerShell disponible, ni tampoco ningún programa


externo (ejecutables o scripts).

Para obtener más información sobre los modos de lenguaje, vea Acerca de los modos
de lenguaje.

Elegir la identidad de JEA


En segundo plano, JEA necesita una identidad (cuenta) para usarla al ejecutar los
comandos de un usuario conectado. En el archivo de configuración de sesión se define
qué identidad usa JEA.

Cuenta virtual local

Las cuentas virtuales locales son útiles cuando todos los roles definidos para el punto de
conexión de JEA se usan para administrar el equipo local y una cuenta de administrador
local es suficiente para ejecutar los comandos de forma correcta. Las cuentas virtuales
son cuentas temporales que son únicas para un usuario específico y solo duran lo
mismo que la sesión de PowerShell. En un servidor miembro o estación de trabajo, las
cuentas virtuales pertenecen al grupo Administradores del equipo local. En un
controlador de dominio de Active Directory, las cuentas virtuales pertenecen al grupo
Administradores de dominio.

PowerShell

# Setting the session to use a virtual account


RunAsVirtualAccount = $true

Si los roles definidos por la configuración de sesión no requieren privilegios


administrativos completos, puede especificar los grupos de seguridad a los que
pertenecerá la cuenta virtual. En un servidor miembro o estación de trabajo, los grupos
de seguridad especificados deben ser grupos locales, no grupos de un dominio.

Cuando se especifican uno o varios grupos de seguridad, la cuenta virtual no se asigna


al grupo de administradores local o de dominio.

PowerShell

# Setting the session to use a virtual account that only belongs to the
NetworkOperator and NetworkAuditor local groups
RunAsVirtualAccount = $true
RunAsVirtualAccountGroups = 'NetworkOperator', 'NetworkAuditor'

7 Nota

Las cuentas virtuales se conceden temporalmente en el inicio de sesión como


derecho de servicio en la directiva de seguridad del servidor local. Si a uno de los
VirtualAccountGroups especificados ya se le ha concedido este derecho en la
directiva, la cuenta virtual individual ya no se agregará y se quitará de la directiva.
Esto puede ser útil en escenarios como los controladores de dominio, donde se
auditan estrechamente las revisiones de la directiva de seguridad del controlador
de dominio. Esto solo está disponible en Windows Server 2016 con el paquete
acumulativo de revisiones de noviembre de 2018 o un paquete posterior y en
Windows Server 2019 con el paquete acumulativo de revisiones de enero de 2019
o un paquete posterior.

Cuenta de servicio administrada de grupo


Una cuenta de servicio administrada de grupo (GMSA) es la identidad adecuada para
usarla cuando los usuarios de JEA tienen que acceder a recursos de red como recursos
compartidos de archivos y servicios web. Los GMSA proporcionan una identidad de
dominio que se usa para autenticarse con recursos en cualquier máquina del dominio.
Los derechos que proporciona una GMSA están determinados por los recursos a los que
se accede. No tiene derechos de administrador en ningún equipo o servicio a menos
que el administrador del equipo o servicio haya concedido de forma explícita esos
privilegios a la cuenta GMSA.

PowerShell

# Configure JEA sessions to use the GMSA in the local computer's domain
# with the sAMAccountName of 'MyJEAGMSA'
GroupManagedServiceAccount = 'Domain\MyJEAGMSA'
Las GMSA solo se deben usar cuando sea necesario:

Cuando se usa una GMSA, es difícil realizar el seguimiento de las acciones hasta un
usuario. Todos los usuarios comparten la misma identidad de ejecución. Tendrá
que revisar los registros y las transcripciones de la sesión de PowerShell para poner
en correlación a los usuarios individuales con sus acciones.

La GMSA puede tener acceso a muchos recursos de red a los que el usuario que se
conecta no necesita acceso. Intente limitar siempre los permisos efectivos en una
sesión de JEA para seguir el principio de privilegios mínimos.

7 Nota

Las cuentas de servicio administradas de grupo solo están disponibles en equipos


unidos a un dominio en los que se usa PowerShell 5.1.

Para obtener más información sobre cómo proteger una sesión de JEA, vea el artículo
sobre consideraciones de seguridad.

Transcripciones de sesión
Es recomendable configurar un punto de conexión de JEA para registrar de forma
automática las transcripciones de las sesiones de los usuarios. Las transcripciones de
sesión de PowerShell contienen información sobre el usuario que se conecta, la
identidad de ejecución asignada y los comandos que ha ejecutado el usuario. Pueden
ser útiles para un equipo de auditoría que necesite saber quién ha realizado un cambio
específico en un sistema.

Para configurar la transcripción automática en el archivo de configuración de sesión,


proporcione una ruta de acceso a una carpeta en que se almacenarán las
transcripciones.

PowerShell

TranscriptDirectory = 'C:\ProgramData\JEAConfiguration\Transcripts'

La cuenta de sistema local, que requiere acceso de lectura y escritura al directorio,


escribe las transcripciones en la carpeta. Los usuarios estándar no deben tener acceso a
la carpeta. Limite el número de administradores de seguridad que tienen acceso para
auditar las transcripciones.
Unidad de usuario
Si los usuarios que se conectan necesitan copiar archivos desde o al punto de conexión
de JEA, puede habilitar la unidad de usuario en el archivo de configuración de sesión. La
unidad de usuario es un PSDrive asignado a una carpeta única para cada usuario que se
conecta. Esta carpeta permite a los usuarios copiar archivos en o desde el sistema, sin
concederles acceso al sistema de archivos completo ni exponer el proveedor FileSystem.
El contenido de la unidad de usuario es persistente en todas las sesiones para adaptarse
a situaciones en que se podría interrumpir la conectividad de red.

PowerShell

MountUserDrive = $true

De manera predeterminada, la unidad de usuario le permite almacenar un máximo de


50 MB de datos por usuario. Puede limitar la cantidad de datos que puede consumir un
usuario con el campo UserDriveMaximumSize.

PowerShell

# Enables the user drive with a per-user limit of 500MB (524288000 bytes)
MountUserDrive = $true
UserDriveMaximumSize = 524288000

Si no quiere que los datos de la unidad de usuario sean persistentes, puede configurar
una tarea programada en el sistema para limpiar la carpeta de forma automática cada
noche.

7 Nota

La unidad de usuario solo está disponible en PowerShell 5.1 o una versión


posterior.

Para obtener más información sobre unidades de PowerShell, vea Administración de


unidades de PowerShell.

Definiciones de roles
Las definiciones de roles en un archivo de configuración de sesión definen la asignación
de usuarios a roles. A todos los usuarios o grupos incluidos en este campo se les asigna
permiso al punto de conexión de JEA cuando se registra. Cada usuario o grupo puede
incluirse como una clave en la tabla hash solo una vez, pero se le pueden asignar varios
roles. El nombre de la funcionalidad de rol debe ser el nombre del archivo de
funcionalidad de rol, sin la extensión .psrc .

PowerShell

RoleDefinitions = @{
'CONTOSO\JEA_DNS_ADMINS' = @{ RoleCapabilities = 'DnsAdmin',
'DnsOperator', 'DnsAuditor' }
'CONTOSO\JEA_DNS_OPERATORS' = @{ RoleCapabilities = 'DnsOperator',
'DnsAuditor' }
'CONTOSO\JEA_DNS_AUDITORS' = @{ RoleCapabilities = 'DnsAuditor' }
}

Si un usuario pertenece a más de un grupo en la definición de rol, obtiene acceso a los


roles de cada uno. Si dos roles conceden acceso a los mismos cmdlets, se concede al
usuario el conjunto de parámetros más permisivo.

Al especificar usuarios o grupos locales en el campo de definiciones de rol, asegúrese de


usar el nombre del equipo, no localhost ni comodines. Puede comprobar el nombre del
equipo observando la variable $env:COMPUTERNAME .

PowerShell

RoleDefinitions = @{
'MyComputerName\MyLocalGroup' = @{ RoleCapabilities = 'DnsAuditor' }
}

Orden de búsqueda de funcionalidad de rol


Como se ha mostrado en el ejemplo anterior, el nombre base del archivo de
funcionalidad de rol hace referencia a las funcionalidades de rol. El nombre base de un
archivo es el nombre de archivo sin la extensión. Si hay varias funcionalidades de rol
disponibles en el sistema con el mismo nombre, PowerShell usa su orden de búsqueda
implícito para seleccionar el archivo de funcionalidad de rol efectivo. JEA no
proporciona acceso a todos los archivos de funcionalidad de rol con el mismo nombre.

JEA utiliza la variable de entorno $env:PSModulePath para determinar qué rutas de


acceso examinar para archivos de capacidad de rol. Dentro de cada una de esas rutas de
acceso, JEA busca módulos de PowerShell válidos que contengan una subcarpeta
"RoleCapabilities". Al igual que con la importación de módulos, JEA prefiere
funcionalidades de rol que se suministran con Windows a capacidades de rol
personalizadas con el mismo nombre.
Para todos los demás conflictos de nomenclatura, la precedencia se determina por el
orden en el que Windows enumera los archivos en el directorio. No se garantiza que el
orden sea alfabético. Para el usuario que se conecta se usa el primer archivo de
funcionalidad de rol que coincide con el nombre especificado. Como el orden de
búsqueda de funcionalidad de rol no es determinista, se recomienda encarecidamente
que las funcionalidades de rol tengan nombres de archivo únicos.

Reglas de acceso condicional


De forma automática, se concede acceso a los puntos de conexión de JEA a todos los
usuarios y grupos incluidos en el campo RoleDefinitions. Las reglas de acceso
condicional permiten ajustar este acceso y requieren que los usuarios pertenezcan a
grupos de seguridad adicionales que no afecten a los roles a los que están asignados.
Esto es útil cuando se quiere integrar una solución de administración de acceso con
privilegios "Just-In-Time", autenticación de tarjeta inteligente u otra solución de
autenticación multifactor con JEA.

Las reglas de acceso condicional se definen en el campo RequiredGroups en un archivo


de configuración de sesión. En él, puede proporcionar una tabla hash (opcionalmente
anidada) que use las claves "And" y "Or" para construir las reglas. Estos son algunos
ejemplos sobre cómo usar este campo:

PowerShell

# Example 1: Connecting users must belong to a security group called


"elevated-jea"
RequiredGroups = @{ And = 'elevated-jea' }

# Example 2: Connecting users must have signed on with 2 factor


authentication or a smart card
# The 2 factor authentication group name is "2FA-logon" and the smart card
group
# name is "smartcard-logon"
RequiredGroups = @{ Or = '2FA-logon', 'smartcard-logon' }

# Example 3: Connecting users must elevate into "elevated-jea" with their


JIT system and
# have logged on with 2FA or a smart card
RequiredGroups = @{ And = 'elevated-jea', @{ Or = '2FA-logon', 'smartcard-
logon' }}

7 Nota

Las reglas de acceso condicional solo están disponibles en PowerShell 5.1 o


versiones posteriores.
Otras propiedades
Los archivos de configuración de sesión también pueden hacer lo mismo que un archivo
de funcionalidad de rol, pero sin la capacidad de proporcionar acceso a los usuarios que
se conectan a distintos comandos. Si quiere permitir que todos los usuarios obtengan
acceso a cmdlets, funciones o proveedores específicos, puede hacerlo directamente en
el archivo de configuración de sesión. Para obtener una lista completa de las
propiedades que se admiten en el archivo de configuración de sesión, ejecute Get-Help
New-PSSessionConfigurationFile -Full .

Probar un archivo de configuración de sesión


Puede probar una configuración de sesión con el cmdlet Test-
PSSessionConfigurationFile. Se recomienda probar el archivo de configuración de sesión
si se ha editado manualmente el archivo .pssc . Las pruebas garantizan que la sintaxis
sea correcta. Si un archivo de configuración de sesión no supera esta prueba, no se
puede registrar en el sistema.

Archivo de configuración de sesión de ejemplo


En el ejemplo siguiente se muestra cómo crear y validar una configuración de sesión
para JEA. Para que resulte cómodo y legible, las definiciones de roles se crean y
almacenan en la variable $roles . no es un requisito para hacerlo.

PowerShell

$roles = @{
'CONTOSO\JEA_DNS_ADMINS' = @{ RoleCapabilities = 'DnsAdmin',
'DnsOperator', 'DnsAuditor' }
'CONTOSO\JEA_DNS_OPERATORS' = @{ RoleCapabilities = 'DnsOperator',
'DnsAuditor' }
'CONTOSO\JEA_DNS_AUDITORS' = @{ RoleCapabilities = 'DnsAuditor' }
}

$parameters = @{
SessionType = 'RestrictedRemoteServer'
Path = '.\JEAConfig.pssc'
RunAsVirtualAccount = $true
TranscriptDirectory = 'C:\ProgramData\JEAConfiguration\Transcripts'
RoleDefinitions = $roles
RequiredGroups = @{ Or = '2FA-logon', 'smartcard-logon' }
}
New-PSSessionConfigurationFile @parameters
Test-PSSessionConfigurationFile -Path .\JEAConfig.pssc # should yield True

Actualizar los archivos de configuración de


sesión
Para cambiar las propiedades de una configuración de sesión de JEA, incluida la
asignación de usuarios a los roles, debe anular el registro. Después, vuelva a registrar la
configuración de sesión JEA mediante un archivo de configuración de sesión
actualizado.

Pasos siguientes
Registrar una configuración de JEA
Crear roles de JEA
Registro de configuraciones de JEA
Artículo • 13/04/2023

Una vez que ha creado las funcionalidades de rol y el archivo de configuración de


sesión, el último paso consiste en registrar el punto de conexión de JEA. El registro del
punto de conexión de JEA en el sistema pone a disposición el punto de conexión para
que lo usen los motores de automatización y los usuarios.

Configuración de la máquina sencilla


Para entornos pequeños, puede implementar JEA al registrar el archivo de configuración
de sesión mediante el cmdlet Register-PSSessionConfiguration.

Antes de comenzar, asegúrese de que se cumplen los requisitos previos siguientes:

Se han creado uno o varios roles, y se han colocado en la carpeta RoleCapabilities


de un módulo de PowerShell.
Se ha creado y probado un archivo de configuración de sesión.
El usuario que registra la configuración de JEA tiene derechos de administrador en
el sistema.
Ha seleccionado un nombre para el punto de conexión de JEA.

El nombre del punto de conexión de JEA es obligatorio cuando los usuarios se conectan
al sistema mediante JEA. El cmdlet Get-PSSessionConfiguration enumera los nombres
de los puntos de conexión de un sistema. Los puntos de conexión que empiezan por
microsoft normalmente se entregan con Windows. El punto de conexión
microsoft.powershell es el que se usa de manera predeterminada al conectarse a un

punto de conexión remoto de PowerShell.

PowerShell

Get-PSSessionConfiguration | Select-Object Name

Output

Name
----
microsoft.powershell
microsoft.powershell.workflow
microsoft.powershell32

Ejecute el comando siguiente para registrar el punto de conexión.


PowerShell

Register-PSSessionConfiguration -Path .\MyJEAConfig.pssc -Name


'JEAMaintenance' -Force

2 Advertencia

El comando anterior reinicia el servicio WinRM en el sistema. Esto finaliza todas las
sesiones de comunicación remota de PowerShell y todas las configuraciones de
DSC en curso. Se recomienda desconectar las máquinas de producción antes de
ejecutar el comando para evitar interrumpir las operaciones empresariales.

Después del registro, estará listo para usar JEA. Puede eliminar el archivo de
configuración de sesión en cualquier momento. El archivo de configuración no se usa
después del registro del punto de conexión.

Configuración de varios equipos con DSC


Al implementar JEA en varios equipos, el modelo de implementación más sencillo usa el
recurso de configuración de estado deseado (DSC) de JEA para implementar JEA en
todos los equipos de forma rápida y coherente.

Para implementar JEA con DSC, asegúrese de que se cumplen los requisitos previos
siguientes:

Se han creado una o varias funcionalidades de rol y se han agregado a un módulo


de PowerShell.
El módulo de PowerShell que contiene los roles se almacena en un recurso
compartido de archivo (de solo lectura) al que pueden obtener acceso todos los
equipos.
Se ha determinado la configuración de la sesión. No es necesario crear un archivo
de configuración de sesión cuando se usa el recurso DSC de JEA.
Tiene credenciales que le permiten realizar acciones administrativas en todos los
equipos, o bien tiene acceso al servidor de extracción de DSC que se usa para
administrar los equipos.
Ha descargado el recurso de DSC de JEA .

Cree una configuración de DSC para el punto de conexión de JEA en un equipo de


destino o servidor de extracción. En esta configuración, el recurso de DSC
JustEnoughAdministration define el archivo de configuración de sesión y el recurso File
copia las funcionalidades de rol desde el recurso compartido de archivos.
Se pueden configurar las siguientes propiedades con el recurso de DSC:

Definiciones de roles
Grupos de cuenta virtual
Nombre de cuenta de servicio administrada de grupo
Directorio de transcripciones
Unidad de usuario
Reglas de acceso condicional
Scripts de inicio de la sesión de JEA

La sintaxis de cada una de estas propiedades en una configuración de DSC es coherente


con el archivo de configuración de sesión de PowerShell.

A continuación se muestra un ejemplo de configuración de DSC de un módulo de


mantenimiento general del servidor. Supone que un módulo de PowerShell válido que
contiene las funcionalidades de rol se encuentra en el recurso compartido de archivos
\\myfileshare\JEA .

PowerShell

Configuration JEAMaintenance
{
Import-DscResource -Module JustEnoughAdministration,
PSDesiredStateConfiguration

File MaintenanceModule
{
SourcePath = "\\myfileshare\JEA\ContosoMaintenance"
DestinationPath = "C:\Program
Files\WindowsPowerShell\Modules\ContosoMaintenance"
Checksum = "SHA-256"
Ensure = "Present"
Type = "Directory"
Recurse = $true
}

JeaEndpoint JEAMaintenanceEndpoint
{
EndpointName = "JEAMaintenance"
RoleDefinitions = "@{ 'CONTOSO\JEAMaintenanceAuditors' = @{
RoleCapabilities = 'GeneralServerMaintenance-Audit' };
'CONTOSO\JEAMaintenanceAdmins' = @{ RoleCapabilities =
'GeneralServerMaintenance-Audit', 'GeneralServerMaintenance-Admin' } }"
TranscriptDirectory = 'C:\ProgramData\JEAConfiguration\Transcripts'
DependsOn = '[File]MaintenanceModule'
}
}
Después, esta configuración se aplica en un sistema mediante la invocación directa del
administrador de configuración local o la actualización de la configuración del servidor
de extracción.

El recurso de DSC también permite reemplazar el punto de conexión de


Microsoft.PowerShell predeterminado. Cuando se reemplaza, el recurso registra de
forma automática un punto de conexión de reserva denominado
Microsoft.PowerShell.Restricted. El punto de conexión de reserva tiene la ACL de
WinRM predeterminada que permite el acceso a los miembros del grupo Usuarios de
administración remota y Administradores local.

Anular el registro de configuraciones de JEA


El cmdlet Unregister-PSSessionConfiguration quita un punto de conexión de JEA. Si
anula el registro de un punto de conexión de JEA, evitará que nuevos usuarios creen
sesiones de JEA en el sistema. También permite actualizar una configuración de JEA al
volver a registrar un archivo de configuración de sesión actualizado con el mismo
nombre de punto de conexión.

PowerShell

# Unregister the JEA endpoint called "ContosoMaintenance"


Unregister-PSSessionConfiguration -Name 'ContosoMaintenance' -Force

2 Advertencia

Anular el registro de un punto de conexión de JEA provocará que se reinicie el


servicio WinRM. Esto interrumpe la mayoría de las operaciones de administración
remotas en curso, incluidas otras sesiones de PowerShell, invocaciones de WMI y
algunas herramientas de administración. Anule el registro de puntos de conexión
de PowerShell solo durante ventanas de mantenimiento planificadas.

Pasos siguientes
Probar el punto de conexión de JEA
Uso de JEA
Artículo • 13/04/2023

En este artículo se describen las distintas formas de poder conectarse a un punto de


conexión de JEA y usarlo.

Usar JEA de forma interactiva


Si va a probar la configuración de JEA o tiene tareas sencillas para los usuarios, puede
usar JEA como haría con una sesión normal de comunicación remota de PowerShell.
Para las tareas complejas de comunicación remota, se recomienda usar la comunicación
remota implícita. La comunicación remota implícita permite a los usuarios trabajar con
los objetos de datos de forma local.

Para usar JEA de forma interactiva, necesita lo siguiente:

El nombre del equipo al que se va a conectar (puede ser el equipo local)


El nombre del punto de conexión de JEA registrado en ese equipo
Credenciales que tienen acceso al punto de conexión de JEA en ese equipo

Con esa información, puede iniciar una sesión de JEA con los cmdlets New-PSSession o
Enter-PSSession.

PowerShell

$sessionParams = @{
ComputerName = 'localhost'
ConfigurationName = 'JEAMaintenance'
Credential = Get-Credential
}
Enter-PSSession @sessionParams

Si la cuenta de usuario actual tiene acceso al punto de conexión de JEA, puede omitir el
parámetro Credential.

Cuando el mensaje de PowerShell cambie a [localhost]: PS> , sabe que ahora va a


interactuar con la sesión remota de JEA. Puede ejecutar Get-Command para comprobar
qué comandos están disponibles. Consulte con el administrador para saber si hay
alguna restricción en los parámetros disponibles o los valores de parámetro permitidos.

Recuerde que las sesiones de JEA funcionan en NoLanguage modo. Es posible que
algunas de las formas en las que suele usar PowerShell no estén disponibles. Por
ejemplo, no puede usar variables para almacenar datos ni inspeccionar las propiedades
en los objetos que devuelven los cmdlets. En el ejemplo siguiente se muestran dos
enfoques para que los mismos comandos funcionen en NoLanguage modo.

PowerShell

# Using variables is prohibited in NoLanguage mode. The following will not


work:
# $vm = Get-VM -Name 'SQL01'
# Start-VM -VM $vm

# You can use pipes to pass data through to commands that accept input from
the pipeline
Get-VM -Name 'SQL01' | Start-VM

# You can also wrap subcommands in parentheses and enter them inline as
arguments
Start-VM -VM (Get-VM -Name 'SQL01')

# You can also use parameter sets that don't require extra data to be passed
in
Start-VM -VMName 'SQL01'

Para invocaciones de comandos más complejos que dificultan este enfoque, le


recomendamos usar la comunicación remota implícita o la creación de funciones
personalizadas que encapsulen la funcionalidad que necesita. Para obtener más
información sobre NoLanguageMode , vea about_Language_Modes.

Uso de JEA con comunicación remota implícita


PowerShell dispone de un modelo de comunicación remota implícita que permite
importar cmdlets de proxy desde un equipo remoto e interactuar con ellos como si
fueran comandos locales. La comunicación remota implícita se explica en esta hey,
Scripting Guy!entrada de blog . La comunicación remota implícita es útil cuando se
trabaja con JEA porque permite trabajar con los cmdlets de JEA en un modo de lenguaje
completo. Puede usar finalización con tabulación, variables, manipular objetos e incluso
usar scripts locales para automatizar las tareas para un punto de conexión de JEA.
Siempre que se invoca un comando de proxy, los datos se envían al punto de conexión
de JEA en el equipo remoto y se ejecutan allí.

La comunicación remota implícita funciona mediante la importación de cmdlets de una


sesión de PowerShell existente. Puede optar por agregar la cadena que elija como
prefijo en los nombres de cada cmdlet de proxy. El prefijo permite distinguir qué
comandos son para el sistema remoto. Se crea un módulo de script temporal que
contiene todos los comandos de proxy y se importa durante la sesión local de
PowerShell.

PowerShell

# Create a new PSSession to your JEA endpoint


$jeaSession = New-PSSession -ComputerName 'SERVER01' -ConfigurationName
'JEAMaintenance'

# Import the entire PSSession and prefix each imported cmdlet with "JEA"
Import-PSSession -Session $jeaSession -Prefix 'JEA'

# Invoke "Get-Command" on the remote JEA endpoint using the proxy cmdlet
Get-JEACommand

) Importante

Es posible que algunos sistemas no puedan importar toda la sesión de JEA debido
a restricciones en los cmdlets de JEA predeterminados. Para solucionar esto,
importe solo los comandos que necesita de la sesión de JEA al proporcionar sus
nombres de forma explícita en el parámetro -CommandName . Una actualización futura
abordará el problema de importación de sesiones de JEA completas en los sistemas
afectados.

Si no puede importar una sesión de JEA debido a las restricciones de JEA sobre los
parámetros predeterminados, siga los pasos siguientes para filtrar los comandos
predeterminados del conjunto importado. Todavía puede usar comandos como Select-
Object , pero solo la versión local instalada en el equipo en lugar de la que se ha

importado desde la sesión remota de JEA.

PowerShell

# Create a new PSSession to your JEA endpoint


$jeaSession = New-PSSession -ComputerName 'SERVER01' -ConfigurationName
'JEAMaintenance'

# Get a list of all the commands on the JEA endpoint


$commands = Invoke-Command -Session $jeaSession -ScriptBlock { Get-Command }

# Filter out the default cmdlets


$jeaDefaultCmdlets = @(
'Clear-Host'
'Exit-PSSession'
'Get-Command'
'Get-FormatData'
'Get-Help'
'Measure-Object'
'Out-Default'
'Select-Object'
)
$filteredCommands = $commands.Name | Where-Object { $jeaDefaultCmdlets -
notcontains $_ }

# Import only commands explicitly added in role capabilities and prefix each
# imported cmdlet with "JEA"
Import-PSSession -Session $jeaSession -Prefix 'JEA' -CommandName
$filteredCommands

También puede conservar los cmdlets de proxy de comunicación remota implícita


mediante Export-PSSession. Para obtener más información sobre la comunicación
remota implícita, vea la documentación de Import-PSSession e Import-Module.

Usar JEA mediante programación


JEA también se puede usar en sistemas de automatización y en aplicaciones de usuario,
como sitios web y aplicaciones de soporte técnico internos. El enfoque es el mismo que
para crear aplicaciones que se comunican con puntos de conexión de PowerShell sin
restricciones. Asegúrese de que el programa está diseñado para funcionar con la
limitación impuesta por JEA.

Para tareas simples y de uso único, puede usar Invoke-Command para ejecutar
comandos en una sesión de JEA.

PowerShell

Invoke-Command -ComputerName 'SERVER01' -ConfigurationName 'JEAMaintenance'


-ScriptBlock {
Get-Process
Get-Service
}

Para comprobar qué comandos están disponibles para su uso cuando se conecta a una
sesión de JEA, ejecute Get-Command e itere los resultados para comprobar los parámetros
permitidos.

PowerShell

$commandParameters = @{
ComputerName = 'SERVER01'
ConfigurationName = 'JEAMaintenance'
ScriptBlock = { Get-Command }
}
Invoke-Command @commandParameters |
Where-Object { $_.CommandType -in @('Function', 'Cmdlet') } |
Format-Table Name, Parameters

Si va a compilar una aplicación de C#, puede crear un espacio de ejecución de


PowerShell que se conecte a una sesión de JEA si especifica el nombre de la
configuración de un objeto WSManConnectionInfo.

C#

// using System.Management.Automation;
var computerName = "SERVER01";
var configName = "JEAMaintenance";
// See
https://learn.microsoft.com/dotnet/api/system.management.automation.pscreden
tial
var creds = // create a PSCredential object here

WSManConnectionInfo connectionInfo = new WSManConnectionInfo(


false, // Use SSL
computerName, // Computer name
5985, // WSMan Port
"/wsman", // WSMan Path
// Connection URI with config name
string.Format(
CultureInfo.InvariantCulture,
"http://schemas.microsoft.com/powershell/{0}",
configName
),
creds // Credentials
);

// Now, use the connection info to create a runspace where you can run the
commands
using (Runspace runspace = RunspaceFactory.CreateRunspace(connectionInfo))
{
// Open the runspace
runspace.Open();

using (PowerShell ps = PowerShell.Create())


{
// Set the PowerShell object to use the JEA runspace
ps.Runspace = runspace;

// Now you can add and invoke commands


ps.AddCommand("Get-Command");
foreach (var result in ps.Invoke())
{
Console.WriteLine(result);
}
}
// Close the runspace
runspace.Close();
}

Usar JEA con PowerShell Direct


Hyper-V en Windows 10 y Windows Server 2016 ofrece PowerShell Direct, una
característica que permite a los administradores de Hyper-V administrar máquinas
virtuales con PowerShell, con independencia de la configuración de red o de
administración remota de la máquina virtual.

Puede usar PowerShell Direct con JEA para proporcionar a un administrador de Hyper-V
acceso limitado a la máquina virtual. Esto puede ser útil si pierde la conectividad de red
a la máquina virtual y necesita un administrador de centro de datos para corregir la
configuración de red.

No se requiere ninguna configuración adicional para usar JEA en PowerShell Direct. Pero
el sistema operativo invitado que se ejecuta dentro de la máquina virtual debe ser
Windows 10, Windows Server 2016 o una versión posterior. El administrador de Hyper-V
puede conectarse al punto de conexión de JEA mediante los parámetros -VMName o -
VMId en los cmdlets de PSRemoting:

PowerShell

$sharedParams = @{
ConfigurationName = 'NICMaintenance'
Credential = Get-Credential -UserName 'localhost\JEAformyHoster'
}
# Entering a JEA session using PowerShell Direct when the VM name is unique
Enter-PSSession -VMName 'SQL01' @sharedParams

# Entering a JEA session using PowerShell Direct using VM ids


$vm = Get-VM -VMName 'MyVM' | Select-Object -First 1
Enter-PSSession -VMId $vm.VMId @sharedParams

Se recomienda crear una cuenta de usuario dedicada con los derechos mínimos
necesarios para administrar el sistema para uso por parte de un administrador de
Hyper-V. Recuerde que incluso un usuario sin privilegios puede iniciar sesión en una
máquina de Windows de manera predeterminada, incluido con PowerShell sin
restricciones. Eso le permite examinar el sistema de archivos y obtener más información
sobre el entorno del sistema operativo. Para bloquear a un administrador de Hyper-V y
limitar su acceso a una máquina virtual solo mediante PowerShell Direct con JEA, tendrá
que denegar los derechos de inicio de sesión local a la cuenta de JEA del administrador
de Hyper-V.
Consideraciones de seguridad de JEA
Artículo • 17/10/2023

JEA le ayuda a mejorar su posición en materia de seguridad, ya que reduce el número


de administradores permanentes de sus equipos. En JEA se usa una configuración de
sesión de PowerShell para crear un punto de entrada con el fin de que los usuarios
administren el sistema. A los usuarios que necesiten acceso con privilegios elevados,
pero no ilimitado, al equipo para realizar tareas administrativas se les puede conceder
acceso al punto de conexión de JEA. Puesto que JEA permite a estos usuarios ejecutar
comandos administrativos sin tener acceso de administrador completo, puede quitar
esos usuarios de grupos de seguridad con privilegios elevados.

Cuenta de ejecución
Cada punto de conexión de JEA tiene una cuenta de ejecución designada con la que se
ejecutan las acciones del usuario que se conecta. Esta cuenta se puede configurar en el
archivo de configuración de sesión, y la cuenta que elija influye de forma significativa en
la seguridad del punto de conexión.

Las cuentas virtuales son la forma recomendada de configurar la cuenta de ejecución.


Las cuentas virtuales son cuentas locales únicas y temporales creadas por el usuario que
se conecta para usarlas durante la sesión de JEA. Una vez finalizada la sesión, la cuenta
virtual se destruye y ya no se puede volver a usar. El usuario que se conecta desconoce
las credenciales de la cuenta virtual. La cuenta virtual no se puede usar para acceder al
sistema a través de otros medios como Escritorio remoto o un punto de conexión de
PowerShell sin restricciones.

De forma predeterminada, las cuentas virtuales son miembros del grupo local de
Administración istrators en la máquina. Esta pertenencia les da derechos completos
para administrar cualquier cosa en el sistema, pero no tiene derechos para administrar
recursos en la red. Cuando el usuario se conecta a otras máquinas desde la sesión de
JEA, el contexto de usuario es el de la cuenta de equipo local, no la cuenta virtual.

Los controladores de dominio son un caso especial ya que no hay ningún grupo de
administradores local. En su lugar, las cuentas virtuales pertenecen a Administradores
de dominio y pueden administrar los servicios de directorio en el controlador de
dominio. La identidad de dominio sigue estando restringida para su uso en el
controlador de dominio donde se ha creado la instancia de la sesión de JEA. En su lugar,
cualquier acceso de red parece proceder del objeto de equipo de controlador de
dominio.
En ambos casos, puede asignar la cuenta virtual a grupos de seguridad específicos,
especialmente cuando la tarea se puede realizar sin privilegios de administrador de
dominio o local. Si ya tiene un grupo de seguridad definido para los administradores,
conceda la pertenencia a la cuenta virtual a ese grupo. La pertenencia a grupos para
cuentas virtuales está limitada a grupos de seguridad locales en servidores miembros y
estaciones de trabajo. En los controladores de dominio, las cuentas virtuales deben ser
miembros de grupos de seguridad de dominio. Una vez agregada la cuenta virtual a
uno o varios grupos de seguridad, ya no pertenece a los grupos predeterminados
(administradores de dominio o locales).

En la tabla siguiente se resumen las posibles opciones de configuración y los permisos


resultantes de las cuentas virtuales:

Tipo de equipo Configuración del Contexto de usuario local Contexto de


grupo de cuenta usuario de
virtual red

Controlador de Valor predeterminado Usuario de dominio, miembro Cuenta de


dominio de <DOMAIN>\Domain Admins equipo

Controlador de Grupos de dominio A y Usuario de dominio, miembro Cuenta de


dominio B de <DOMAIN>\A , <DOMAIN>\B equipo

Servidor miembro Valor predeterminado Usuario local, miembro de Cuenta de


o estación de BUILTIN\Administrators equipo
trabajo

Servidor miembro Grupos locales C y D Usuario local, miembro de Cuenta de


o estación de <COMPUTER>\C y <COMPUTER>\D equipo
trabajo

Al examinar los registros de eventos de auditoría de seguridad y aplicación, verá que


cada sesión de usuario de JEA tiene una cuenta virtual única. Esta cuenta única ayuda a
realizar el seguimiento de las acciones del usuario en un punto de conexión de JEA
hasta el usuario original que ha ejecutado el comando. Los nombres de cuenta virtual
siguen el formato WinRM Virtual
Users\WinRM_VA_<ACCOUNTNUMBER>_<DOMAIN>_<sAMAccountName> . Por ejemplo, si el usuario

Alice del dominio Contoso reinicia un servicio en un punto de conexión de JEA, el


nombre de usuario asociado con todos los eventos del administrador de control de
servicio sería WinRM Virtual Users\WinRM_VA_1_contoso_alice .

Las cuentas de servicio administradas de grupo (gMSA) son útiles cuando un servidor
miembro necesita tener acceso a recursos de red en la sesión de JEA. Por ejemplo,
cuando se usa un punto de conexión de JEA para controlar el acceso a una API REST
hospedada en otro equipo. Es fácil escribir funciones para invocar las API REST, pero se
necesita una identidad de red para autenticarse con la API. El uso de una cuenta de
servicio administrada de grupo posibilita el segundo salto, mientras se conserva el
control sobre los equipos que pueden usar la cuenta. Las pertenencias a grupos de
seguridad (locales o de dominio) de la gMSA definieron los permisos efectivos para la
cuenta de gMSA.

Cuando un punto de conexión de JEA se configura para usar una cuenta gMSA, parece
que las acciones de todos los usuarios de JEA provienen de la misma gMSA. La única
manera de realizar el seguimiento de las acciones hasta un usuario específico consiste
en identificar el conjunto de comandos que se ejecutan en una transcripción de la
sesión de PowerShell.

Las credenciales de paso a través se usan cuando no se especifica una cuenta de


ejecución . PowerShell usa las credenciales del usuario que se conecta para ejecutar
comandos en el servidor remoto. Para usar credenciales de paso a través, debe conceder
al usuario que conecta el acceso directo a los grupos de administración con privilegios.
Esta configuración NO se recomienda para JEA. Si el usuario que se conecta ya tiene
privilegios de administrador, puede omitir JEA y administrar el sistema mediante otros
métodos de acceso.

Las cuentas de ejecución estándar permiten especificar cualquier cuenta de usuario


bajo la que se ejecuta toda la sesión de PowerShell. Las configuraciones de sesión en las
que se usan cuentas de ejecución fijas (con el parámetro -RunAsCredential ) no son
compatibles con JEA. Las definiciones de roles ya no funcionan según lo previsto. A
todos los usuarios autorizados para acceder al punto de conexión se les asigna el
mismo rol.

No se debe usar un elemento RunAsCredential en un punto de conexión de JEA, ya que


dificulta el seguimiento de las acciones hasta usuarios específicos y carece de
compatibilidad para asignar usuarios a roles.

ACL de punto de conexión de WinRM


Como sucede con los puntos de conexión de comunicación remota de PowerShell
normales, cada punto de conexión de JEA tiene una lista de control de acceso (ACL)
independiente que controla quién se puede autenticar con el punto de conexión de JEA.
Si no está configurado correctamente, es posible que los usuarios de confianza no
puedan acceder al punto de conexión de JEA y es posible que los usuarios que no sean
de confianza tengan acceso. La ACL de WinRM no afecta a la asignación de usuarios a
roles de JEA. La asignación se controla mediante el campo RoleDefinitions del archivo
de configuración de sesión que se ha usado para registrar el punto de conexión.
De forma predeterminada, cuando un punto de conexión de JEA tiene varias
funcionalidades de rol, la ACL de WinRM se configura para permitir el acceso a todos los
usuarios asignados. Por ejemplo, una sesión de JEA configurada con los comandos
siguientes concede acceso total a CONTOSO\JEA_Lev1 y CONTOSO\JEA_Lev2 .

PowerShell

$roles = @{ 'CONTOSO\JEA_Lev1' = 'Lev1Role'; 'CONTOSO\JEA_Lev2' = 'Lev2Role'


}
New-PSSessionConfigurationFile -Path '.\jea.pssc' -SessionType
RestrictedRemoteServer -RoleDefinitions $roles -RunAsVirtualAccount
Register-PSSessionConfiguration -Path '.\jea.pssc' -Name 'MyJEAEndpoint'

Puede auditar los permisos de usuario con el cmdlet Get-PSSessionConfiguration.

PowerShell

Get-PSSessionConfiguration -Name 'MyJEAEndpoint' | Select-Object Permission

Output

Permission
----------
CONTOSO\JEA_Lev1 AccessAllowed
CONTOSO\JEA_Lev2 AccessAllowed

Para cambiar los usuarios que tienen acceso, ejecute Set-PSSessionConfiguration -Name
'MyJEAEndpoint' -ShowSecurityDescriptorUI para obtener un aviso interactivo o Set-

PSSessionConfiguration -Name 'MyJEAEndpoint' -SecurityDescriptorSddl <SDDL string>

para actualizar los permisos. Los usuarios necesitan al menos derechos de invocación
para tener acceso al punto de conexión de JEA.

Es posible crear un punto de conexión de JEA que no asigne un rol definido a todos los
usuarios que tienen acceso. Estos usuarios pueden iniciar una sesión de JEA, pero solo
tienen acceso a los cmdlets predeterminados. Puede auditar los permisos de usuario en
un punto de conexión de JEA ejecutando Get-PSSessionCapability . Para obtener más
información, vea Auditoría y creación de informes en JEA.

Roles con privilegios mínimos


Al diseñar roles de JEA, es importante recordar que la cuenta de servicio administrada
de grupo y la cuenta virtual que se ejecutan en segundo plano pueden tener acceso sin
restricciones al equipo local. Las funcionalidades de rol de JEA ayudan a limitar los
comandos y las aplicaciones que se pueden ejecutar en ese contexto con privilegios. Los
roles diseñados de manera incorrecta pueden permitir comandos peligrosos que
autoricen a un usuario a salir de los límites de JEA u obtener acceso a información
confidencial.

Por ejemplo, observe la siguiente entrada de funcionalidad de rol:

PowerShell

@{
VisibleCmdlets = 'Microsoft.PowerShell.Management\*-Process'
}

Esta funcionalidad de rol permite a los usuarios ejecutar cualquier cmdlet de PowerShell
con el nombre Process del módulo Microsoft.PowerShell.Management. Es posible que
los usuarios necesiten acceder a cmdlets como Get-Process para ver qué aplicaciones se
ejecutan en el sistema y Stop-Process para eliminar cualquier aplicación que no
responda. En cambio, esta entrada también permite Start-Process , que se puede usar
para iniciar un programa arbitrario con permisos de administrador total. No es necesario
instalar el programa de forma local en el sistema. Un usuario conectado podría iniciar un
programa desde un recurso compartido de archivos que proporcione a los usuarios
privilegios de administrador local, ejecuta malware y mucho más.

Una versión más segura de esta misma funcionalidad de rol tendría el siguiente aspecto:

PowerShell

@{
VisibleCmdlets = 'Microsoft.PowerShell.Management\Get-Process',
'Microsoft.PowerShell.Management\Stop-Process'
}

Evite usar caracteres comodín en las funcionalidades de rol. Asegúrese de auditar


periódicamente los permisos de usuario efectivos para ver qué comandos son accesibles
para un usuario. Para obtener más información, consulte la sección Comprobar derechos
efectivos del artículo Auditoría e informes sobre JEA .

Mejores prácticas recomendadas


A continuación se muestran recomendaciones de procedimientos recomendados para
garantizar la seguridad de los puntos de conexión de JEA:
Limitar el uso y las funcionalidades de los proveedores de
PowerShell
Revise cómo se usan los proveedores permitidos para asegurarse de que no cree
vulnerabilidades en la sesión configurada.

2 Advertencia

No permita el proveedor FileSystem . Si los usuarios pueden escribir en cualquier


parte del sistema de archivos, es posible omitir completamente la seguridad.

No permita el proveedor de certificados . Con el proveedor habilitado, un usuario


podría obtener acceso a las claves privadas almacenadas.

No permita comandos que puedan crear nuevos espacios


de ejecución.

2 Advertencia

Los *-Job cmdlets pueden crear nuevos espacios de ejecución sin restricciones.

No permita el Trace-Command cmdlet.

2 Advertencia

El uso Trace-Command de trae todos los comandos de seguimiento a la sesión.

No cree sus propias implementaciones de proxy para los


comandos restringidos.
PowerShell tiene un conjunto de comandos de proxy para escenarios de comandos
restringidos. Estos comandos de proxy garantizan que los parámetros de entrada no
puedan poner en peligro la seguridad de la sesión. Los comandos siguientes tienen
servidores proxy restringidos:

Exit-PSSession

Get-Command
Get-FormatData
Get-Help
Measure-Object

Out-Default
Select-Object

Si crea su propia implementación de estos comandos, puede permitir accidentalmente


que los usuarios ejecuten código prohibido por los comandos proxy de JEA.

JEA no protege frente a administradores


Uno de los principios básicos de JEA es que permite a los no administradores realizar
algunas tareas administrativas. JEA no protege frente a los usuarios que ya tienen
privilegios de administrador. Los usuarios que pertenecen a dominios Administración,
Administración istrators locales u otros grupos con privilegios elevados pueden eludir
las protecciones de JEA de otras maneras. Por ejemplo, podrían iniciar sesión con RDP,
usar consolas MMC remotas o conectarse a puntos de conexión de PowerShell sin
restricciones. Además, el administrador local de un sistema puede modificar las
configuraciones de JEA para agregar más usuarios o cambiar una funcionalidad de rol
para ampliar el ámbito de lo que un usuario puede hacer en su sesión de JEA. Es
importante evaluar los permisos extendidos de los usuarios de JEA para ver si hay otras
formas de obtener acceso con privilegios al sistema.

Además de usar JEA para el mantenimiento diario normal, es habitual tener un sistema
de administración de acceso con privilegios Just-In-Time. Estos sistemas permiten a los
usuarios designados convertirse temporalmente en un administrador local solo después
de completar un flujo de trabajo que documente su uso de esos permisos.

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Auditoría y creación de informes en JEA
Artículo • 13/04/2023

Después de haber implementado JEA, tendrá que auditar la configuración de JEA de


forma periódica. La auditoría ayudar a evaluar si los usuarios adecuados tienen acceso al
punto de conexión de JEA y sus roles asignados siguen siendo correctos.

Buscar sesiones de JEA registradas en un


equipo
Para comprobar qué sesiones de JEA están registradas en un equipo, use el cmdlet Get-
PSSessionConfiguration.

PowerShell

# Filter for sessions that are configured as 'RestrictedRemoteServer' to


# find JEA-like session configurations
Get-PSSessionConfiguration | Where-Object { $_.SessionType -eq
'RestrictedRemoteServer' }

Output

Name : JEAMaintenance
PSVersion : 5.1
StartupScript :
RunAsUser :
Permission : CONTOSO\JEA_DNS_ADMINS AccessAllowed,
CONTOSO\JEA_DNS_OPERATORS AccessAllowed,
CONTOSO\JEA_DNS_AUDITORS AccessAllowed

Los derechos efectivos del punto de conexión se muestran en la propiedad Permission.


Estos usuarios tienen derecho a conectarse al punto de conexión de JEA. Pero los roles y
los comandos a los que tienen acceso están determinados por la propiedad
RoleDefinitions del archivo de configuración de sesión que se ha usado para registrar el
punto de conexión. Expanda la propiedad RoleDefinitions para evaluar las asignaciones
de rol en un punto de conexión de JEA registrado.

PowerShell

# Get the desired session configuration


$jea = Get-PSSessionConfiguration -Name 'JEAMaintenance'

# Enumerate users/groups and which roles they have access to


$jea.RoleDefinitions.GetEnumerator() | Select-Object Name, @{
Name = 'Role Capabilities'
Expression = { $_.Value.RoleCapabilities }
}

Buscar funcionalidades de rol disponibles en el


equipo
JEA obtiene las funcionalidades de rol de los archivos .psrc almacenados en la carpeta
RoleCapabilities dentro de un módulo de PowerShell. La función siguiente busca todas
las funcionalidades de rol disponibles en un equipo.

PowerShell

function Find-LocalRoleCapability {
$results = @()

# Find modules with a "RoleCapabilities" subfolder and add any PSRC


files to the result set
Get-Module -ListAvailable | ForEach-Object {
$psrcpath = Join-Path -Path $_.ModuleBase -ChildPath
'RoleCapabilities'
if (Test-Path $psrcpath) {
$results += Get-ChildItem -Path $psrcpath -Filter *.psrc
}
}

# Format the results nicely to make it easier to read


$results | Select-Object @{ Name = 'Name'; Expression = {
$_.Name.TrimEnd('.psrc') }}, @{
Name = 'Path'; Expression = { $_.FullName }
} | Sort-Object Name
}

7 Nota

El orden de los resultados de esta función no es necesariamente el orden en el que


se seleccionarán las funcionalidades de rol si varias funcionalidades de rol
comparten el mismo nombre.

Comprobar los derechos efectivos de un


usuario específico
El cmdlet Get-PSSessionCapability enumera todos los comandos disponibles en un
punto de conexión de JEA en función de las pertenencias a grupos del usuario. La salida
de Get-PSSessionCapability es idéntica a la del usuario especificado que ejecuta Get-
Command -CommandType All en una sesión de JEA.

PowerShell

Get-PSSessionCapability -ConfigurationName 'JEAMaintenance' -Username


'CONTOSO\Alice'

Si los usuarios no son miembros permanentes de grupos que les concederían derechos
adicionales de JEA, es posible que este cmdlet no refleje esos permisos adicionales. Esto
sucede al usar sistemas de administración de acceso con privilegios Just-In-Time para
permitir que los usuarios pertenezcan de forma temporal a un grupo de seguridad.
Evalúe con atención la asignación de usuarios a roles y funcionalidades para garantizar
que los usuarios solo obtienen el nivel de acceso necesario para realizar su trabajo de
forma correcta.

Registros de eventos de PowerShell


Si ha habilitado el registro de bloques de script o de módulo en el sistema, puede ver
eventos en los registros de eventos de Windows para cada comando que ejecute un
usuario en una sesión de JEA. Para buscar estos eventos, abra el registro de eventos
Microsoft-Windows-PowerShell/Operational y busque eventos con el identificador
4104.

En cada entrada del registro de eventos se incluye información sobre la sesión en la que
se ha ejecutado el comando. Para las sesiones de JEA, el evento incluye información
sobre ConnectedUser y RunAsUser. ConnectedUser es el usuario actual que ha creado
la sesión de JEA. RunAsUser es la cuenta de JEA que se ha usado para ejecutar el
comando.

En los registros de eventos de la aplicación se muestran los cambios realizados por


RunAsUser. Por tanto, es necesario tener habilitado el registro de scripts y módulos para
realizar el seguimiento de la invocación de un comando específico hasta
ConnectedUser.

Registros de eventos de la aplicación


Es posible que los comandos que se ejecutan en una sesión de JEA que interactúan con
aplicaciones o servicios externos registren eventos en sus propios registros de eventos.
A diferencia de los registros y las transcripciones de PowerShell, otros mecanismos de
registro no capturan el usuario conectado de la sesión de JEA. En su lugar, esas
aplicaciones solo registran el usuario de ejecución virtual. Para determinar quién ha
ejecutado el comando, tiene que consultar una transcripción de sesión o poner en
correlación los registros de eventos de PowerShell con la hora y el usuario que se
muestran en el registro de eventos de la aplicación.

El registro de WinRM también puede ayudarle a poner en correlación a los usuarios de


ejecución con el usuario que se conecta en un registro de eventos de la aplicación. El
identificador de evento 193 del registro operativo o de Administración remota de
Windows de Microsoft Windows registra el identificador de seguridad (SID) y el
nombre de cuenta del usuario que se conecta y del usuario de ejecución en todas las
sesiones de JEA nuevas.

Transcripciones de sesión
Si ha configurado JEA para crear una transcripción para cada sesión de usuario, se
almacena una copia de texto de las acciones de todos los usuarios en la carpeta
especificada.

El comando siguiente (como administrador) busca todos los directorios de transcripción.

PowerShell

Get-PSSessionConfiguration |
Where-Object { $_.TranscriptDirectory -ne $null } |
Format-Table Name, TranscriptDirectory

Cada transcripción comienza con información sobre la hora en que se ha iniciado la


sesión, qué usuario se ha conectado a la sesión y qué identidad de JEA se le ha
asignado.

**********************
Windows PowerShell transcript start
Start time: 20160710144736
Username: CONTOSO\Alice
RunAs User: WinRM Virtual Users\WinRM VA_1_CONTOSO_Alice
Machine: SERVER01 (Microsoft Windows NT 10.0.14393.0)
[...]

El cuerpo de la transcripción contiene información sobre cada comando que ha


invocado el usuario. La sintaxis exacta del comando que se usa no está disponible en las
sesiones de JEA debido a la manera en que se transforman los comandos para la
comunicación remota de PowerShell. Pero todavía puede determinar el comando real
que se ha ejecutado. A continuación se muestra un fragmento de código de ejemplo de
una transcripción de un usuario que ejecuta Get-Service Dns en una sesión de JEA:

PS>CommandInvocation(Get-Service): "Get-Service"
>> ParameterBinding(Get-Service): name="Name"; value="Dns"
>> CommandInvocation(Out-Default): "Out-Default"
>> ParameterBinding(Out-Default): name="InputObject"; value="Dns"

Running Dns DNS Server

Se escribe una línea CommandInvocation para cada comando que ejecuta un usuario.
En ParameterBindings se registran todos los parámetros y valores proporcionados con
el comando. En el ejemplo anterior, puede ver que al parámetro Name se le ha
proporcionado el valor Dns para el cmdlet Get-Service .

El resultado de cada comando también desencadenará una instancia de


CommandInvocation, normalmente para Out-Default . InputObject de Out-Default es
el objeto de PowerShell que devuelve el comando. Los detalles de ese objeto se
imprimen unas líneas más adelante, imitando detenidamente lo que habría visto el
usuario.

Vea también
Entrada de blog sobre seguridad de PowerShell ♥ the Blue Team
Ejecutar comandos remotos
Artículo • 07/07/2023

Puede ejecutar comandos en un equipo o en cientos de ellos usando un solo comando


de PowerShell. Windows PowerShell admite la computación remota mediante diversas
tecnologías, como WMI, RPC y WS-Management.

PowerShell admite la comunicación remota de WMI, WS-Management y SSH. En


PowerShell 7 y versiones posteriores, RPC solo se admite en Windows.

Para más información sobre la comunicación remota en PowerShell, consulte los


siguientes artículos:

Comunicación remota mediante SSH en PowerShell


Comunicación remota mediante WSMan en PowerShell

Comunicación remota de Windows PowerShell


sin configuración
Muchos de los cmdlets de Windows PowerShell tienen el parámetro ComputerName,
que le permite recopilar datos y cambiar la configuración de uno o más equipos
remotos. Estos cmdlets utilizan diversos protocolos de comunicación y funcionan en
todos los sistemas operativos Windows sin ninguna configuración especial.

Estos cmdlets son:

Restart-Computer
Test-Connection
Clear-EventLog
Get-EventLog
Get-HotFix
Get-Process
Get-Service
Set-Service
Get-WinEvent
Get-WmiObject

Normalmente, los cmdlets que admiten la comunicación remota sin una configuración
especial tienen el parámetro ComputerName y carecen del parámetro Session. Para
encontrar estos cmdlets en la sesión, escriba:
PowerShell

Get-Command | Where-Object {
$_.Parameters.Keys -contains "ComputerName" -and
$_.Parameters.Keys -notcontains "Session"
}

Comunicación remota de Windows PowerShell


Mediante el protocolo WS-Management, la comunicación remota de
Windows PowerShell permite ejecutar cualquier comando de Windows PowerShell en
uno o varios equipos remotos. Puede establecer conexiones persistentes, iniciar
sesiones interactivas y ejecutar scripts en equipos remotos.

Para usar la comunicación remota de Windows PowerShell, el equipo remoto debe estar
configurado para la administración remota. Para más información y ver instrucciones,
consulte About Remote Requirements (Acerca de los requisitos remotos).

Cuando haya configurado la comunicación remota de Windows PowerShell, tendrá a su


disposición un gran número de estrategias de comunicación remota. En este artículo se
enumeran algunos de ellos. Para más información, consulte About Remote (Acerca del
acceso remoto).

Inicio de una sesión interactiva


Para iniciar una sesión interactiva con un único equipo remoto, use el cmdlet Enter-
PSSession. Por ejemplo, para iniciar una sesión interactiva con el equipo remoto
Server01, escriba:

PowerShell

Enter-PSSession Server01

El símbolo del sistema cambia para mostrar el nombre del equipo remoto. Cualquier
comando que escriba en el símbolo del sistema se ejecuta en el equipo remoto y los
resultados se muestran en el equipo local.

Para finalizar la sesión interactiva, escriba:

PowerShell

Exit-PSSession
Para obtener más información sobre los Enter-PSSession cmdlets y Exit-PSSession ,
consulte:

Enter-PSSession
Exit-PSSession

Ejecutar un comando remoto


Para ejecutar un comando en uno o varios equipos, use el cmdlet Invoke-Command. Por
ejemplo, para ejecutar un comando Get-UICulture en los equipos remotos Server01 y
Server02, escriba:

PowerShell

Invoke-Command -ComputerName Server01, Server02 -ScriptBlock {Get-UICulture}

El resultado se muestra en su equipo.

Resultados

LCID Name DisplayName PSComputerName


---- ---- ----------- --------------
1033 en-US English (United States) server01.corp.fabrikam.com
1033 en-US English (United States) server02.corp.fabrikam.com

Ejecutar un script
Para ejecutar un script en uno o varios equipos remotos, use el parámetro FilePath del
Invoke-Command cmdlet . El script debe estar en el equipo local o accesible desde este.

Los resultados se devuelven en el equipo local.

Por ejemplo, el siguiente comando ejecuta el DiskCollect.ps1 script en los equipos


remotos, Server01 y Server02.

PowerShell

Invoke-Command -ComputerName Server01, Server02 -FilePath


c:\Scripts\DiskCollect.ps1

Establecer una conexión persistente


Utilice el cmdlet New-PSSession para crear una sesión persistente en un equipo remoto.
En el ejemplo siguiente se crean sesiones remotas en Server01 y Server02. Los objetos
de la sesión se almacenan en la variable $s .

PowerShell

$s = New-PSSession -ComputerName Server01, Server02

Ahora que las sesiones se han establecido, puede ejecutar cualquier comando en ellas.
Y, como las sesiones son persistentes, puede recopilar datos en un solo comando y
usarlos en un otro comando.

Por ejemplo, el siguiente comando ejecuta un Get-HotFix comando en las sesiones de


la $s variable y guarda los resultados en la $h variable. La variable $h se crea en cada
una de las sesiones en $s , pero no existe en la sesión local.

PowerShell

Invoke-Command -Session $s {$h = Get-HotFix}

Ahora puede usar los datos de la variable $h con otros comandos en la misma sesión.
Los resultados se muestran en el equipo local. Por ejemplo:

PowerShell

Invoke-Command -Session $s {$h | where {$_.InstalledBy -ne "NT


AUTHORITY\SYSTEM"}}

Comunicación remota avanzada


PowerShell incluye cmdlets que le permiten:

Configurar y crear sesiones remotas desde los extremos locales y remotos


Creación de sesiones personalizadas y restringidas
Importación de comandos desde una sesión remota que se ejecuta implícitamente
en la sesión remota
Configuración de la seguridad de una sesión remota

PowerShell en Windows incluye un proveedor WSMan. El proveedor crea una unidad


WSMAN: que le permite desplazarse por una jerarquía de valores de configuración en el

equipo local y en los equipos remotos.


Para más información sobre el proveedor de WSMan, consulte Proveedor de WSMan y
About WS-Management Cmdlets (Acerca de los cmdlets de WS-Management). También
puede escribir Get-Help wsman en la consola de Windows PowerShell.

Para obtener más información, consulte:

Preguntas más frecuentes sobre la comunicación remota de PowerShell


Register-PSSessionConfiguration
Import-PSSession

Para obtener ayuda con los errores de comunicación remota, consulte


about_Remote_Troubleshooting.

Consulte también
about_Remote
about_Remote_Requirements
about_Remote_Troubleshooting
about_PSSessions
about_WS-Management_Cmdlets
Invoke-Command
Import-PSSession
New-PSSession
Register-PSSessionConfiguration
Proveedor de WSMan
Comunicación remota de PowerShell a
través de SSH
Artículo • 07/10/2023

Información general
La comunicación remota de PowerShell suele usar WinRM para la negociación de la
conexión y el transporte de datos. SSH está ahora disponible para plataformas Linux y
Windows y permite una verdadera comunicación remota multiplataforma en PowerShell.

WinRM proporciona un modelo de hospedaje sólido para las sesiones remotas de


PowerShell. La comunicación remota basada en SSH no admite actualmente la
configuración remota de puntos de conexión y de Just Enough Administration (JEA).

La comunicación remota mediante SSH permite una comunicación remota de sesión de


PowerShell básica entre los equipos Windows y Linux. La comunicación remota
mediante SSH crea un proceso de host de PowerShell en el equipo de destino como un
subsistema SSH. Finalmente, implementaremos un modelo general de hospedaje, similar
a WinRM, para admitir la configuración de puntos de conexión y JEA.

Los cmdlets New-PSSession , Enter-PSSession y Invoke-Command ahora tienen un nuevo


conjunto de parámetros que permite esta nueva conexión de comunicación remota.

[-HostName <string>] [-UserName <string>] [-KeyFilePath <string>]

Para crear una sesión remota, especifique el equipo de destino con el parámetro
HostName y proporcione el nombre de usuario con UserName. Al ejecutar los cmdlets
de forma interactiva, se le pedirá una contraseña. También puede usar la autenticación
de la clave SSH mediante un archivo de clave privada con el parámetro KeyFilePath. La
creación de claves para la autenticación SSH varía según la plataforma.

Información de configuración general


Deben estar instalados PowerShell 6 o versiones posteriores y SSH en todos los equipos.
Instale tanto el cliente ( ssh.exe ) y el servidor ( sshd.exe ) SSH para que pueda
comunicarse de forma remota hacia y desde los equipos. OpenSSH para Windows ahora
está disponible en las compilación 1809 de Windows 10 y en Windows Server 2019. Para
obtener más información, vea Administrar Windows con OpenSSH. Para Linux, instale
SSH, incluido el servidor sshd, más adecuado para su plataforma. También necesita
instalar PowerShell de GitHub para obtener la característica de comunicación remota
mediante SSH. El servidor SSH debe estar configurado para crear un subsistema SSH
para hospedar un proceso PowerShell en el equipo remoto. Además, debe habilitar la
contraseña o la autenticación basada en claves.

Instalación del servicio SSH en un equipo


Windows
1. Instale la versión más reciente de PowerShell. Para más información, consulte
Instalación de PowerShell en Windows.

Para confirmar que PowerShell tiene compatibilidad con la comunicación remota


SSH, enumere los conjuntos de parámetros New-PSSession . Observará que hay
nombres de conjuntos de parámetros que comienzan por SSH. Esos conjuntos de
parámetros incluyen parámetros SSH.

PowerShell

(Get-Command New-PSSession).ParameterSets.Name

Output

Name
----
SSHHost
SSHHostHashParam

2. Instale la versión más reciente de OpenSSH para Win32. Para obtener instrucciones
de instalación, vea Introducción a OpenSSH.

7 Nota

Si quiere establecer PowerShell como el shell predeterminado para OpenSSH,


vea Configuración de Windows para OpenSSH.

3. Edite el archivo sshd_config ubicado en $env:ProgramData\ssh .

Asegúrese de que la autenticación de contraseña esté habilitada:


PasswordAuthentication yes

Cree el subsistema SSH que hospeda un proceso de PowerShell en el equipo


remoto:

Subsystem powershell c:/progra~1/powershell/7/pwsh.exe -sshs -nologo

7 Nota

A partir de PowerShell 7.4, ya no es necesario usar el -nologo parámetro al


ejecutar PowerShell en modo de servidor SSH.

7 Nota

La ubicación predeterminada del ejecutable de PowerShell es


c:/progra~1/powershell/7/pwsh.exe . Esta puede variar en función de cómo

haya instalado PowerShell.

Debe usar el nombre corto de 8.3 para las rutas de acceso de archivo que
contengan espacios. Hay un error en OpenSSH para Windows que impide que
los espacios funcionen en rutas de acceso ejecutables del subsistema. Para
más información, consulte este problema de GitHub .

Normalmente, el nombre corto de 8.3 de la carpeta Program Files en


Windows es Progra~1 . No obstante, puede usar el comando siguiente para
asegurarse:

PowerShell

Get-CimInstance Win32_Directory -Filter 'Name="C:\\Program Files"'


|
Select-Object EightDotThreeFileName

Output

EightDotThreeFileName
---------------------
c:\progra~1
Opcionalmente, habilite la autenticación de clave:

PubkeyAuthentication yes

Para obtener más información, vea Administración de claves de OpenSSH.

4. Reinicie el servicio sshd.

PowerShell

Restart-Service sshd

5. Agregue la ruta de acceso donde está instalado OpenSSH a la variable de entorno


Path. Por ejemplo, C:\Program Files\OpenSSH\ . Esta entrada permite encontrar el
archivo ssh.exe .

Instalación del servicio SSH en un equipo


Ubuntu Linux
1. Instale la versión más reciente de PowerShell. Consulte Instalación de PowerShell
en Ubuntu.

2. Instale Servidor OpenSSH en Ubuntu .

Bash

sudo apt install openssh-client


sudo apt install openssh-server

3. Edite el archivo sshd_config en ubicación /etc/ssh .

Asegúrese de que la autenticación de contraseña esté habilitada:

PasswordAuthentication yes

Opcionalmente, habilite la autenticación de clave:


PubkeyAuthentication yes

Para obtener más información sobre la creación de claves SSH en Ubuntu, vea la
página del manual de ssh-keygen .

Agregue una entrada de subsistema de PowerShell:

Subsystem powershell /usr/bin/pwsh -sshs -nologo

7 Nota

La ubicación predeterminada del ejecutable de PowerShell es /usr/bin/pwsh .


Esta puede variar en función de cómo haya instalado PowerShell.

7 Nota

A partir de PowerShell 7.4, ya no es necesario usar el -nologo parámetro al


ejecutar PowerShell en modo de servidor SSH.

4. Reinicie el servicio ssh.

Bash

sudo systemctl restart sshd.service

Instalación del servicio SSH en un equipo


macOS
1. Instale la versión más reciente de PowerShell. Para obtener más información,
Instalación de PowerShell en macOS.

Asegúrese de que la comunicación remota mediante SSH está habilitada. Para ello,
siga estos pasos:
a. Abra System Settings .
b. Haga clic en General .
c. Haga clic en Sharing .
d. Active Remote Login para establecer Remote Login: On .
e. Permita el acceso a los usuarios adecuados.

2. Edite el archivo sshd_config en ubicación /private/etc/ssh/sshd_config .

Use un editor de texto, como nano:

Bash

sudo nano /private/etc/ssh/sshd_config

Asegúrese de que la autenticación de contraseña esté habilitada:

PasswordAuthentication yes

Agregue una entrada de subsistema de PowerShell:

Subsystem powershell /usr/local/bin/pwsh -sshs -nologo

7 Nota

La ubicación predeterminada del ejecutable de PowerShell es


/usr/local/bin/pwsh . Esta puede variar en función de cómo haya instalado

PowerShell.

7 Nota

A partir de PowerShell 7.4, ya no es necesario usar el -nologo parámetro al


ejecutar PowerShell en modo de servidor SSH.

Opcionalmente, habilite la autenticación de clave:

PubkeyAuthentication yes

3. Reinicie el servicio sshd.


Bash

sudo launchctl stop com.openssh.sshd


sudo launchctl start com.openssh.sshd

Autenticación
La comunicación remota de PowerShell a través de SSH se basa en el intercambio de
autenticación entre el cliente de SSH y el servicio SSH, y no implementa los esquemas
de autenticación. El resultado es que los esquemas de autenticación configurados,
incluida la autenticación multifactor, se controlan mediante SSH y son independientes
de PowerShell. Por ejemplo, puede configurar el servicio SSH para que solicite la
autenticación con una clave pública y con una contraseña de un solo uso para una
mayor seguridad. La configuración de autenticación multifactor queda fuera del ámbito
de este documento. Consulte la documentación para SSH sobre cómo configurar la
autenticación multifactor correctamente y validar su funcionamiento fuera de
PowerShell antes de intentar usarlo con comunicación remota de PowerShell.

7 Nota

Los usuarios conservan los mismos privilegios en las sesiones remotas. Es decir, los
administradores tienen acceso a un shell con privilegios elevados, a diferencia de
los usuarios normales.

Ejemplo de comunicación remota de


PowerShell
La manera más fácil de comprobar si la comunicación remota funciona es probarla en
un único equipo. En este ejemplo, vamos a crear una sesión remota en el mismo equipo
Linux. Estamos usando cmdlets de PowerShell de manera interactiva para que aparezcan
avisos de SSH que solicitan comprobar el equipo host y que piden una contraseña.
Puede hacer lo mismo en un equipo Windows para garantizar que la comunicación
remota funcione. Después, establézcala entre equipos mediante el cambio del nombre
de host.

Linux a Linux
PowerShell
$session = New-PSSession -HostName UbuntuVM1 -UserName TestUser

Output

The authenticity of host 'UbuntuVM1 (9.129.17.107)' can't be established.


ECDSA key fingerprint is SHA256:2kCbnhT2dUE6WCGgVJ8Hyfu1z2wE4lifaJXLO7QJy0Y.
Are you sure you want to continue connecting (yes/no)?
TestUser@UbuntuVM1s password:

PowerShell

$session

Output

Id Name ComputerName ComputerType State ConfigurationName


Availability
-- ---- ------------ ------------ ----- ----------------- --
----------
1 SSH1 UbuntuVM1 RemoteMachine Opened DefaultShell
Available

PowerShell

Enter-PSSession $session

Output

[UbuntuVM1]: PS /home/TestUser> uname -a


Linux TestUser-UbuntuVM1 4.2.0-42-generic 49~16.04.1-Ubuntu SMP Wed Jun 29
20:22:11 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux

[UbuntuVM1]: PS /home/TestUser> Exit-PSSession

PowerShell

Invoke-Command $session -ScriptBlock { Get-Process pwsh }

Output

Handles NPM(K) PM(K) WS(K) CPU(s) Id SI ProcessName


PSComputerName
------- ------ ----- ----- ------ -- -- ----------- ---
-----------
0 0 0 19 3.23 10635 635 pwsh
UbuntuVM1
0 0 0 21 4.92 11033 017 pwsh
UbuntuVM1
0 0 0 20 3.07 11076 076 pwsh
UbuntuVM1

Linux a Windows
PowerShell

Enter-PSSession -HostName WinVM1 -UserName PTestName

PTestName@WinVM1s password:

PowerShell

[WinVM1]: PS C:\Users\PTestName\Documents> cmd /c ver

Output

Microsoft Windows [Version 10.0.10586]

Windows a Windows
PowerShell

C:\Users\PSUser\Documents>pwsh.exe

Output

PowerShell
Copyright (c) Microsoft Corporation. All rights reserved.

PowerShell

$session = New-PSSession -HostName WinVM2 -UserName PSRemoteUser

Output
The authenticity of host 'WinVM2 (10.13.37.3)' can't be established.
ECDSA key fingerprint is SHA256:kSU6slAROyQVMEynVIXAdxSiZpwDBigpAF/TXjjWjmw.
Are you sure you want to continue connecting (yes/no)?
Warning: Permanently added 'WinVM2,10.13.37.3' (ECDSA) to the list of known
hosts.
PSRemoteUser@WinVM2's password:

PowerShell

$session

Output

Id Name ComputerName ComputerType State


ConfigurationName Availability
-- ---- ------------ ------------ ----- ----------
------- ------------
1 SSH1 WinVM2 RemoteMachine Opened
DefaultShell Available

PowerShell

Enter-PSSession -Session $session

Output

[WinVM2]: PS C:\Users\PSRemoteUser\Documents> $PSVersionTable

Name Value
---- -----
PSEdition Core
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
SerializationVersion 1.1.0.1
BuildVersion 3.0.0.0
CLRVersion
PSVersion 6.0.0-alpha
WSManStackVersion 3.0
PSRemotingProtocolVersion 2.3
GitCommitId v6.0.0-alpha.17

[WinVM2]: PS C:\Users\PSRemoteUser\Documents>

Limitaciones
El comando sudo no funciona en una sesión remota con un equipo Linux.
PSRemoting a través de SSH no admite perfiles y no tiene acceso a $PROFILE . Una
vez que esté en una sesión, podrá cargar un perfil prefijando por puntos dicho
perfil con la ruta del archivo completa. Esto no está relacionado con los perfiles
ssh. Puede configurar el servidor SSH para usar PowerShell como el shell
predeterminado y cargar un perfil mediante SSH. Vea la documentación de SSH
para obtener más información.

Antes de PowerShell 7.1, la comunicación remota a través de SSH no admitía


sesiones remotas de segundo salto. Esta capacidad se limitaba a las sesiones que
usaban WinRM. PowerShell 7.1 permite que Enter-PSSession y Enter-
PSHostProcess funcionen desde cualquier sesión remota interactiva.

Consulte también
Instalación de PowerShell en Linux
Instalación de PowerShell en macOS
Instalación de PowerShell en Windows
Administrar Windows con OpenSSH
Administración de claves de OpenSSH
SSH de Ubuntu

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Uso de la comunicación remota de WS-
Management (WSMan) en PowerShell
Artículo • 07/10/2023

Habilitación de la comunicación remota de


PowerShell
Para habilitar la comunicación remota de PowerShell, ejecute el Enable-PSRemoting
cmdlet en una sesión de PowerShell con privilegios elevados. La ejecución Enable-
PSRemoting configura un punto de conexión de comunicación remota para la versión de

instalación específica en la que se ejecuta el cmdlet. Por ejemplo, al ejecutar Enable-


PSRemoting PowerShell 7.3, PowerShell crea un punto de conexión remoto que ejecuta

PowerShell 7.3. Si ejecuta Enable-PSRemoting powerShell 7-preview, PowerShell crea un


punto de conexión de comunicación remota que ejecuta PowerShell 7-preview. Puede
crear varios puntos de conexión remotos para diferentes versiones de que se ejecutan
en paralelo.

La ejecución Enable-PSRemoting crea dos puntos de conexión para esa versión.

Uno tiene un nombre simple correspondiente a la versión principal de PowerShell.


que hospeda la sesión. Por ejemplo, PowerShell.7.3.
El otro nombre de configuración contiene el número de versión completo. Por
ejemplo, PowerShell.7.3.7.

Puede conectarse a la versión más reciente de la versión de host de PowerShell 7 con el


nombre simple, PowerShell.7.3. Puede conectarse a una versión específica de
PowerShell con el nombre más largo y específico de la versión.

Use el parámetro ConfigurationName con los New-PSSession cmdlets y Enter-


PSSession para conectarse a una configuración con nombre.

La comunicación remota de WSMan no se


admite en plataformas que no son de Windows
Desde la versión de PowerShell 6, la compatibilidad con la comunicación remota a
través de WS-Management (WSMan) en plataformas que no son de Windows solo está
disponible para un conjunto limitado de distribuciones de Linux. Todas las versiones de
esas distribuciones compatibles con WSMan ya no son compatibles con los proveedores
de Linux que los crearon.

En el caso de windows, WSMan se basaba en el proyecto Open Management


Infrastructure (OMI), que ya no admite la comunicación remota de PowerShell. El
cliente WSMan de OMI depende de OpenSSL 1.0. La mayoría de las distribuciones de
Linux se han movido a OpenSSL 2.0, que no es compatible con versiones anteriores. En
este momento, no hay ninguna distribución admitida que tenga las dependencias
necesarias para que el cliente WSMan de OMI funcione.

Las bibliotecas obsoletas y el código auxiliar se han quitado para plataformas que no
son de Windows. La comunicación remota basada en WSMan sigue siendo compatible
entre sistemas Windows. La comunicación remota a través de SSH es compatible con
todas las plataformas. Para más información, consulte Comunicación remota de
PowerShell a través de SSH.

7 Nota

Es posible que los usuarios puedan obtener la comunicación remota de WSMan


para trabajar con el módulo PSWSMan . Microsoft no admite ni mantiene este
módulo.

Información adicional
Enable-PSRemoting
Enter-PSSession
New-PSSession

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Consideraciones sobre la seguridad de
comunicación remota de PowerShell
mediante WinRM
Artículo • 13/04/2023

La comunicación remota de PowerShell es la forma recomendada para administrar los


sistemas de Windows. La comunicación remota de PowerShell está habilitada de forma
predeterminada en Windows Server 2012 R2. En este documento se tratan cuestiones
de seguridad, recomendaciones y procedimientos recomendados para el uso de la
comunicación remota de PowerShell.

¿Qué es la comunicación remota de


PowerShell?
La comunicación remota de PowerShell usa Administración remota de Windows
(WinRM), que es la implementación de Microsoft del protocolo Servicios web para
administración (WS-Management) , que permite a los usuarios ejecutar comandos de
PowerShell en equipos remotos. Puede encontrar más información acerca del uso de la
comunicación remota de PowerShell en Ejecutar comandos remotos.

La comunicación remota de PowerShell no es lo mismo que usar el parámetro


ComputerName de un cmdlet para ejecutarlo en un equipo remoto, que usa la llamada
a procedimiento remoto (RPC) como protocolo subyacente.

Configuración predeterminada de la
comunicación remota de PowerShell
La comunicación remota de PowerShell (y WinRM) escucha los puertos siguientes:

HTTP: 5985
HTTPS: 5986

De manera predeterminada, la comunicación remota de PowerShell solo permite


conexiones de los miembros del grupo Administradores. Las sesiones se inician en el
contexto del usuario, por lo que todos los controles de acceso del sistema operativo
que se aplican a usuarios individuales y grupos continuarán aplicándose a estos
mientras estén conectados a través de la comunicación remota de PowerShell.
En redes privadas, la regla de Firewall de Windows predeterminada para la
comunicación remota de PowerShell acepta todas las conexiones. En redes públicas, la
regla predeterminada del Firewall de Windows permite las conexiones de comunicación
remota de PowerShell únicamente desde dentro de la misma subred. Tendrá que
cambiar explícitamente esa regla para abrir la comunicación remota de PowerShell a
todas las conexiones de una red pública.

2 Advertencia

La regla de firewall para redes públicas está diseñada para proteger el equipo
frente a los intentos de conexión externa potencialmente malintencionados. Tenga
precaución al quitar esta regla.

Aislamiento de procesos
La comunicación remota de PowerShell usa WinRM para la comunicación entre equipos.
WinRM se ejecuta como servicio en la cuenta servicio de red y genera procesos aislados
que se ejecutan como cuentas de usuario para las instancias de host de PowerShell. Una
instancia de PowerShell que se ejecuta como un usuario no tiene acceso a un proceso
que ejecuta una instancia de PowerShell como otro usuario.

Registros de eventos generados por la


comunicación remota de PowerShell
FireEye ha proporcionado un buen resumen de los registros de eventos y otras pruebas
de seguridad generados por las sesiones de comunicación remota de PowerShell,
disponible en Investigating PowerShell Attacks (Investigación de los ataques de
PowerShell).

Protocolos de transporte y cifrado


Resulta útil tener en cuenta la seguridad de una conexión remota de PowerShell desde
dos perspectivas: la autenticación inicial y la comunicación continua.

Independientemente del protocolo de transporte utilizado (HTTP o HTTPS), WinRM


siempre cifra toda la comunicación remota de PowerShell después de la autenticación
inicial.
Autenticación inicial
La autenticación confirma la identidad del cliente al servidor, e idealmente, del servidor
al cliente.

Cuando un cliente se conecta a un servidor de dominio mediante su nombre de equipo,


el protocolo de autenticación predeterminado es Kerberos. Kerberos garantiza la
identidad del usuario y del servidor sin enviar ningún tipo de credencial reutilizable.

Cuando un cliente se conecta a un servidor de dominio mediante su dirección IP o se


conecta a un servidor de grupo de trabajo, la autenticación Kerberos no es posible. En
ese caso, la comunicación remota de PowerShell se basa en el protocolo de
autenticación NTLM. El protocolo de autenticación NTLM garantiza la identidad del
usuario sin enviar ningún tipo de credenciales delegables. Para demostrar la identidad
del usuario, el protocolo NTLM requiere que tanto el cliente como el servidor procesen
una clave de sesión de la contraseña del usuario sin intercambiar la propia contraseña.
Normalmente, el servidor no conoce la contraseña del usuario, por lo que se comunica
con el controlador de dominio, que conoce la contraseña del usuario y calcula la clave
de sesión del servidor.

Sin embargo, el protocolo NTLM no garantiza la identidad del servidor. De la misma


forma que con todos los protocolos que usan NTLM para la autenticación, un atacante
con acceso a una cuenta de equipo unido a un dominio podría invocar el controlador de
dominio para procesar una clave de sesión NTLM y, por tanto, suplantar el servidor.

La autenticación basada en NTLM está deshabilitada de forma predeterminada, pero


puede permitirse al configurar SSL en el servidor de destino o el valor WinRM
TrustedHosts del cliente.

Uso de certificados SSL para validar la identidad del servidor


durante las conexiones basadas en NTLM

Puesto que el protocolo de autenticación NTLM no puede garantizar la identidad del


servidor de destino (solo que ya conoce la contraseña), puede configurar los servidores
de destino para usar SSL para la comunicación remota de PowerShell. La asignación de
un certificado SSL al servidor de destino (si lo emite una entidad emisora de certificados
en la que el cliente también confía) habilita la autenticación basada en NTLM que
garantiza la identidad del usuario y del servidor.

Omisión de errores de identidad de servidor basados en NTLM


Si no es factible implementar un certificado SSL en un servidor para las conexiones de
NTLM, puede suprimir los errores de identidad resultantes mediante la adición del
servidor a la lista WinRM TrustedHosts. Tenga en cuenta que agregar un nombre de
servidor a la lista TrustedHosts no debe considerarse como ninguna forma de
instrucción de la confiabilidad de los propios hosts, ya que el protocolo de autenticación
NTLM no puede garantizar que se conecte de hecho al host al que está intentando
conectarse. En su lugar, debe considerar que el valor de TrustedHosts sea la lista de
hosts de la que quiere suprimir el error generado por la imposibilidad de comprobar la
identidad del servidor.

Comunicación continua
Una vez completada la autenticación inicial, WinRM cifra la comunicación en curso. Al
conectarse a través de HTTPS, el protocolo TLS se usa para negociar el cifrado que se
usa para transportar los datos. Al conectarse a través de HTTP, el cifrado de nivel de
mensaje viene determinado por el protocolo de autenticación inicial utilizado.

La autenticación básica no proporciona cifrado.


La autenticación NTLM usa un cifrado RC4 con una clave de 128 bits.
El cifrado de autenticación de Kerberos viene determinado por el etype del vale
TGS. Es AES-256 en los sistemas modernos.
El cifrado CredSSP utiliza el conjunto de cifrado TLS que se negoció en el
protocolo de enlace.

Creación del segundo salto


De forma predeterminada, la comunicación remota de PowerShell usa Kerberos (si está
disponible) o NTLM para la autenticación. Ambos protocolos se autentican en el equipo
remoto sin enviarle credenciales. Esta es la manera más segura de autenticarse, pero
dado que la máquina remota no tiene las credenciales del usuario, no puede acceder a
otros equipos y servicios en nombre del usuario. Esto se conoce como el "problema del
segundo salto".

Hay varias formas de evitar este problema. Para obtener descripciones de estos
métodos y las ventajas e inconvenientes de cada uno, consulte Realizar el segundo salto
en la comunicación remota de PowerShell.

Referencias
Administración remota de Windows (WinRM)
Servicios web para administración (WS-Management)
2.2.9.1 Tipos de mensajes de cifrado
Kerberos
Protocolo de autenticación NTLM
Investigating PowerShell Attacks (Investigación de los ataques de PowerShell)
Realizar el segundo salto en la
comunicación remota de PowerShell
Artículo • 18/10/2023

El "problema del segundo salto" se refiere a una situación similar a la siguiente:

1. Ha iniciado sesión en ServidorA.


2. En ServidorA, inicia una sesión remota de PowerShell para conectarse a ServidorB.
3. Un comando que ejecuta en ServidorB a través de la sesión de comunicación
remota de PowerShell intenta obtener acceso a un recurso en ServidorC.
4. Se deniega el acceso al recurso en ServerC , ya que las credenciales que usó para
crear la sesión de comunicación remota de PowerShell no se pasan de ServerB a
ServerC.

Hay varias formas de abordar este problema. En la tabla siguiente se enumeran los
métodos por orden de preferencia.

Configuración Nota:

CredSSP Ofrece un equilibrio entre la facilidad de uso y la


seguridad.

Delegación limitada de Kerberos basada en Ofrece mayor seguridad con una configuración
recursos más sencilla.

Delegación limitada de Kerberos Ofrece una seguridad elevada, pero requiere un


administrador de dominio.

Delegación Kerberos (sin restricciones) No se recomienda

Just Enough Administration (JEA) Puede proporcionar la mejor seguridad, pero


requiere una configuración más detallada.

PSSessionConfiguration con RunAs Es una opción más sencilla de configurar, pero


requiere la administración de credenciales.

Pase de credenciales dentro de un bloque de Es la opción más sencilla de usar, pero se deben
script de Invoke-Command proporcionar credenciales.

CredSSP
Puede usar el proveedor de compatibilidad para seguridad de credenciales (CredSSP)
para la autenticación. CredSSP copia en caché las credenciales en el servidor remoto
(ServidorB), por lo que, al usarlo, le hace vulnerable a los ataques de robos de
credenciales. Si el equipo remoto se ve comprometido, el atacante tiene acceso a las
credenciales del usuario. CredSSP está deshabilitado de forma predeterminada tanto en
el equipo del cliente como del servidor. Debe habilitar CredSSP solo en los entornos de
mayor confianza. Por ejemplo, un administrador de dominio que se conecta a un
controlador de dominio porque el controlador de dominio es de plena confianza.

Para obtener más información sobre problemas de seguridad cuando se usa CredSSP
para la comunicación remota de PowerShell, vea Accidental Sabotage: Beware of
CredSSP (Sabotaje accidental: tenga cuidado con CredSSP).

Para obtener más información acerca de los ataques de robo de credenciales, consulte
Mitigating Pass-the-Hash (PtH) Attacks and Other Credential Theft (Mitigación de
ataques Pass-the-Hash (PtH) y otros robos de credenciales).

Para obtener un ejemplo sobre cómo habilitar y usar CredSSP para la comunicación
remota de PowerShell, vea Habilitar la funcionalidad "segundo salto" de PowerShell con
CredSSP .

Ventajas
Funciona en todos los servidores con Windows Server 2008 o versiones
posteriores.

Desventajas
Tiene vulnerabilidades de seguridad.
Requiere la configuración de roles de cliente y servidor.
no funciona con el grupo Usuarios protegidos. Para obtener más información, vea
Grupo de seguridad de usuarios protegidos.

Delegación limitada de Kerberos


Puede usar la delegación limitada heredada (no basada en recursos) para realizar el
segundo salto. Configure la delegación restringida de Kerberos con la opción "Usar
cualquier protocolo de autenticación" para permitir la transición del protocolo.

Ventajas
No requiere código especial
Las credenciales no se almacenan.
Desventajas
No admite el segundo salto para WinRM.
Requiere el acceso de administrador de dominio para la configuración.
Se debe configurar en el objeto de Active Directory del servidor remoto
(ServidorB).
Limitado a un dominio. No se pueden cruzar dominios ni bosques.
Requiere derechos para actualizar objetos y nombres de entidad de seguridad de
servicio (SPN).
El ServidorB puede adquirir un vale de Kerberos para el ServidorC en nombre del
usuario sin la intervención de este.

7 Nota

Las cuentas de Active Directory que tienen la cuenta distinguen y no se pueden


delegar las propiedades establecidas. Para obtener más información, vea Security
Focus: Análisis de "Account is sensitive and can't be delegated" for Privileged
Accounts and Kerberos Authentication Tools and Kerberos authentication Tools and
Configuración.

Delegación limitada de Kerberos basada en


recursos
Con la delegación limitada de Kerberos basada en recursos (introducida en Windows
Server 2012), configura la delegación de credenciales en el objeto de servidor en que
residen los recursos. En el escenario del segundo salto descrito anteriormente, puede
configurar el ServidorC para especificar desde dónde aceptar las credenciales delegadas.

Ventajas
Las credenciales no se almacenan.
Se configura con los cmdlets de PowerShell. No requiere código especial.
No requiere el acceso de dominio Administración istrator para configurar.
Funciona en dominios y bosques.

Desventajas
Necesita Windows Server 2012 o versiones posteriores.
No admite el segundo salto para WinRM.
Requiere derechos para actualizar objetos y nombres de entidad de seguridad de
servicio (SPN).

7 Nota

Las cuentas de Active Directory que tienen la cuenta distinguen y no se pueden


delegar las propiedades establecidas. Para obtener más información, vea Security
Focus: Análisis de "Account is sensitive and can't be delegated" for Privileged
Accounts and Kerberos Authentication Tools and Kerberos authentication Tools and
Configuración.

Ejemplo
Veamos un ejemplo de PowerShell que configura la delegación restringida basada en
recursos en el ServidorC para admitir credenciales delegadas de un ServidorB. En este
ejemplo, se supone que todos los servidores ejecutan Windows Server 2012 o una
versión posterior y que hay al menos un controlador de dominio de Windows Server
2012 en cada dominio a los que pertenecen los servidores.

Antes de que pueda configurar la delegación restringida, debe agregar la característica


RSAT-AD-PowerShell para instalar el módulo de PowerShell de Active Directory y después

importar ese módulo en la sesión:

PowerShell

Add-WindowsFeature RSAT-AD-PowerShell
Import-Module ActiveDirectory
Get-Command -ParameterName PrincipalsAllowedToDelegateToAccount

Varios cmdlets disponibles tienen ahora un parámetro


PrincipalsAllowedToDelegateToAccount:

Output

CommandType Name ModuleName


----------- ---- ----------
Cmdlet New-ADComputer ActiveDirectory
Cmdlet New-ADServiceAccount ActiveDirectory
Cmdlet New-ADUser ActiveDirectory
Cmdlet Set-ADComputer ActiveDirectory
Cmdlet Set-ADServiceAccount ActiveDirectory
Cmdlet Set-ADUser ActiveDirectory
El parámetro PrincipalsAllowedToDelegateToAccount establece el atributo de objeto de
Active Directory msDS-AllowedToActOnBehalfOfOtherIdentity, que contiene una lista
de control de acceso (ACL) que especifica qué cuentas tienen permiso para delegar
credenciales a la cuenta asociada (en nuestro ejemplo, será la cuenta del equipo de
ServidorA).

Ahora vamos a configurar las variables que usaremos para representar los servidores:

PowerShell

# Set up variables for reuse


$ServerA = $env:COMPUTERNAME
$ServerB = Get-ADComputer -Identity ServerB
$ServerC = Get-ADComputer -Identity ServerC

WinRM (y, por tanto, la comunicación remota de PowerShell) se ejecuta como la cuenta
de equipo de forma predeterminada. Puede ver esto si atiende a la propiedad
StartName del servicio winrm :

PowerShell

Get-CimInstance Win32_Service -Filter 'Name="winrm"' | Select-Object


StartName

Output

StartName
---------
NT AUTHORITY\NetworkService

Para que ServidorC permita la delegación desde una sesión de comunicación remota de
PowerShell en ServidorB, debemos establecer el parámetro
PrincipalsAllowedToDelegateToAccount en ServidorC al objeto de equipo de ServidorB:

PowerShell

# Grant resource-based Kerberos constrained delegation


Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount
$ServerB

# Check the value of the attribute directly


$x = Get-ADComputer -Identity $ServerC -Properties msDS-
AllowedToActOnBehalfOfOtherIdentity
$x.'msDS-AllowedToActOnBehalfOfOtherIdentity'.Access

# Check the value of the attribute indirectly


Get-ADComputer -Identity $ServerC -Properties
PrincipalsAllowedToDelegateToAccount

El Centro de distribución de claves (KDC) de Kerberos copia en caché los intentos de


acceso denegados (caché negativa) durante 15 minutos. Si ServerB ha intentado acceder
previamente a ServerC, debe borrar la memoria caché en ServerB invocando el siguiente
comando:

PowerShell

Invoke-Command -ComputerName $ServerB.Name -Credential $cred -ScriptBlock {


klist purge -li 0x3e7
}

También puede reiniciar el equipo o esperar al menos 15 minutos para borrar la caché.

Después de borrar la caché, puede ejecutar correctamente código desde el ServidorA a


través del ServidorB hasta el ServidorC:

PowerShell

# Capture a credential
$cred = Get-Credential Contoso\Alice

# Test kerberos double hop


Invoke-Command -ComputerName $ServerB.Name -Credential $cred -ScriptBlock {
Test-Path \\$($using:ServerC.Name)\C$
Get-Process lsass -ComputerName $($using:ServerC.Name)
Get-EventLog -LogName System -Newest 3 -ComputerName
$($using:ServerC.Name)
}

En este ejemplo, la variable $using se usa para hacer visible la variable $ServerC en el
ServidorB. Para obtener más información sobre la variable $using , consulte
about_Remote_Variables.

Para permitir que varios servidores deleguen credenciales en el ServidorC, establezca el


valor del parámetro PrincipalsAllowedToDelegateToAccount en el ServidorC a una
matriz:

PowerShell

# Set up variables for each server


$ServerB1 = Get-ADComputer -Identity ServerB1
$ServerB2 = Get-ADComputer -Identity ServerB2
$ServerB3 = Get-ADComputer -Identity ServerB3
$ServerC = Get-ADComputer -Identity ServerC
$servers = @(
$ServerB1,
$ServerB2,
$ServerB3
)

# Grant resource-based Kerberos constrained delegation


Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount
$servers

Si desea realizar el segundo salto entre dominios, use el parámetro Server para
especificar el nombre de dominio completo (FQDN) del controlador de dominio del
dominio al que pertenece ServerB:

PowerShell

# For ServerC in Contoso domain and ServerB in other domain


$ServerB = Get-ADComputer -Identity ServerB -Server dc1.alpineskihouse.com
$ServerC = Get-ADComputer -Identity ServerC
Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount
$ServerB

Para quitar la capacidad de delegar credenciales en el ServidorC, establezca el valor del


parámetro PrincipalsAllowedToDelegateToAccount en el ServidorC en $null :

PowerShell

Set-ADComputer -Identity $ServerC -PrincipalsAllowedToDelegateToAccount


$null

Información sobre la delegación limitada de Kerberos


basada en recursos
Novedades de la autenticación Kerberos
How Windows Server 2012 Eases the Pain of Kerberos Constrained Delegation, Part
1 (Cómo simplifica Windows Server 2012 el proceso de delegación limitada de
Kerberos, parte 1)
How Windows Server 2012 Eases the Pain of Kerberos Constrained Delegation, Part
2 (Cómo simplifica Windows Server 2012 el proceso de delegación limitada de
Kerberos, parte 2)
Descripción de la delegación restringida de Kerberos para implementaciones de
proxy de aplicación de Microsoft Entra con autenticación integrada de Windows
[Atributos de esquema de Active Directory ms-ADA2 M2.210 atributo msDS-
AllowedToActOnBehalfOfOtherIdentity]MS-ADA2
[Extensiones de protocolo Kerberos ms-SFU : servicio para el protocolo de
delegación restringida y de usuario 1.3.2 S4U2proxy]MS-SFU
Remote Administration Without Constrained Delegation Using
PrincipalsAllowedToDelegateToAccount (Administración remota sin delegación
limitada con PrincipalsAllowedToDelegateToAccount)

Delegación Kerberos (sin restricciones)


También puede usar la delegación sin restricciones de Kerberos para realizar el segundo
salto. Al igual que todos los escenarios de Kerberos, las credenciales no se almacenan.
Este método no admite el segundo salto para WinRM.

2 Advertencia

No proporciona control sobre dónde se usan las credenciales delegadas. Es menos


seguro que CredSSP. Solo se debe usar para escenarios de prueba.

Just Enough Administration (JEA)


JEA le permite restringir qué comandos puede ejecutar un administrador durante una
sesión de PowerShell. Se puede usar para resolver el problema del segundo salto.

Para obtener información sobre JEA, consulte Just Enough Administration.

Ventajas
No hay mantenimiento de contraseña al usar una cuenta virtual.

Desventajas
Requiere WMF 5.0 o versiones posteriores.
Es necesario configurar cada servidor intermedio (ServidorB).

PSSessionConfiguration con RunAs


Puede crear una configuración de sesión en el ServidorB y establecer su parámetro
RunAsCredential.
Para obtener información sobre el uso de PSSessionConfiguration y RunAs para
resolver el problema del segundo salto, vea Otra solución a la comunicación remota de
PowerShell de varios saltos.

Ventajas
Funciona con cualquier servidor con WMF 3.0 o versiones posteriores.

Desventajas
Requiere la configuración de PSSessionConfiguration y RunAs en cada servidor
intermedio (ServidorB).
Requiere el mantenimiento de la contraseña cuando se usa una cuenta de
ejecución de dominio

Pasar credenciales dentro de un bloque de


script de Invoke-Command
Se pueden pasar credenciales dentro del parámetro ScriptBlock de una llamada al
cmdlet Invoke-Command.

Ventajas
No requiere una configuración especial del servidor.
Funciona en cualquier servidor que ejecute WMF 2.0 o versiones posteriores.

Desventajas
Se requiere una técnica de código complicada.
Si ejecuta WMF 2.0, requiere una sintaxis diferente para pasar argumentos a una
sesión remota.

Ejemplo
En el ejemplo siguiente se muestra cómo pasar credenciales en un bloque de script:

PowerShell

# This works without delegation, passing fresh creds


# Note $Using:Cred in nested request
$cred = Get-Credential Contoso\Administrator
Invoke-Command -ComputerName ServerB -Credential $cred -ScriptBlock {
hostname
Invoke-Command -ComputerName ServerC -Credential $Using:cred -
ScriptBlock {hostname}
}

Consulte también
Consideraciones de seguridad de comunicación remota de PowerShell

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Preguntas más frecuentes sobre la
comunicación remota de
PowerShell
Preguntas más frecuentes

Al trabajar de forma remota, escriba comandos en PowerShell en un equipo (conocido


como "equipo local"), pero los comandos se ejecutan en otro equipo (conocido como
"equipo remoto"). La experiencia de trabajar de forma remota debe ser tan parecida a
trabajar directamente en el equipo remoto como sea posible.

7 Nota

Para usar la comunicación remota de PowerShell, el equipo remoto debe


configurarse para la comunicación remota. Para obtener más información, consulte
about_Remote_Requirements.

¿Ambos equipos deben tener Instalado


PowerShell?
Sí. Para trabajar de forma remota, los equipos locales y remotos deben tener PowerShell,
Microsoft .NET Framework y el protocolo Servicios web para administración (WS-
Management). Los archivos y otros recursos necesarios para ejecutar un comando
determinado deben estar en el equipo remoto.

Los equipos que ejecutan Windows PowerShell 3.0 y los equipos que ejecutan Windows
PowerShell 2.0 pueden conectarse entre sí de forma remota y ejecutar comandos
remotos. Sin embargo, algunas características, como la capacidad de desconectar de
una sesión y volver a conectarse a ella, solo funcionan cuando ambos equipos ejecutan
Windows PowerShell 3.0.

Debe tener permiso para conectarse al equipo remoto, permiso para ejecutar
PowerShell y permiso para acceder a almacenes de datos (como archivos y carpetas) y el
registro en el equipo remoto.

Para obtener más información, consulte about_Remote_Requirements.


¿Cómo funciona la comunicación
remota?
Al enviar un comando remoto, el comando se transmite a través de la red al motor de
PowerShell en el equipo remoto y se ejecuta en el cliente de PowerShell en el equipo
remoto. Los resultados del comando se devuelven al equipo local y aparecen en la
sesión de PowerShell en el equipo local.

Para transmitir los comandos y recibir la salida, PowerShell usa el protocolo WS-
Management. Para obtener información sobre el protocolo WS-Management, vea WS-
Management Protocol en la documentación de Windows.

A partir de Windows PowerShell 3.0, las sesiones remotas se almacenan en el equipo


remoto. Esto le permite desconectar de la sesión y volver a conectarse de una sesión
diferente o de otro equipo sin interrumpir los comandos o perder el estado.

¿Es seguro la comunicación remota de


PowerShell?
Cuando se conecta a un equipo remoto, el sistema usa las credenciales de nombre de
usuario y contraseña en el equipo local o las credenciales que proporcione en el
comando para iniciar sesión en el equipo remoto. Las credenciales y el resto de la
transmisión se cifran.

Para agregar protección adicional, puede configurar el equipo remoto para que use
Capa de sockets seguros (SSL) en lugar de HTTP para escuchar solicitudes de
Administración remota de Windows (WinRM). A continuación, los usuarios pueden usar
el parámetro UseSSL de los Invoke-Command cmdlets , New-PSSession y Enter-PSSession al
establecer una conexión. Esta opción usa el canal HTTPS más seguro en lugar de HTTP.

¿Todos los comandos remotos requieren


comunicación remota de PowerShell?
No. Algunos cmdlets tienen un parámetro ComputerName que permite obtener objetos
del equipo remoto.

Estos cmdlets no usan la comunicación remota de PowerShell. Por lo tanto, puede


usarlos en cualquier equipo que ejecute PowerShell, incluso si el equipo no está
configurado para la comunicación remota de PowerShell o si el equipo no cumple los
requisitos para la comunicación remota de PowerShell.

Estos cmdlets incluyen lo siguiente:

Get-Hotfix

Rename-Computer

Restart-Computer
Stop-Computer

Para buscar todos los cmdlets con un parámetro ComputerName , escriba:

PowerShell

Get-Help * -Parameter ComputerName


# or
Get-Command -ParameterName ComputerName

Para determinar si el parámetro ComputerName de un cmdlet determinado requiere


comunicación remota de PowerShell, consulte la descripción del parámetro. Para
mostrar la descripción del parámetro, escriba:

PowerShell

Get-Help <cmdlet-name> -Parameter ComputerName

Por ejemplo:

PowerShell

Get-Help Get-Hotfix -Parameter ComputerName

Para todos los demás comandos, use el Invoke-Command cmdlet .

Cómo ejecutar un comando en un


equipo remoto?
Para ejecutar un comando en un equipo remoto, use el Invoke-Command cmdlet .

Incluya el comando entre llaves ( {} ) para convertirlo en un bloque de script. Use el


parámetro ScriptBlock de Invoke-Command para especificar el comando .
Puede usar el parámetro ComputerName de Invoke-Command para especificar un equipo
remoto. O bien, puede crear una conexión persistente a un equipo remoto (una sesión)
y, a continuación, usar el parámetro Session de Invoke-Command para ejecutar el
comando en la sesión.

Por ejemplo, los siguientes comandos ejecutan un Get-Process comando de forma


remota.

PowerShell

Invoke-Command -ComputerName Server01, Server02 -ScriptBlock {Get-Process}

# - OR -

Invoke-Command -Session $s -ScriptBlock {Get-Process}

Para interrumpir un comando remoto, escriba CTRL + C . La solicitud de interrupción se


pasa al equipo remoto, donde finaliza el comando remoto.

Para obtener más información sobre los comandos remotos, consulte about_Remote y
los temas de ayuda de los cmdlets que admiten la comunicación remota.

¿Puedo simplemente telnet en un


equipo remoto?
Puede usar el Enter-PSSession cmdlet para iniciar una sesión interactiva con un equipo
remoto.

En el símbolo del sistema de PowerShell, escriba:

PowerShell

Enter-PSSession <ComputerName>

El símbolo del sistema cambia para mostrar que está conectado al equipo remoto.

<ComputerName>\C:>

Ahora, los comandos que escriba se ejecutan en el equipo remoto igual que si los
escribe directamente en el equipo remoto.
Para finalizar la sesión interactiva, escriba:

PowerShell

Exit-PSSession

Una sesión interactiva es una sesión persistente que usa el protocolo WS-Management.
No es lo mismo que usar Telnet, pero proporciona una experiencia similar.

Para más información, consulte Enter-PSSession .

¿Puedo crear una conexión persistente?


Sí. Puede ejecutar comandos remotos especificando el nombre del equipo remoto, su
nombre NetBIOS o su dirección IP. O bien, puede ejecutar comandos remotos
especificando una sesión de PowerShell (PSSession) conectada al equipo remoto.

Cuando se usa el parámetro ComputerName de Invoke-Command o Enter-PSSession ,


PowerShell establece una conexión temporal. PowerShell usa la conexión para ejecutar
solo el comando actual y, a continuación, cierra la conexión. Se trata de un método muy
eficaz para ejecutar un solo comando o varios comandos no relacionados, incluso en
muchos equipos remotos.

Cuando se usa el New-PSSession cmdlet para crear una PSSession, PowerShell establece
una conexión persistente para PSSession. Después, puede ejecutar varios comandos en
la PSSession, incluidos los comandos que comparten datos.

Normalmente, se crea una PSSession para ejecutar una serie de comandos relacionados
que comparten datos. De lo contrario, la conexión temporal creada por el parámetro
ComputerName es suficiente para la mayoría de los comandos.

Para obtener más información sobre las sesiones, consulte about_PSSessions.

¿Puedo ejecutar comandos en más de


un equipo a la vez?
Sí. El parámetro ComputerName del Invoke-Command cmdlet acepta varios nombres de
equipo y el parámetro Session acepta varias PSSessions.

Al ejecutar un Invoke-Command comando, PowerShell ejecuta los comandos en todos los


equipos especificados o en todas las PSSessions especificadas.
PowerShell puede administrar cientos de conexiones remotas simultáneas. Sin embargo,
el número de comandos remotos que puede enviar puede estar limitado por los
recursos del equipo y su capacidad para establecer y mantener varias conexiones de
red.

Para obtener más información, vea el ejemplo en el Invoke-Command tema de Ayuda.

¿Dónde están mis perfiles?


Los perfiles de PowerShell no se ejecutan automáticamente en sesiones remotas, por lo
que los comandos que agrega el perfil no están presentes en la sesión. Además, la
$profile variable automática no se rellena en sesiones remotas.

Para ejecutar un perfil en una sesión, use el Invoke-Command cmdlet .

Por ejemplo, el siguiente comando ejecuta el perfil CurrentUserCurrentHost desde el


equipo local de la sesión en $s .

Invoke-Command -Session $s -FilePath $profile

El siguiente comando ejecuta el perfil CurrentUserCurrentHost desde el equipo remoto


de la sesión en $s . Dado que la $profile variable no se rellena, el comando usa la ruta
de acceso explícita al perfil.

PowerShell

Invoke-Command -Session $s {
. "$home\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1"
}

Después de ejecutar este comando, los comandos que el perfil agrega a la sesión están
disponibles en $s .

También puede usar un script de inicio en una configuración de sesión para ejecutar un
perfil en cada sesión remota que use la configuración de sesión.

Para más información sobre los perfiles de PowerShell, consulte about_Profiles. Para
obtener más información sobre las configuraciones de sesión, vea Register-
PSSessionConfiguration .
¿Cómo funciona la limitación en los
comandos remotos?
Para ayudarle a administrar los recursos en el equipo local, PowerShell incluye una
característica de limitación por comando que le permite limitar el número de conexiones
remotas simultáneas establecidas para cada comando.

El valor predeterminado es 32 conexiones simultáneas, pero puede usar el parámetro


ThrottleLimit de los cmdlets para establecer un límite de limitación personalizado para
determinados comandos.

Al usar la característica de limitación, recuerde que se aplica a cada comando, no a toda


la sesión o al equipo. Si ejecuta comandos simultáneamente en varias sesiones o
PSSessions, el número de conexiones simultáneas es la suma de las conexiones
simultáneas en todas las sesiones.

Para buscar cmdlets con un parámetro ThrottleLimit , escriba:

Get-Help * -Parameter ThrottleLimit


-or-
Get-Command -ParameterName ThrottleLimit

¿La salida de los comandos remotos es


diferente de la salida local?
Cuando se usa PowerShell localmente, se envían y reciben objetos de .NET Framework
dinámicos; Los objetos "activos" son objetos asociados a programas o componentes del
sistema reales. Al invocar los métodos o cambiar las propiedades de los objetos
dinámicos, los cambios afectan al programa o componente real. Además, cuando
cambian las propiedades de un programa o componente, también cambian las
propiedades del objeto que las representan.

Sin embargo, dado que la mayoría de los objetos activos no se pueden transmitir a
través de la red, PowerShell "serializa" la mayoría de los objetos enviados en comandos
remotos, es decir, convierte cada objeto en una serie de elementos de datos XML
(Lenguaje de restricción en XML [CLiXML]) para la transmisión.

Cuando PowerShell recibe un objeto serializado, convierte el XML en un tipo de objeto


deserializado. El objeto deserializado es un registro preciso de las propiedades del
programa o componente en un momento anterior, pero ya no es "activo", es decir, ya
no está asociado directamente con el componente. Además, los métodos se quitan
porque ya no son eficaces.

Normalmente, puede usar objetos deserializados igual que usaría objetos dinámicos,
pero debe tener en cuenta sus limitaciones. Además, los objetos devueltos por el
Invoke-Command cmdlet tienen propiedades adicionales que le ayudan a determinar el

origen del comando.

Algunos tipos de objetos, como los objetos DirectoryInfo y los GUID, se convierten de
nuevo en objetos activos cuando se reciben. Estos objetos no necesitan ningún control
ni formato especiales.

Para obtener información sobre cómo interpretar y dar formato a la salida remota,
consulte about_Remote_Output.

¿Puedo ejecutar trabajos en segundo


plano de forma remota?
Sí. Un trabajo en segundo plano de PowerShell es un comando de PowerShell que se
ejecuta de forma asincrónica sin interactuar con la sesión. Al iniciar un trabajo en
segundo plano, el símbolo del sistema se devuelve inmediatamente y puede continuar
trabajando en la sesión mientras se ejecuta el trabajo aunque se ejecute durante un
período de tiempo prolongado.

Puede iniciar un trabajo en segundo plano incluso mientras se ejecutan otros comandos
porque los trabajos en segundo plano siempre se ejecutan de forma asincrónica en una
sesión temporal.

Puede ejecutar trabajos en segundo plano en un equipo local o remoto. De forma


predeterminada, un trabajo en segundo plano se ejecuta en el equipo local. Sin
embargo, puede usar el parámetro AsJob del Invoke-Command cmdlet para ejecutar
cualquier comando remoto como un trabajo en segundo plano. Además, puede usar
Invoke-Command para ejecutar un Start-Job comando de forma remota.

Para obtener más información sobre los trabajos en segundo plano en PowerShell,
consulte about_Jobs y about_Remote_Jobs.

¿Puedo ejecutar programas de Windows


en un equipo remoto?
Puede usar comandos remotos de PowerShell para ejecutar programas basados en
Windows en equipos remotos. Por ejemplo, puede ejecutar Shutdown.exe o
Ipconfig.exe en un equipo remoto.

Sin embargo, no puede usar comandos de PowerShell para abrir la interfaz de usuario
de ningún programa en un equipo remoto.

Cuando se inicia un programa de Windows en un equipo remoto, el comando no se


completa y el símbolo del sistema de PowerShell no devuelve, hasta que el programa
haya terminado o hasta que presione CTRL + C para interrumpir el comando. Por
ejemplo, si ejecuta el Ipconfig.exe programa en un equipo remoto, el símbolo del
sistema no devuelve hasta Ipconfig.exe que se completa.

Si usa comandos remotos para iniciar un programa que tiene una interfaz de usuario, se
inicia el proceso de programa, pero la interfaz de usuario no aparece. El comando de
PowerShell no se completa y el símbolo del sistema no devuelve hasta que detenga el
proceso del programa o hasta que presione CTRL + C , lo que interrumpe el comando y
detiene el proceso.

Por ejemplo, si usa un comando de PowerShell para ejecutarse Notepad en un equipo


remoto, el proceso del Bloc de notas se inicia en el equipo remoto, pero la interfaz de
usuario del Bloc de notas no aparece. Para interrumpir el comando y restaurar el
símbolo del sistema, presione CTRL + C .

¿Puedo limitar los comandos que los


usuarios pueden ejecutar de forma
remota en mi equipo?
Sí. Cada sesión remota debe usar una de las configuraciones de sesión en el equipo
remoto. Puede administrar las configuraciones de sesión en el equipo (y los permisos
para esas configuraciones de sesión) para determinar quién puede ejecutar comandos
de forma remota en el equipo y qué comandos pueden ejecutar.

Una configuración de sesión configura el entorno de la sesión. Puede definir la


configuración mediante un ensamblado que implemente una nueva clase de
configuración o mediante un script que se ejecute en la sesión. La configuración puede
determinar los comandos que están disponibles en la sesión. Además, la configuración
puede incluir opciones que protegen el equipo, como la configuración que limita la
cantidad de datos que la sesión puede recibir de forma remota en un solo objeto o
comando. También puede especificar un descriptor de seguridad que determine los
permisos necesarios para usar la configuración.

El Enable-PSRemoting cmdlet crea las configuraciones de sesión predeterminadas en el


equipo: Microsoft.PowerShell, Microsoft.PowerShell.Workflow y Microsoft.PowerShell32
(solo sistemas operativos de 64 bits). Enable-PSRemoting establece el descriptor de
seguridad de la configuración para permitir que solo los miembros del grupo
Administradores del equipo los usen.

Puede usar los cmdlets de configuración de sesión para editar las configuraciones de
sesión predeterminadas, para crear nuevas configuraciones de sesión y cambiar los
descriptores de seguridad de todas las configuraciones de sesión.

A partir de Windows PowerShell 3.0, el New-PSSessionConfigurationFile cmdlet le


permite crear configuraciones de sesión personalizadas mediante un archivo de texto. El
archivo incluye opciones para establecer el modo de idioma y para especificar los
cmdlets y módulos que están disponibles en las sesiones que usan la configuración de
sesión.

Cuando los usuarios usan los Invoke-Command cmdlets , New-PSSession o Enter-PSSession


, pueden usar el parámetro ConfigurationName para indicar la configuración de sesión
que se usa para la sesión. Además, pueden cambiar la configuración predeterminada
que usan sus sesiones cambiando el valor de la $PSSessionConfigurationName variable
de preferencia en la sesión.

Para obtener más información sobre las configuraciones de sesión, consulte la Ayuda
para los cmdlets de configuración de sesión. Para buscar los cmdlets de configuración
de sesión, escriba:

PowerShell

Get-Command *PSSessionConfiguration

¿Qué son las configuraciones de


distribución de ventilador y
distribución?
El escenario de comunicación remota de PowerShell más común que implica varios
equipos es la configuración uno a varios, en la que un equipo local (el equipo del
administrador) ejecuta comandos de PowerShell en numerosos equipos remotos. Esto
se conoce como el escenario de "distribución ramificada".

Sin embargo, en algunas empresas, la configuración es de varios a uno, donde muchos


equipos cliente se conectan a un único equipo remoto que ejecuta PowerShell, como un
servidor de archivos o un quiosco. Esto se conoce como la configuración de "fan-in".

La comunicación remota de PowerShell admite configuraciones de distribución


ramificada y de ventilador.

Para la configuración de distribución ramificada, PowerShell usa el protocolo Web


Services for Management (WS-Management) y el servicio WinRM que admite la
implementación de Microsoft de WS-Management. Cuando un equipo local se conecta
a un equipo remoto, WS-Management establece una conexión y usa un complemento
para PowerShell para iniciar el proceso de host de PowerShell (Wsmprovhost.exe) en el
equipo remoto. El usuario puede especificar un puerto alternativo, una configuración de
sesión alternativa y otras características para personalizar la conexión remota.

Para admitir la configuración de "fan-in", PowerShell usa Internet Information Services


(IIS) para hospedar WS-Management, para cargar el complemento de PowerShell y para
iniciar PowerShell. En este escenario, en lugar de iniciar cada sesión de PowerShell en un
proceso independiente, todas las sesiones de PowerShell se ejecutan en el mismo
proceso de host.

El hospedaje de IIS y la administración remota de ventilador no se admiten en Windows


XP ni en Windows Server 2003.

En una configuración de ventilador, el usuario puede especificar un URI de conexión y


un punto de conexión HTTP, incluido el transporte, el nombre del equipo, el puerto y el
nombre de la aplicación. IIS reenvía todas las solicitudes con un nombre de aplicación
especificado a la aplicación. El valor predeterminado es WS-Management, que puede
hospedar PowerShell.

También puede especificar un mecanismo de autenticación y prohibir o permitir el


redireccionamiento desde puntos de conexión HTTP y HTTPS.

¿Puedo probar la comunicación remota


en un solo equipo que no esté en un
dominio?
Sí. La comunicación remota de PowerShell está disponible incluso cuando el equipo
local no está en un dominio. Puede usar las características de comunicación remota para
conectarse a sesiones y crear sesiones en el mismo equipo. Las características funcionan
igual que cuando se conecta a un equipo remoto.

Para ejecutar comandos remotos en un equipo de un grupo de trabajo, cambie la


siguiente configuración de Windows en el equipo.

Precaución: esta configuración afecta a todos los usuarios del sistema y puede hacer
que el sistema sea más vulnerable a un ataque malintencionado. Tenga cuidado al
realizar estos cambios.

Windows Vista, Windows 7, Windows 8:

Cree la siguiente entrada del Registro y, a continuación, establezca su valor en 1:


LocalAccountTokenFilterPolicy en
HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System

Puede usar el siguiente comando de PowerShell para agregar esta entrada:

PowerShell

$parameters = @{

Path='HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System'
Name='LocalAccountTokenFilterPolicy'
propertyType='DWord'
Value=1
}
New-ItemProperty @parameters

Windows Server 2003, Windows Server 2008, Windows Server 2012, Windows
Server 2012 R2:

No se necesitan cambios porque la configuración predeterminada del "Modelo de


acceso a la red: uso compartido y seguridad para cuentas locales" es "Clásico".
Compruebe la configuración en caso de que haya cambiado.

¿Puedo ejecutar comandos remotos en


un equipo de otro dominio?
Sí. Normalmente, los comandos se ejecutan sin errores, aunque es posible que tenga
que usar el parámetro Credential de los Invoke-Command cmdlets , New-PSSession o
Enter-PSSession para proporcionar las credenciales de un miembro del grupo
Administradores en el equipo remoto. Esto a veces es necesario incluso cuando el
usuario actual es miembro del grupo Administradores en los equipos locales y remotos.

Sin embargo, si el equipo remoto no está en un dominio en el que confía el equipo


local, es posible que el equipo remoto no pueda autenticar las credenciales del usuario.

Para habilitar la autenticación, use el siguiente comando para agregar el equipo remoto
a la lista de hosts de confianza para el equipo local en WinRM. Escriba el comando en el
símbolo del sistema de PowerShell.

PowerShell

Set-Item WSMan:\localhost\Client\TrustedHosts -Value <Remote-computer-name>

Por ejemplo, para agregar el equipo Server01 a la lista de hosts de confianza en el


equipo local, escriba el siguiente comando en el símbolo del sistema de PowerShell:

PowerShell

Set-Item WSMan:\localhost\Client\TrustedHosts -Value Server01

¿Admite PowerShell la comunicación


remota a través de SSH?
Sí. Para más información, consulte Comunicación remota de PowerShell a través de SSH.

Consulte también
about_Remote

about_Profiles

about_PSSessions

about_Remote_Jobs

about_Remote_Variables

Invoke-Command

New-PSSession
6 Collaborate with us on PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Características de seguridad de
PowerShell
Artículo • 06/10/2023

PowerShell tiene varias características diseñadas para mejorar la seguridad del entorno
de scripting.

Directiva de ejecución
La directiva de ejecución de PowerShell es una característica de seguridad que controla
las condiciones en las que PowerShell carga archivos de configuración y ejecuta scripts.
Esta característica ayuda a evitar la ejecución de scripts malintencionados. Puede usar
una configuración de directiva de grupo para establecer directivas de ejecución para
equipos y usuarios. Las directivas de ejecución solo se aplican a la plataforma Windows.

Para obtener más información, vea about_Execution_Policies.

Registro de módulos y bloques de scripts


El registro de módulos permite habilitar el registro de módulos de PowerShell
seleccionados. Este valor es eficaz en todas las sesiones del equipo. Los eventos de
ejecución de canalizaciones de los módulos especificados se registran en el registro de
Windows PowerShell en el Visor de eventos.

El registro de bloques de scripts habilita el registro para el procesamiento de comandos,


bloques de scripts, funciones y scripts, tanto si se invocan de forma interactiva como
mediante automatización. Esta información se registra en el registro de eventos
Microsoft-Windows-PowerShell/Operational.

Para más información, consulte los siguientes artículos.

about_Group_Policy_Settings
about_Logging_Windows
about_Logging_Non-Windows

Compatibilidad con AMSI


Windows Antimalware Scan Interface (AMSI) es una API que permite a las aplicaciones
pasar acciones a un escáner antimalware, como Windows Defender, para detectar
cargas malintencionadas. A partir de PowerShell 5.1, si PowerShell se ejecuta en
Windows 10 (y superior) pasa todos los bloques de script a AMSI.

PowerShell 7.3 amplía los datos que se envían a AMSI para su inspección. Ahora incluye
todas las invocaciones de miembros de método de .NET.

Para obtener más información sobre AMSI, consulte Cómo ayuda AMSI.

Modo de lenguaje restringido


El modo ConstrainedLanguage protege el sistema mediante la limitación de los cmdlets
y los tipos de .NET que se pueden usar en una sesión de PowerShell. Para obtener una
descripción completa, vea about_Language_Modes.

Control de la aplicación
Windows 10 incluye dos tecnologías, Control de aplicaciones de Windows Defender
(WDAC) y AppLocker, que se pueden usar para controlar aplicaciones. Estas tecnologías
permiten crear una experiencia de bloqueo que ayuda a proteger el entorno de
PowerShell.

Para más información sobre la forma en que PowerShell admite AppLocker y WDAC,
consulte Uso de Control de aplicaciones de Windows Defender.

Cambios en PowerShell 7.4


En Windows, cuando PowerShell se ejecuta en una directiva de Control de aplicaciones
de Windows Defender (WDAC), cambia su comportamiento en función de la directiva de
seguridad definida. En una directiva de WDAC, PowerShell ejecuta los scripts y módulos
de confianza que permite la directiva en modo Lenguaje completo. Los restantes scripts
y bloques de scripts no son de confianza y se ejecutan en modo Lenguaje restringido.
PowerShell genera errores cuando los scripts que no son de confianza intentan realizar
acciones no permitidas. Es difícil conocer los motivos por los que un script no se ejecuta
correctamente en el modo Lenguaje restringido.

PowerShell 7.4 ahora admite directivas WDAC en el modo Auditoría. En este modo,
PowerShell ejecuta los scripts que no son de confianza en el modo Lenguaje restringido,
pero registra los mensajes en el registro de eventos, en lugar de generar errores. Los
mensajes del registro describen qué restricciones se aplicarían si la directiva estuviera en
modo Aplicar.
Cambios en PowerShell 7.3
PowerShell 7.3 ahora admite la capacidad de bloquear o permitir archivos de script
de PowerShell a través de la API WDAC.

Cambios en PowerShell 7.2


Hay un caso extremo en AppLocker donde solo hay reglas de denegación y el
modo restringido no se usa para aplicar la directiva que permite omitir la directiva
de ejecución. A partir de PowerShell 7.2, se realizó un cambio para garantizar que
las reglas de AppLocker tuvieran prioridad sobre un comando Set-ExecutionPolicy
-ExecutionPolicy Bypass .

PowerShell 7.2 ahora no permite el uso del cmdlet Add-Type en una sesión de
PowerShell en modo NoLanguage en una máquina bloqueada.

PowerShell 7.2 ahora no permite que los scripts usen objetos COM en condiciones
de bloqueo del sistema de AppLocker. Los cmdlets que usan COM o DCOM
internamente no se ven afectados.

Criterios de servicio de seguridad


PowerShell sigue los criterios de servicio de seguridad de Microsoft para Windows . En
la tabla siguiente se describen las características que cumplen los criterios de servicio y
las que no lo hacen.

Característica Tipo

Bloqueo del sistema: con WDAC Característica de seguridad

Modo de lenguaje restringido: con WDAC Característica de seguridad

Bloqueo del sistema: con AppLocker Defensa en profundidad

Modo de lenguaje restringido: con AppLocker Defensa en profundidad

Directiva de ejecución Defensa en profundidad

Lista de materiales de software (SBOM)


A partir de PowerShell 7.2, todos los paquetes de instalación contiene una lista de
materiales de software (SBOM). La SBOM se encuentra en
$PSHOME/_manifest/spdx_2.2/manifest.spdx.json . Crear y publicar la SBOM es el primer
paso para modernizar la ciberseguridad del Gobierno federal y mejorar la seguridad de
la cadena de suministros de software.

El equipo de PowerShell también está produciendo SBOM para los módulos que son
suyos pero se envían fuera de PowerShell. Las SBOM se añadirán en la siguiente versión
del módulo. En el caso de los módulos, la SBOM se instala en la carpeta del módulo que
hay en _manifest/spdx_2.2/manifest.spdx.json .

Para obtener más información sobre esta iniciativa, vea la entrada de blog Generating
Software Bills of Materials (SBOMs) with SPDX at Microsoft (Generación de listas de
materiales de software [SBOM] con SPDX en Microsoft).

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Uso de Control de aplicaciones de
Windows Defender
Artículo • 01/06/2023

Windows 10 incluye dos tecnologías, Control de aplicaciones de Windows Defender


(WDAC) y AppLocker, que se pueden usar para controlar aplicaciones. Estas tecnologías
permiten crear una experiencia de bloqueo que ayuda a proteger el entorno de
PowerShell.

AppLocker se basa en las características de control de aplicaciones de las directivas de


restricción de software. AppLocker contiene funcionalidades y extensiones que permiten
crear reglas para permitir o denegar la ejecución de aplicaciones en función de
identidades únicas de archivos y especificar qué usuarios o grupos tienen permiso para
ejecutar esas aplicaciones.

7 Nota

Si hay que elegir entre WDAC o AppLocker, es aconsejable implementar el control


de aplicaciones mediante WDAC, en lugar de AppLocker. Microsoft mejora
constantemente WDAC y las plataformas de administración de Microsoft están
ampliando su compatibilidad con WDAC. Aunque AppLocker puede seguir
recibiendo correcciones de seguridad, sus características ya no recibirán mejoras.

WDAC se incorporó con Windows 10 y permite a las organizaciones controlar los


controladores y aplicaciones que pueden ejecutarse en sus dispositivos Windows. MDAC
está diseñado como una característica de seguridad según los criterios de
mantenimiento definidos por el Centro de respuestas de seguridad de Microsoft
(MSRC).

Para más información sobre AppLocker y WDAC, consulte Controles de la aplicación


para Windows y Disponibilidad de características de AppLocker y WDAC.

Aplicación de directivas de WDAC


Cuando PowerShell se ejecuta en una directiva de WDAC, cambia su comportamiento en
función de la directiva de seguridad definida. En una directiva de WDAC, PowerShell
ejecuta los scripts y módulos de confianza que permite la directiva en modo Lenguaje
completo. Los restantes scripts y bloques de scripts no son de confianza y se ejecutan
en modo Lenguaje restringido. PowerShell genera errores cuando los scripts que no son
de confianza intentan realizar acciones que no se permiten en modo Lenguaje
restringido. Puede ser complicado conocer los motivos por los que un script no se ha
ejecutado correctamente en modo Lenguaje restringido.

Auditoría de directivas de WDAC


En PowerShell 7.4-preview.4, se agregó una nueva característica experimental,
PSConstrainedAuditLogging . Al habilitar esta característica, PowerShell admite directivas
WDAC en modo Auditoría. En este modo, PowerShell ejecuta sin errores los scripts que
no son de confianza en el modo Lenguaje restringido, pero registra los mensajes en el
registro de eventos en su lugar. Los mensajes del registro describen qué restricciones se
aplicarían si la directiva estuviera en modo Aplicar.

Visualización de eventos de auditoría


PowerShell registra los eventos de auditoría en el registro de eventos
PowerShellCore/Analytic. El registro Analytic se debe habilitar. Para habilitar este
registro en la Visor de eventos de Windows, haga clic con el botón derecho en el
registro PowerShellCore/Analytic y seleccione Habilitar registro.

Otra opción es ejecutar el siguiente comando desde una sesión de PowerShell con
privilegios elevados.

PowerShell

wevtutil.exe sl PowerShellCore/Analytic /enabled:true /quiet

Puede ver los eventos en el Visor de eventos de Windows o usar el cmdlet Get-WinEvent
para recuperar los eventos.

PowerShell

Get-WinEvent -LogName PowerShellCore/Analytic -Oldest |


Where-Object Id -eq 16387 | Format-List

Output

TimeCreated : 4/19/2023 10:11:07 AM


ProviderName : PowerShellCore
Id : 16387
Message : WDAC Audit.

Title: Method or Property Invocation


Message: Method or Property 'WriteLine' on type 'System.Console'
invocation will not
be allowed in ConstrainedLanguage mode.
At C:\scripts\Test1.ps1:3 char:1
+ [System.Console]::WriteLine("pwnd!")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
FullyQualifiedId: MethodOrPropertyInvocationNotAllowed

El mensaje de evento incluye la posición del script en que se aplicaría la restricción. Esta
información le ayuda a saber dónde debe cambiar el script para que se ejecute en la
directiva de WDAC.

) Importante

Una vez que haya revisado los eventos de auditoría, debe deshabilitar el registro
Analytic. Los registros Analytic crecen rápidamente y consumen grandes cantidades
de espacio en disco.

Visualización de eventos de auditoría en el depurador de


PowerShell
Si establece la variable $DebugPreference en Break para una sesión interactiva de
PowerShell, PowerShell interrumpirá el depurador de scripts de línea de comandos en la
ubicación actual del script en que se produjo el evento de auditoría, lo que le permite
depurar el código e inspeccionar el estado actual del script en tiempo real.
Uso de características experimentales en
PowerShell
Artículo • 29/09/2023

La compatibilidad con las características experimentales de PowerShell proporciona un


mecanismo para que las características experimentales coexistan con las características
estables existentes en PowerShell o los módulos de PowerShell.

Una característica experimental es aquella en la que el diseño no ha finalizado. La


característica está disponible para que los usuarios puedan probar y proporcionar
comentarios. Una vez finalizada una característica experimental, los cambios de diseño
se vuelven importantes.

U Precaución

No está previsto que las características experimentales se usen en producción, ya


que los cambios se pueden interrumpir. Las características experimentales no
cuentan con soporte técnico oficial. Sin embargo, agradecemos los comentarios y
los informes de errores. Puede informar de las incidencias en el repositorio de
origen de GitHub .

Para obtener más información acerca de cómo habilitar o deshabilitar estas


características, vea Acerca de las características experimentales.

Características disponibles
En este artículo se describen las características experimentales que están disponibles y
cómo usarlas.

Leyenda

El icono indica que la característica experimental está disponible en la versión


de PowerShell
El icono indica la versión de PowerShell donde la característica experimental ya
es estándar
El icono indica la versión de PowerShell donde la característica experimental se
ha eliminado
Nombre 7.2 7.3 7.4

PSCommandNotFoundSuggestion

PSDesiredStateConfiguration.InvokeDscResource (DSC v2)

PSNativePSPathResolution

PSSubsystemPluginModel

PSNativeCommandArgumentPassing

PSAnsiRenderingFileInfo

PSLoadAssemblyFromNativeCode

PSNativeCommandErrorActionPreference

PSCustomTableHeaderLabelDecoration

PSFeedbackProvider

PSModuleAutoLoadSkipOfflineFiles

PSCommandWithArgs

PSConstrainedAuditLogging

PSNativeCommandPreserveBytePipe

PSWindowsNativeCommandArgPassing

PSAnsiRenderingFileInfo

7 Nota

Esta característica se convirtió en estándar en PowerShell 7.3.

Este experimento se agregó en PowerShell 7.2. Esta característica agrega el miembro


$PSStyle.FileInfo y permite colorear tipos de archivo específicos.

$PSStyle.FileInfo.Directory : miembro integrado para especificar el color de los


directorios.
$PSStyle.FileInfo.SymbolicLink : miembro integrado para especificar el color de

los vínculos simbólicos.


$PSStyle.FileInfo.Executable : miembro integrado para especificar el color de los

ejecutables.
$PSStyle.FileInfo.Extension : use este miembro para definir colores para

diferentes extensiones de archivo. El miembro Extension incluye previamente


extensiones para archivar y para archivos de PowerShell.

Para obtener más información, vea about_Automatic_Variables.

7 Nota

Esta característica depende de la característica PSAnsiRendering que ahora es una


característica estándar.

PSCommandNotFoundSuggestion
Recomienda comandos potenciales basados en la búsqueda de coincidencias
aproximadas después de CommandNotFoundException.

PowerShell

PS> get

Output

get: The term 'get' isn't recognized as the name of a cmdlet, function,
script file,
or operable program. Check the spelling of the name, or if a path was
included, verify
that the path is correct and try again.

Suggestion [4,General]: The most similar commands are: set, del, ft, gal,
gbp, gc, gci,
gcm, gdr, gcs.

PSCommandWithArgs
Esta característica habilita el parámetro -CommandWithArgs para pwsh . Este parámetro
permite ejecutar un comando de PowerShell con argumentos. A diferencia de -Command ,
este parámetro rellena la variable integrada $args que el comando puede usar.

La primera cadena es el comando y las cadenas subsiguientes delimitadas por espacios


en blanco son los argumentos.

Por ejemplo:
PowerShell

pwsh -CommandWithArgs '$args | % { "arg: $_" }' arg1 arg2

Este ejemplo produce el siguiente resultado:

Output

arg: arg1
arg: arg2

Esta característica se agregó en PowerShell 7.4.preview.2.

PSConstrainedAuditLogging

7 Nota

Esta característica se convirtió en estándar en PowerShell 7.4.preview-6.

En Windows, cuando PowerShell se ejecuta en una directiva de Control de aplicaciones


de Windows Defender (WDAC), cambia su comportamiento en función de la directiva de
seguridad definida. En una directiva de WDAC, PowerShell ejecuta los scripts y módulos
de confianza que permite la directiva en modo Lenguaje completo. Los restantes scripts
y bloques de scripts no son de confianza y se ejecutan en modo Lenguaje restringido.
PowerShell genera errores cuando los scripts que no son de confianza intentan realizar
acciones no permitidas. Es difícil conocer los motivos por los que un script no se ejecuta
correctamente en el modo Lenguaje restringido.

Si se habilitar la característica experimental PSConstrainedAuditLogging , PowerShell


admite directivas de WDAC en modo Auditoría. En este modo, PowerShell ejecuta los
scripts que no son de confianza en el modo Lenguaje restringido, pero registra los
mensajes en el registro de eventos, en lugar de generar errores. Los mensajes del
registro describen qué restricciones se aplicarían si la directiva estuviera en modo
Aplicar.

Esta característica se agregó en PowerShell 7.4.preview.4.

PSCustomTableHeaderLabelDecoration

7 Nota
Esta característica se convirtió en estándar en PowerShell 7.4.preview-6.

Cuando esta característica está habilitada, $PSStyle incluye la diferenciación de formato


para las etiquetas de encabezado de tabla que no son miembros de propiedad. Por
ejemplo, la salida predeterminada de Get-Process incluye las columnas siguientes:
NPM(K) , PM(M) , WS(M) , y CPU(s) .

PowerShell

Get-Process pwsh

Output

NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName


------ ----- ----- ------ -- -- -----------
99 84.57 170.50 5.89 48688 1 pwsh
73 87.75 133.08 3.09 49120 1 pwsh
98 70.31 158.56 4.23 91220 1 pwsh
125 70.19 171.33 4.84 92124 1 pwsh

Estos nombres de columna no coinciden con ninguna propiedad del objeto


System.Diagnostics.Process devuelto por el cmdlet. Estos son valores calculados por el
sistema de formato de PowerShell.

Con esta característica habilitada, estos encabezados de columna se muestran en cursiva


para distinguir estos nombres de columna de los nombres de propiedad.

PSDesiredStateConfiguration.InvokeDscResource
Habilita la compilación en MOF en sistemas que no son de Windows y permite el uso de
Invoke-DSCResource sin LCM.

En versiones preliminares anteriores de PowerShell 7.2, esta característica estaba


habilitada de manera predeterminada. A partir de PowerShell 7.2, se quitó el módulo
PSDesiredStateConfiguration y esta característica está deshabilitada de manera
predeterminada. Para habilitar esta característica, debe instalar el módulo
PSDesiredStateConfiguration v2.0.5 desde la Galería de PowerShell y habilitarla
mediante Enable-ExperimentalFeature .

DSC v3 no tiene esta característica experimental. DSC v3 solo admite Invoke-


DSCResource y no usa ni admite la compilación MOF. Para obtener más información, vea

Desired State Configuration v3 de PowerShell.


PSFeedbackProvider
Al habilitar esta característica, PowerShell usa un nuevo proveedor de comentarios para
proporcionarle comentarios cuando no se encuentra un comando. El proveedor de
comentarios es extensible y se puede implementar mediante módulos de terceros. Otros
subsistemas, como el subsistema de predicción, pueden usar el proveedor de
comentarios para proporcionar resultados predictivos de IntelliSense.

Esta característica incluye dos proveedores de comentarios integrados:

GeneralCommandErrorFeedback sirve para la misma funcionalidad de sugerencia


existente en la actualidad

UnixCommandNotFound, disponible en Linux, proporciona comentarios similares


a Bash.

UnixCommandNotFound actúa como proveedor de comentarios y un predictor.


La sugerencia del comando no encontrado se usa para proporcionar los
comentarios cuando el comando no se encuentra en una ejecución interactiva y
para proporcionar resultados predictivos de IntelliSense para la siguiente línea de
comandos.

PSLoadAssemblyFromNativeCode
Expone una API para permitir la carga de ensamblados desde código nativo.

PSModuleAutoLoadSkipOfflineFiles
Con esta característica habilitada, si PSModulePath de un usuario contiene una carpeta
de un proveedor de nube, como OneDrive, PowerShell ya no desencadena la descarga
de todos los archivos contenidos en esa carpeta. Se omite cualquier archivo marcado
como no descargado. Los usuarios que usan proveedores de nube para sincronizar sus
módulos entre máquinas deben marcar la carpeta de módulos como Anclada o en el
estado equivalente para proveedores distintos de OneDrive. Al marcar la carpeta de
módulos como Anclada se garantiza que los archivos siempre se mantienen en el disco.

PSNativeCommandArgumentPassing

7 Nota
Esta característica se convirtió en estándar en PowerShell 7.3.

Cuando esta característica experimental está habilitada, PowerShell usa la propiedad


ArgumentList del objeto StartProcessInfo en lugar de nuestro mecanismo actual de

reconstrucción de una cadena al invocar un ejecutable nativo.

U Precaución

Este nuevo comportamiento supone un cambio importante respecto al


comportamiento actual. Puede provocar la interrupción de los scripts y la
automatización que se usan como soluciones alternativas para diferentes
problemas al invocar aplicaciones nativas. Hasta ahora, las comillas debían
escaparse, y no es posible proporcionar argumentos vacíos a una aplicación nativa.
Use el token stop-parsing ( --% ) o el cmdlet para omitir el Start-Process paso de
argumentos nativos cuando sea necesario.

Esta característica agrega una nueva variable de preferencia


$PSNativeCommandArgumentPassing que controla este comportamiento. Esta variable

permite seleccionar el comportamiento durante el runtime. Los valores válidos son


Legacy , Standard y Windows . El comportamiento predeterminado es específico de cada

plataforma. En plataformas Windows la configuración predeterminada es Windows y las


plataformas no Windows adoptan el valor predeterminado Standard .

Legacy es el comportamiento que se ha usado hasta ahora. El comportamiento de los

modos Windows y Standard es el mismo con la excepción de que, en modo Windows , las
invocaciones de los archivos siguientes usan automáticamente el paso de argumentos
de estilo Legacy .

cmd.exe
find.exe

cscript.exe
wscript.exe

sqlcmd.exe - Agregado en PowerShell 7.3.1

termina en .bat
termina en .cmd
termina en .js
termina en .vbs
termina en .wsf
Si $PSNativeCommandArgumentPassing se establece en Legacy o Standard , el analizador
no comprueba estos archivos.

El comportamiento predeterminado es específico de cada plataforma. En plataformas


Windows la configuración predeterminada es Windows y en plataformas no Windows
Standard .

7 Nota

Los ejemplos siguientes usan la herramienta TestExe.exe . Puede compilar TestExe


a partir del código fuente. Consulte TestExe en el repositorio de origen de
PowerShell.

Nuevos comportamientos disponibles con este cambio:

Las cadenas literales o expandibles con comillas insertadas se conservan:

PowerShell

PS> $a = 'a" "b'


PS> TestExe -echoargs $a 'c" "d' e" "f
Arg 0 is <a" "b>
Arg 1 is <c" "d>
Arg 2 is <e f>

Las cadenas vacías usadas como argumentos se conservan:

PowerShell

PS> TestExe -echoargs '' a b ''


Arg 0 is <>
Arg 1 is <a>
Arg 2 is <b>
Arg 3 is <>

Para obtener más ejemplos del nuevo comportamiento, consulte about_Parsing.

PowerShell 7.3 también agregó la capacidad de realizar un seguimiento del enlace de


parámetros para comandos nativos. Para más información, vea Trace-Command.

PSNativeCommandErrorActionPreference

7 Nota
Esta característica se convirtió en estándar en PowerShell 7.4.preview-6.

Los comandos nativos normalmente devuelven un código de salida a la aplicación que


realiza la llamada, que es de cero en caso de éxito o distinto de cero en caso de error.
Sin embargo, los comandos nativos no participan actualmente en el flujo de errores de
PowerShell. La salida redirigida de stderr no se interpreta de la misma forma que el flujo
de errores de PowerShell. Muchos comandos nativos usan stderr como un flujo de
información o detallado, por lo que solo importa el código de salida. Los usuarios que
trabajan con comandos nativos en sus scripts deben comprobar el estado de salida
después de cada llamada con un ejemplo similar al siguiente:

PowerShell

if ($LASTEXITCODE -ne 0) {
throw "Command failed. See above errors for details"
}

Sin embargo, este ejemplo no admite todos los casos en los que $? puede ser "false"
procedente de un error de cmdlet o de función, lo que hace que $LASTEXITCODE sea
obsoleto.

Esta característica implementa la variable de preferencia


$PSNativeCommandUseErrorActionPreference que controla cómo se controlan los errores

de comandos nativos en PowerShell. De esta forma, los errores de comandos nativos


producen objetos de error que se agregan al flujo de errores de PowerShell y puede
terminar la ejecución del script sin control adicional.

Para habilitar esta característica, ejecute los siguientes comandos:

PowerShell

Enable-ExperimentalFeature PSNativeCommandErrorActionPreference

Debe iniciar una nueva sesión de PowerShell para que se aplique este cambio. A partir
de PowerShell 7.4, $PSNativeCommandUseErrorActionPreference se establece en $true de
forma predeterminada. Con la preferencia establecida en $true , se obtiene el siguiente
comportamiento:

Cuando $ErrorActionPreference = 'Stop' , los scripts se interrumpirán cuando un


comando nativo devuelva un código de salida distinto de cero.
Cuando $ErrorActionPreference = 'Continue' (opción predeterminada), verá
mensajes de error de PowerShell para errores de comandos nativos, pero los
scripts no se interrumpirán.

PSNativeCommandPreserveBytePipe

7 Nota

Esta característica se convirtió en estándar en PowerShell 7.4.preview-6.

Esta característica conserva los datos de secuencia de bytes al redirigir la secuencia


stdout de un comando nativo a un archivo o al canalización de datos de secuencia de
bytes al flujo stdin de un comando nativo.

Por ejemplo, con el comando nativo curl puede descargar un archivo binario y
guardarlo en el disco mediante el redireccionamiento.

PowerShell

$uri =
'https://github.com/PowerShell/PowerShell/releases/download/v7.3.4/powershel
l-7.3.4-linux-arm64.tar.gz'

# native command redirected to a file


curl -s -L $uri > powershell.tar.gz

También puede canalizar los datos de secuencia de bytes a la secuencia stdin de otro
comando nativo. En el ejemplo siguiente se descarga un archivo TAR comprimido
mediante curl . Los datos de archivo descargados se transmiten al comando tar para
extraer el contenido del archivo.

PowerShell

# native command output piped to a native command


curl -s -L $uri | tar -xzvf - -C .

También puede canalizar la salida de flujo de bytes de un comando de PowerShell a la


entrada del comando nativo. En los ejemplos siguientes se usa Invoke-WebRequest para
descargar el mismo archivo TAR que el ejemplo anterior.

PowerShell

# byte stream piped to a native command


(Invoke-WebRequest $uri).Content | tar -xzvf - -C .
# bytes piped to a native command (all at once as byte[])
,(Invoke-WebRequest $uri).Content | tar -xzvf - -C .

Esta característica no admite datos de secuencia de bytes al redirigir la salida stderr a


stdout. Al combinar las secuencias stderr y stdout, las secuencias combinadas se tratan
como datos de cadena.

La característica experimental se introdujo en PowerShell 7.4 preview 4.

PSNativePSPathResolution

7 Nota

Esta característica experimental se quitó en PowerShell 7.3 y ya no se admite.

Si una ruta de acceso de PSDrive que usa el proveedor de sistema de archivos se pasa a
un comando nativo, la ruta de acceso del archivo resuelta se pasa al comando nativo.
Esto significa que un comando como code temp:/test.txt funciona ahora como se
esperaba.

Además, en Windows, si la ruta de acceso comienza con ~ , se resuelve en la ruta de


acceso completa y se pasa al comando nativo. En ambos casos, la ruta de acceso se
normaliza en los separadores de directorio para el sistema operativo correspondiente.

Si la ruta de acceso no es un parámetro PSDrive o ~ (en Windows), no se produce


la normalización de la ruta de acceso.
Si la ruta de acceso está entre comillas simples, no se resuelve y se trata como
literal.

PSSubsystemPluginModel
Esta característica habilita el modelo de complemento de subsistema en PowerShell. La
característica permite separar componentes de System.Management.Automation.dll en
subsistemas individuales que residen en su propio ensamblado. Esta separación reduce
la superficie de memoria del disco del motor de PowerShell principal y permite que
estos componentes se conviertan en características opcionales para una instalación
mínima de PowerShell.

Actualmente, solo se admite el subsistema CommandPredictor. Este subsistema se usa


junto con el módulo PSReadLine para proporcionar complementos de predicción
personalizados. En el futuro, Job, CommandCompleter, Remoting y otros componentes
podrían separarse en ensamblados de subsistema fuera de
System.Management.Automation.dll .

La característica experimental incluye un nuevo cmdlet, Get-PSSubsystem. Este cmdlet


solo está disponible cuando la característica está habilitada y devuelve información
sobre los subsistemas que están disponibles en el sistema.

PSWindowsNativeCommandArgPassing

7 Nota

Esta característica se convirtió en estándar en PowerShell 7.4.preview-6.

La característica cambia los valores predeterminados de la variable


$PSNativeCommandArgumentPassing .

Al habilitar esta característica en Windows, $PSNativeCommandArgumentPassing se


establece en Windows .
Al habilitar esta característica en plataformas que no son de Windows,
$PSNativeCommandArgumentPassing se establece en Standard .

Al deshabilitar esta característica en Windows, $PSNativeCommandArgumentPassing se


establece en Legacy .
Al deshabilitar esta característica en plataformas que no son de Windows,
$PSNativeCommandArgumentPassing se establece en Standard .

Además, esta característica agrega nuevas métricas de telemetría para informarnos de


cómo se usa la característica.

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Uso de alias
Artículo • 13/04/2023

Un alias es un nombre alternativo o un nombre abreviado para un cmdlet o para un


elemento de comando, como una función, un script, un archivo o un archivo ejecutable.
Puede ejecutar el comando con el alias en lugar del nombre ejecutable.

Administración de alias de comandos


PowerShell proporciona cmdlets para administrar alias de comandos.

PowerShell

Get-Command -Noun Alias

Output

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Export-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Get-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Import-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet New-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Remove-Alias 7.0.0.0 Microsoft.PowerShell.Utility
Cmdlet Set-Alias 7.0.0.0 Microsoft.PowerShell.Utility

Para más información, vea about_Aliases.

Use el cmdlet Get-Alias para enumerar los alias disponibles en el entorno. Para
enumerar los alias de un único cmdlet, use el parámetro Definition y especifique el
nombre ejecutable.

PowerShell

Get-Alias -Definition Get-ChildItem

Output

CommandType Name
----------- ----
Alias dir -> Get-ChildItem
Alias gci -> Get-ChildItem
Alias ls -> Get-ChildItem
Para obtener la definición de un único alias, use el parámetro Name.

PowerShell

Get-Alias -Name gci

Output

CommandType Name
----------- ----
Alias gci -> Get-ChildItem

Alias de compatibilidad en Windows


PowerShell tiene varios alias que permiten a los usuarios de UNIX y cmd.exe utilizar
comandos familiares en Windows. En la tabla siguiente se muestran comandos
comunes, el cmdlet de PowerShell relacionado y el alias de PowerShell:

Comando Comando de Cmdlet de Alias de PowerShell


cmd.exe UNIX PowerShell

cd, chdir cd Set-Location sl , cd , chdir

cls eliminar Clear-Host cls clear

copy cp Copy-Item cpi , cp , copy

del, erase, rd, rm Remove-Item ri , del , erase , rd , rm ,


rmdir rmdir

dir ls Get-ChildItem gci , dir , ls

echo echo Write-Output write echo

md mkdir New-Item ni

move mv Move-Item mi , move , mi

popd popd Pop-Location popd

pwd Get-Location gl , pwd

pushd pushd Push-Location pushd

ren mv Rename-Item rni , ren

type cat Get-Content gc , cat , type


7 Nota

Los alias de esta tabla son específicos de Windows. Algunos alias no están
disponibles en otras plataformas. Esto es así para permitir que el comando nativo
funcione en una sesión de PowerShell. Por ejemplo, ls no se define como un alias
de PowerShell en macOS ni Linux, por lo que en lugar de Get-ChildItem se ejecuta
el comando nativo.

Creación de nombres alternativos para


comandos con parámetros
Puede asignar un alias a un cmdlet, script, función o archivo ejecutable. A diferencia de
algunos shells de Unix, no se puede asignar un alias a un comando con parámetros. Por
ejemplo, puede asignar un alias al cmdlet Get-Eventlog , pero no al comando Get-
Eventlog -LogName System . Tendrá que crear una función que contenga el comando con

parámetros.

Para más información, vea about_Aliases.

Alias de parámetro y nombres abreviados


PowerShell también proporciona maneras de crear nombres abreviados para
parámetros. Los alias de parámetro se definen mediante el atributo Alias al declarar el
parámetro. No se pueden definir mediante los cmdlets *-Alias .

Para más información, vea la documentación del atributo de alias.

Además de los alias de parámetro, PowerShell permite especificar el nombre del


parámetro con la menor cantidad de caracteres necesarios para identificar de forma
única el parámetro. Por ejemplo, el cmdlet Get-ChildItem tiene los parámetros Recurse
y ReadOnly. Para identificar de forma única el parámetro Recurse, solo debe
proporcionar -rec . Si lo combina con el alias de comando, Get-ChildItem -Recurse se
puede abreviar como dir -rec .

No usar alias en scripts


Los alias son una característica de conveniencia para usar de forma interactiva en el
shell. Siempre debe usar los nombres de parámetros y comandos completos en los
scripts.

Los alias se pueden eliminar o redefinir en un script de perfil


Es posible que los alias que defina no estén disponibles para el usuario de los
scripts
Los alias hacen que el código sea más difícil de leer y mantener

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Recursos de aprendizaje de PowerShell
Artículo • 13/04/2023

Recursos adicionales para aprender sobre PowerShell.

Módulos de aprendizaje
Microsoft Learn es una plataforma gratuita de cursos en línea que ofrece aprendizaje
interactivo de los productos de Microsoft y mucho más. Nuestro objetivo es ayudarle a
convertirse en un experto en nuestras tecnologías y a aprender más aptitudes gracias a
un contenido divertido, guiado, práctico e interactivo específico para su rol y sus
objetivos.

Módulos de PowerShell

Blogs y comunidad
Además de la Ayuda disponible en la línea de comandos, los siguientes recursos aportan
más información a los usuarios que quieran ejecutar PowerShell.

Blog del equipo de PowerShell . El mejor recurso para aprender directamente del
equipo de producto de PowerShell.
Los artículos del blog de PowerShell Community se basan en escenarios. Escritos
por la comunidad, para la comunidad.
¿Tiene alguna pregunta sobre cómo usar PowerShell? Conéctese con cientos de
otros usuarios con intereses similarese n uno de los muchos foros de la comunidad
que aparecen en la página de la comunidad de PowerShell.

Microsoft Virtual Academy


Los vídeos de Microsoft Virtual Academy se movieron a Channel 9.

Getting Started with Microsoft PowerShell (Introducción a Microsoft PowerShell)


Advanced Tools & Scripting with PowerShell 3.0 Jump Start (Introducción a las
herramientas avanzadas y el scripting con PowerShell 3.0)
Testing PowerShell with Pester (Prueba de PowerShell con Pester)
Getting Started with PowerShell Desired State Configuration (DSC) (Introducción a
la configuración de estado deseado (DSC) de PowerShell)
Advanced PowerShell DSC and Custom Resources (Configuración de estado
deseado (DSC) avanzado y recursos personalizados de PowerShell)
SharePoint Automation with DSC (Automatización de SharePoint con DSC)

Recursos para desarrolladores de PowerShell


Los siguientes recursos sirven para ayudar a los desarrolladores a crear sus propios
módulos, funciones, cmdlets, proveedores y aplicaciones de hospedaje de PowerShell.

SDK de PowerShell
PowerShell SDK API Browser (Explorador de la API del SDK de PowerShell)
Glosario de PowerShell
Artículo • 13/04/2023

En este artículo se enumeran los términos comunes que se usan para hablar sobre
PowerShell.

módulo binario
Módulo de PowerShell cuyo módulo raíz es un archivo binario ( .dll ). Un módulo
binario puede o no incluir un manifiesto de módulo.

CommonParameter
Parámetro que el motor de PowerShell agrega a todos los cmdlets, a las funciones
avanzadas y a los flujos de trabajo.

usar el operador punto


En PowerShell, para iniciar un comando escribiendo un punto y un espacio antes del
comando. Los comandos que usan el operador punto se ejecutan en el ámbito actual en
lugar de en un nuevo ámbito. Las variables, los alias, las funciones o las unidades que
crea el comando se crean en el ámbito actual y están disponibles para los usuarios
cuando se completa el comando.

módulo dinámico
Módulo que solo existe en memoria. Los cmdlets New-Module y Import-PSSession crean
módulos dinámicos.

parámetro dinámico
Parámetro que se agrega a un cmdlet, una función o un script de PowerShell en
determinadas condiciones. Los cmdlets, las funciones, los proveedores y los scripts
pueden agregar parámetros dinámicos.

archivo de formato
Archivo XML de PowerShell con la extensión .format.ps1xml que define cómo
PowerShell muestra un objeto según su tipo de .NET Framework.

estado de sesión global


Estado de sesión que contiene los datos que son accesibles para el usuario de una
sesión de PowerShell.

Host
Interfaz que el motor de PowerShell usa para comunicarse con el usuario. Por ejemplo,
el host especifica cómo se controlan los mensajes entre PowerShell y el usuario.

aplicación host
Programa que carga el motor de PowerShell en su proceso y lo usa para realizar
operaciones.

método de procesamiento de entrada


Método que un cmdlet puede usar para procesar los registros que recibe como entrada.
Los métodos de procesamiento de entrada incluyen los métodos BeginProcessing ,
ProcessRecord , EndProcessing y StopProcessing .
M

módulo de manifiesto
Módulo de PowerShell que tiene un manifiesto y cuya clave RootModule está vacía.

enumeración de acceso a miembros


Una característica conveniente de PowerShell para enumerar automáticamente los
elementos de una colección cuando se utiliza el operador de acceso a miembros ( . ).

module
Unidad reutilizable independiente que permite la partición, la organización y el resumen
del código de PowerShell. Un módulo puede contener cmdlets, proveedores, funciones,
variables y otros tipos de recursos que pueden importarse como una sola unidad.

manifiesto de módulo
Archivo de datos de PowerShell ( .psd1 ) que describe el contenido de un módulo y que
controla cómo se procesa un módulo.

estado de sesión del módulo


Estado de sesión que contiene los datos públicos y privados de un módulo de
PowerShell. Los datos privados en este estado de sesión no están disponibles para el
usuario de una sesión de PowerShell.

error de no terminación
Error que no impide que PowerShell continúe procesando el comando.

nombre
Palabra que sigue al guion en un nombre de cmdlet de PowerShell. El nombre describe
los recursos en los que actúa el cmdlet.
P

conjunto de parámetros
Grupo de parámetros que pueden usarse en el mismo comando para realizar una acción
específica.

canalizar
En PowerShell, para enviar los resultados del comando anterior como entrada para el
comando siguiente en la canalización.

pipeline
Serie de comandos conectados mediante operadores de canalización ( | ). Cada
operador de canalización envía los resultados del comando anterior como entrada para
el comando siguiente.

Cmdlet de PowerShell
Un único comando que participa en la semántica de canalización de PowerShell. Aquí se
incluyen cmdlets binarios (C#), funciones de script avanzadas, CDXML y flujos de trabajo.

Comando de PowerShell
Elemento de una canalización que provocan que se lleve a cabo una acción. Los
comandos de PowerShell se escriben con el teclado o se invocan mediante
programación.

Archivo de datos de PowerShell


Archivo de texto que tiene la extensión de archivo .psd1 . PowerShell usa los archivos de
datos para distintos propósitos, como almacenar datos de manifiesto de módulo y
almacenar cadenas traducidas para la internacionalización del script.

Unidad de PowerShell
Unidad virtual que proporciona acceso directo a un almacén de datos. La puede definir
un proveedor de PowerShell o se puede crear en la línea de comandos. Las unidades
creadas en la línea de comandos son unidades específicas de la sesión y se pierden
cuando se cierra la sesión.

provider
Programa basado en Microsoft .NET Framework que hace que los datos de un almacén
de datos especializado estén disponibles en PowerShell, de modo que pueda verlos y
administrarlos.

PSSession
Tipo de sesión de PowerShell que crea, administra y cierra el usuario.

módulo raíz
Módulo especificado en la clave RootModule en un manifiesto de módulo.

espacio de ejecución
En PowerShell, entorno operativo en el que se ejecuta cada comando de una
canalización.

bloque de script
En el lenguaje de programación de PowerShell, colección de instrucciones o expresiones
que se pueden usar como una sola unidad. Un bloque de script puede aceptar
argumentos y valores devueltos.

archivo de script
Archivo que tiene la extensión .ps1 y que contiene un script escrito en el lenguaje de
PowerShell.

módulo de script
Módulo de PowerShell cuyo módulo raíz es un archivo de módulo de script ( .psm1 ). Un
módulo de script puede incluir un manifiesto de módulo. El script define los miembros
que exporta el módulo de script.

shell
Intérprete de comandos que se usa para pasar comandos al sistema operativo.

parámetro de modificador
Parámetro que no adopta un argumento. El valor de un parámetro switch tiene $false
como valor predeterminado. Cuando se usa un parámetro switch, su valor se convierte
en $true .

error de terminación
Error que impide que PowerShell termine de procesar el comando.

transaction
Unidad atómica de trabajo. El trabajo de una transacción debe completarse en conjunto.
Si se produce un error en alguna parte de la transacción, se produce un error en toda la
transacción.

archivo de tipo
Archivo XML de PowerShell que tiene la extensión .types.ps1xml y que extiende las
propiedades de los tipos de Microsoft .NET Framework en PowerShell.

Verbo
Palabra que precede al guion en un nombre de cmdlet de PowerShell. El verbo describe
la acción que realiza el cmdlet.
W

Windows PowerShell ISE


Entorno de scripting integrado (ISE): aplicación host de Windows PowerShell que
permite ejecutar comandos, así como escribir, probar y depurar scripts en un sencillo
entorno con color de sintaxis compatible con Unicode.

Complemento de Windows PowerShell


Recurso que define un conjunto de cmdlets, proveedores y tipos de Microsoft .NET
Framework que se pueden agregar al entorno de Windows PowerShell.

Flujo de trabajo de Windows PowerShell


Un flujo de trabajo es una secuencia de pasos conectados y programados que realizan
tareas de larga duración o requieren de la coordinación de pasos múltiples a través de
varios dispositivos o nodos administrados. El flujo de trabajo de Windows PowerShell
permite a los desarrolladores y profesionales de TI crear secuencias de actividades de
administración de varios dispositivos o tareas únicas dentro de un flujo de trabajo,
como flujos de trabajo. El flujo de trabajo de Windows PowerShell permite adaptar y
ejecutar scripts de PowerShell y archivos XAML como flujos de trabajo.
Información general sobre las
novedades de PowerShell
Colección de notas de la versión y documentación sobre las nuevas características
disponibles en las nuevas versiones de PowerShell.

Novedades de PowerShell 7

h NOVEDADES

Novedades de PowerShell 7.3 (versión preliminar)

Novedades de PowerShell 7.2 (LTS)

Novedades de PowerShell 7.1 (fuera de soporte técnico)

Novedades de PowerShell 7.0

Diferencias de PowerShell en plataformas diferentes de Windows

Novedades de PowerShell 5.1

h NOVEDADES

Novedades de PowerShell 5.1

Diferencias entre Windows PowerShell 5.1 y PowerShell 7

Migración de Windows PowerShell 5.1 a PowerShell 7

Historial y compatibilidad

h NOVEDADES

Historial de versiones de módulos y cmdlets

Compatibilidad de módulos

Novedades de las versiones anteriores de PowerShell


h NOVEDADES

Novedades de PowerShell 6.2

Novedades de PowerShell 6.1

Novedades de PowerShell 6.0

Cambios importantes en PowerShell 6.0

Problemas conocidos en PowerShell 6.0


Novedades de PowerShell 7.4 (versión
preliminar)
Artículo • 29/09/2023

PowerShell 7.4-preview.6 incluye las siguientes características, actualizaciones y cambios


importantes. PowerShell 7.4 ahora se basa en .NET 8.0.0-preview.7.

Para ver la lista completa de cambios, consulte el REGISTRO DE CAMBIOS en el


repositorio de GitHub.

Últimos cambios
Las imágenes de Docker de Nano Server no están disponibles para esta versión
Se ha agregado el parámetro ProgressAction a los parámetros comunes
Se han actualizado algunas API de PowerShell para generar ArgumentException
en lugar de ArgumentNullException cuando el argumento es una cadena vacía
(n.º 19215 ) (Gracias, @xtqqczze!)
Se quita el código relacionado con #requires -pssnapin (n.º 19320 )
Test-Json ahora usa Json.Schema.Net en lugar de Newtonsoft.Json.Schema. Con

este cambio, Test-Json ya no admite los esquemas anteriores de Draft 4. (n.º


18141 ) (Gracias a @gregsdennis!)
Ahora, la salida de Test-Connection incluye información más detallada sobre las
pruebas de conexión TCP

Actualizaciones del instalador


Ahora, el paquete MSI de Windows proporciona una opción para deshabilitar la
telemetría de PowerShell durante la instalación. Para obtener más información, consulte
Instalación del paquete MSI desde la línea de comandos.

Inclusión de PSResourceGet
A partir de PowerShell 7.4-preview.6, Microsoft.PowerShell.PSResourceGet v0.9.0-rc1
ahora está incluido. Este módulo se instala en paralelo con PowerShellGet v2.2.5 y
PackageManagement v1.4.8.1.

Para obtener más información, consulte la documentación de


Microsoft.PowerShell.PSResourceGet.
Mejoras de finalización con tabulación
Muchas gracias a @MartinGC94 y a los demás por todo el trabajo en la mejora de la
finalización con tabulación.

Se ha corregido un problema al completar el primer comando de un script con una


expresión de matriz vacía ([n.º 18355 ])
Se ha corregido la finalización de argumentos posicionales (n.º 17796 )
Se ha dado prioridad al conjunto de parámetros predeterminados al completar
argumentos posicionales (n.º 18755 )
Se ha mejorado el pseudoenlace de parámetros dinámicos (n.º 18030 )
Se ha mejorado la inferencia de tipos de claves de la tabla hash (n.º 17907 )
Se ha corregido el error de inferencia de tipos para instrucciones return vacías (n.º
18351 )
Se ha mejorado la inferencia de tipos para Get-Random (n.º 18972 )
Se ha corregido la inferencia de tipos de todas las variables de ámbito (n.º
18758 )
Se ha mejorado la enumeración de tipos deducidos en la canalización (n.º
17799 )
Se ha agregado finalización para valores en las comparaciones al comparar
enumeraciones (n.º 17654 )
Se ha agregado finalización de asignación de propiedades para enumeraciones
(n.º 19178 )
Se ha corregido la finalización de las propiedades de la variable PSCustomObject
(n.º 18682 )
Se ha corregido la finalización de miembros en el argumento de atributo (n.º
17902 )
Excluir los alias de parámetro redundantes de los resultados de finalización (n.º
19382 )
Se ha corregido la finalización de miembros de clase de clases con tipos base (n.º
19179 )
Se ha agregado finalización para usar palabras clave (n.º 16514 )
Reparar la fuga de variables TabExpansion2 al completar variables (n.º 18763 )
Habilitar la finalización de variables en ámbitos de ScriptBlock (n.º 19819 )
Reparar la finalización de la variable para la instrucción foreach (n.º 19814 )
Reparar la prioridad de inferencia de tipos de variable (n.º 18691 )
Reparar la finalización de miembros para la clase Enum de PowerShell (n.º
19740 )
Reparar el análisis de literales de matriz en expresiones de índice en llamadas de
método (n.º 19224 )
Mejorar la finalización de la ruta de acceso (n.º 19489 )
Corregir un error de indexación fuera del límite en CompleteInput para la entrada
de script vacía (n.º 19501 )
Mejorar el rendimiento de la finalización de variables (n.º 19595 )
Mejorar la finalización de claves de tablas hash para asignaciones de variables
restringidas de tipo, tablas hash anidadas y mucho más (n.º 17660 )
Inferir la salida de la aplicación externa como cadenas (n.º 19193 )
Actualizar la finalización de parámetros para que las enumeraciones excluyan los
valores no permitidos por ValidateRange atributos (n.º 17750 ) (Gracias a
@fflaten!).
Corregir la finalización de parámetros dinámicos (#19510 )
Agregar finalización de variables asignadas por la instrucción Data (#19831 )

Mejoras de cmdlets de web


Muchas gracias a @CarloToso y a los demás por todo el trabajo en la mejora de los
cmdlets web.

Los cmdlets web agregan 308 para redirigir los códigos y la limpieza pequeña (n.º
18536 )
Completar la representación de la barra de progreso en Invoke-WebRequest
cuando se complete o cancele la descarga (n.º 18130 )
Los cmdlets web obtienen el intervalo Retry-After de los encabezados de
respuesta si el código de estado es 429 (n.º 18717 )
Los cmdlets web establecen la codificación de conjunto de caracteres
predeterminada en UTF8 (n.º 18219 )
Se conserva WebSession.MaximumRedirection frente a cambios (n.º 19190 )
Los cmdlets web analizan la declaración XML para obtener el valor de codificación,
si está presente. (n.º 18748 )
Corrección mediante xml -Body en cmdlets web sin codificación (n.º 19281 )
Se ha ajustado el comportamiento del método PUT al POST para el tipo de
contenido predeterminado en cmdlets web (n.º 19152 )
Se tiene en cuenta ContentType de encabezados en cmdlets web (n.º 19227 )
Permitir la conservación del método HTTP original agregando -
PreserveHttpMethodOnRedirect a cmdlets web (n.º 18894 )
Los cmdlets web muestran un error en la redirección de https a http (n.º 18595 )
Agregar el modificador AllowInsecureRedirect a cmdlets web (n.º 18546 )
Se ha mejorado el mensaje detallado en cmdlets web cuando se desconoce la
longitud del contenido (n.º 19252 )
Compilar el URI relativo de los vínculos de la respuesta en Invoke-WebRequest (n.º
19092 )
Reparar el redireccionamiento para -CustomMethod POST en cmdlets web (n.º
19111 )
Se ha eliminado la respuesta anterior en cmdlets web (n.º 19117 )
Mejorar el formato de los errores de xml y json Invoke-WebRequest (n.º 18837 )
Agregar validateNotNullOrEmpty a los parámetros OutFile e InFile de cmdlets web
(n.º 19044 )
Se ha actualizado la lista de encabezados de httpKnownHeaderNames (n.º
18947 )
Invoke-RestMethod -FollowRelLink repara los vínculos que contienen comas (n.º

18829 )
Se ha corregido un error al administrar el redireccionamiento y keepAuthorization
en cmdlets web (n.º 18902 )
Agregar StatusCode a HttpResponseException (n.º 18842 )
Compatibilidad con conexiones HTTP persistentes en cmdlets web (n.º 19249 )
(Gracias, @stevenebutler!)
Limpieza pequeña Invoke-RestMethod (n.º 19490 )
Mejorar el mensaje detallado de cmdlets web para mostrar la versión HTTP
correcta (n.º 19616 )
Agregar FileNameStar a MultipartFileContent en cmdlets web (n.º 19467 )
Corregir el estado HTTP de 409 a 429 para que los cmdlets web obtengan el
intervalo de reintento del encabezado Retry-After. (n.º 19622 ) (Gracias a
@mkht!)
Cambiar -TimeoutSec a -ConnectionTimeoutSeconds y agregar -
OperationTimeoutSeconds a cmdlets web (n.º 19558 ) (Gracias a @stevenebutler!)
otros cmdlets
Compatibilidad con Ctrl+c cuando la conexión se bloquea mientras se leen datos
en cmdlets web (n.º 19330 ) (gracias a @stevenebutler!)
Compatibilidad con el socket de dominio unix en WebCmdlets (#19343 )

Otras mejoras de cmdlets


Se agregan tipos de salida a los comandos Format (n.º 18746 ) (gracias a
@MartinGC94!)
Se agregan atributos de tipo de salida para Get-WinEvent (n.º 17948 ) (gracias a
@MartinGC94!)
Añada los parámetros Path y LiteralPath al cmdlet Test-Json (#19042 ) (Gracias,
@ArmaanMcleod!)
Añada el parámetro NoHeader a los cmdlets ConvertTo-Csv y Export-Csv
(#19108 ) (Gracias, @ArmaanMcleod!)
Se han agregado los parámetros Confirm y WhatIf a Stop-Transcript (#18731 )
(Gracias, @JohnLBevan!)
Se ha agregado el parámetro FuzzyMinimumDistance a Get-Command (#18261 )
Se ha habilitado la aceptación de codificación ANSI por parte del parámetro
Encoding en PowerShell ( 19298 ) (Gracias, @CarloToso!)
Agregar progreso a Copy-Item (#18735 )
Update-Help ahora notifica un error al usar la referencia cultural implícita en

sistemas ajenos a EE. UU. (#17780 ) (Gracias, @dkaszews!)


No se requiere actividad al crear un registro de progreso completado (n.º 18474 )
(gracias a @MartinGC94!)
No se permiten valores negativos para Get-Content parámetros de cmdlet -Head y
-Tail (n.º 19715 ) (gracias a @CarloToso!)
Hace que Update-Help genere un error adecuado cuando la referencia cultural
actual no esté asociada a un idioma (n.º 19765 ) (gracias a @josea!)
Se permite la combinación de parámetros -Skip y -SkipLast en el cmdlet Select-
Object . (n.º 18849 ) (gracias a @ArmaanMcleod!)
Se agrega el cmdlet Get-SecureRandom (n.º 19587 )
Set-Clipboard -AsOSC52 para uso remoto (n.º 18222 ) (gracias a @dkaszews!)
Acelerar la resolución de rutas relativas Resolve-Path (n.º 19171 ) (gracias a
@MartinGC94!)
Se agregó el parámetro switch -CaseInsensitive a Select-Object y cmdlets de
Get-Unique (#19683 ) (Gracias @ArmaanMcleod!)
Restart-Computer y Stop-Computer deben producir un error al no ejecutarse a

través de sudo en Unix (#19824 )

Mejoras del motor


Actualizaciones para el $PSStyle

Se han agregado las propiedades Dim y DimOff (#18653 )


Se han agregado métodos estáticos a la clase PSStyle que asignan los valores
ConsoleColor de primer plano y de fondo a secuencias de escape ANSI (#17938 )
Los encabezados de tabla para los campos calculados tienen un formato en cursiva
de forma predeterminada
Se agrega compatibilidad con el respeto de $PSStyle.OutputRendering en el host
remoto (n.º 19601 )

Otras actualizaciones del motor


Se ha hecho que no se afilie la clase de PowerShell con el espacio de ejecución al
declarar el atributo NoRunspaceAffinity (#18138 )
Se ha agregado el atributo ValidateNotNullOrWhiteSpace (#17191 ) (Gracias,
@wmentha!)
Se ha agregado sqlcmd a la lista para pasar argumentos heredados (#18559 )
Se ha agregado la función cd~ (#18308 ) (Gracias, @GigaScratch!)
Se corrige el análisis de tipos de matriz en tipos genéricos (n.º 19205 ) (gracias a
@MartinGC94!)
Se corrige el uso global de caracteres comodín en la raíz de las rutas de acceso del
dispositivo (n.º 19442 ) (gracias a @MartinGC94!)
Se agrega una API pública para obtener ubicaciones de elementos PSModulePath
(n.º 19422 )
Se corrige una cadena incorrecta para la conversión de tipos (n.º 19560 ) (gracias
a @MartinGC94!)
Se corrige la ejecución lenta cuando se usan muchos puntos de interrupción (n.º
14953 ) (gracias a @nohwnd!)
Se quita el código relacionado con #requires -pssnapin (n.º 19320 )

Características experimentales
PowerShell 7.4 presenta las siguientes características experimentales:

PSFeedbackProvider: reemplaza el marco de sugerencias codificado de forma


rígida por un proveedor de comentarios extensible.
Esta característica también agrega las propiedades FeedbackName,
FeedbackText y FeedbackAction a $PSStyle.Formatting que permiten cambiar
el formato de los mensajes de comentarios.
PSModuleAutoLoadSkipOfflineFiles: la detección de módulos ahora omite los
archivos marcados por proveedores de nube como no totalmente en el disco.
PSCommandWithArgs: se ha agregado compatibilidad para pasar argumentos a
comandos como una sola cadena

Se han estandarizado las siguientes características experimentales:

PSConstrainedAuditLogging: se agrega compatibilidad con el registro de mensajes


sobre el código que no se permitiría en el modo de lenguaje restringido
PSCustomTableHeaderLabelDecoration: adición de la diferenciación de formato
para las etiquetas de encabezado de tabla que no son miembros de propiedad.
Esta característica también agrega la propiedad CustomTableHeaderLabel a
$PSStyle.Formatting que permite cambiar el formato de la etiqueta de

encabezado.
PSNativeCommandErrorActionPreference -
$PSNativeCommandUseErrorActionPreference se establece en $true cuando la

característica está habilitada (#18695 )


PSNativeCommandPreserveBytePipe: se conservan los datos de secuencia de bytes
al redirigir la secuencia stdout de un comando nativo a un archivo o al canalizar
datos de secuencia de bytes al flujo stdin de un comando nativo.
PSWindowsNativeCommandArgPassing: se cambia el valor predeterminado de
$PSNativeCommandArgumentPassing a Windows en Windows.

PowerShell 7.4 cambió las siguientes características experimentales:

PSCommandNotFoundSuggestion: esta característica ahora usa un proveedor de


comentarios extensible en lugar de sugerencias codificadas de forma rígida (n.º
18726 )

Para más información sobre las características experimentales, consulte Uso de


características experimentales en PowerShell.

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Novedades de PowerShell 7.3
Artículo • 13/04/2023

PowerShell 7.3 es la siguiente versión estable, integrada en .NET 7.0.

PowerShell 7.3 incluye las características, las actualizaciones y los cambios importantes
que se indican a continuación.

Últimos cambios y mejoras


En esta versión, las API de Windows se actualizaron o quitaron para el
cumplimiento, lo que significa que PowerShell 7.3 no se ejecuta en Windows 7.
Aunque ya no se admite Windows 7, las compilaciones anteriores podrían
ejecutarse en Windows 7.
PowerShell Direct para Hyper-V solo se admite en Windows 10, a partir de la
versión 1809.
Test-Connection se ha interrumpido debido a un cambio importante
intencionado en .NET 7. Se realiza su seguimiento por #17018 .
Adición del bloque clean al bloque de script como elemento del mismo nivel a
begin , process y end para permitir una limpieza de recursos sencilla (n.º 15177 )
Cambio del valor predeterminado de $PSStyle.OutputRendering a Host
Se ha hecho que Out-String y Out-File mantengan la entrada de cadena sin
cambios (n.º 17455 )
Se ha movido la definición de datos de tipo de
System.Security.AccessControl.ObjectSecurity al módulo
Microsoft.PowerShell.Security (n.º 16355 ) (¡Gracias @iSazonov!)!)
Antes de este cambio, un usuario no necesita importar explícitamente el
módulo Microsoft.PowerShell.Security para usar las propiedades de código
definidas para una instancia de System.Security.AccessControl.ObjectSecurity.
Después de este cambio, un usuario debe importar explícitamente el módulo
Microsoft.PowerShell.Security para poder usar esas propiedades y métodos de
código.

Mejoras de finalización con tabulación


PowerShell 7.3 incluye PSReadline 2.2.6, que habilita IntelliSense predictivo de
forma predeterminada. Para más información, vea Acerca de PSReadLine.
Corrección de la finalización de tabulación dentro del bloque de script
especificado para ValidateScriptAttribute . (N.º 14550 ) (¡Gracias
@MartinGC94!)!)
Se ha agregado la finalización con tabulación para las etiquetas de bucle después
de break / continue (n.º 16438 ) (¡Gracias @MartinGC94!)!)
Mejora de la finalización de la tabla hash en varios escenarios (n.º 16498 )
(¡Gracias @MartinGC94!)!)
Expansión de parámetros
Parámetro Arguments para Invoke-CimMethod
Parámetro FilterHashtable para Get-WinEvent
Parámetro Property para los cmdlets CIM
Quita los duplicados de los escenarios de finalización de miembros.
Compatibilidad con las barras diagonales en la finalización del recurso compartido
de red (ruta de acceso UNC) (n.º 17111 ) (¡Gracias @sba923!)!)
Mejora de la finalización automática de miembros (n.º 16504 ) (¡Gracias
@MartinGC94!)!)
Clasificación por orden de prioridad de las finalizaciones ValidateSet sobre
enumeraciones de parámetros (n.º 15257 ) (¡Gracias @MartinGC94!)!)
Se ha agregado compatibilidad con la inferencia de tipos para métodos genéricos
con parámetros de tipo (n.º 16951 ) (¡Gracias @MartinGC94!)!)
Se ha mejorado la inferencia de tipos y finalizaciones (n.º 16963 ) (¡Gracias
@MartinGC94!)!)
Permite que los métodos se muestren en los resultados de finalización de
ForEach-Object -MemberName .

Impide la finalización en expresiones que devuelven void, como ([void]("")) .


Permite que los constructores de clase no predeterminados se muestren cuando
la finalización de la clase se basa en AST.
Se ha mejorado la inferencia de tipos para $_ (n.º 17716 ) (¡Gracias
@MartinGC94!)!)
Se ha corregido la inferencia de tipos para ICollection (n.º 17752 ) (¡Gracias
@MartinGC94!)!)
Se ha evitado la eliminación de las llaves al completar variables (n.º 17751 )
(¡Gracias @MartinGC94!)!)
Se ha agregado la finalización de expresiones de índice para diccionarios
(n.º 17619 ) (¡Gracias @MartinGC94!)!)
Se ha corregido la finalización de tipos para los tokens de atributo (n.º 17484 )
(¡Gracias @MartinGC94!)!)
Se ha mejorado la finalización de tabulación de parámetros dinámicos
(n.º 17661 )(¡Gracias @MartinGC94!)!)
Se ha evitado enlazar parámetros posicionales al completar el parámetro delante
del valor (n.º 17693 ) (¡Gracias @MartinGC94!)!)
Se ha mejorado el control de errores
Establecimiento de $? correctamente para la expresión de comando con
redireccionamientos (n.º 16046 )
Corrección de un error de conversión al usar
$PSNativeCommandUseErrorActionPreference (n.º 15993 )
Respeto opcional del control de errores del comando nativo
ErrorActionPreference (n.º 15897 )
Especificar la ruta de acceso ejecutable como TargetObject para el código de
salida distinto de cero ErrorRecord (n.º 16108 ) (¡Gracias @rkeithhill!)!)

Mejoras de sesión y comunicación remota


Agregar -Options al PSRP mediante comandos SSH para permitir pasar las
opciones de OpenSSH directamente (n.º 12802 ) (¡Gracias @BrannenGH!)!)
Se ha agregado el parámetro -ConfigurationFile a pwsh para permitir iniciar un
nuevo proceso con la configuración de sesión definida en un archivo .pssc
(n.º 17447 )
Se ha agregado compatibilidad para usar New-PSSessionConfigurationFile en
plataformas que no sean de Windows (n.º 17447 )

Se han actualizado los cmdlets:


Adición del parámetro -HttpVersion a los cmdlets web (n.º 15853 ) (¡Gracias
@hayhay27!)!)
Adición de compatibilidad con cmdlets web para etiquetas de entrada abiertas
(n.º 16193 ) (¡Gracias @farmerau!)!)
Corrección de ConvertTo-Json -Depth para permitir 100 como máximo
(n.º 16197 ) (¡Gracias @KevRitchie!)@rkeithhill!)!)
Mejora del control de variables al llamar a Invoke-Command con la expresión
$using: (n.º 16113 ) (¡Gracias @dwtaber!)!)
Se ha agregado -StrictMode a Invoke-Command para permitir que se especifique el
modo strict al invocar el comando localmente (n.º 16545 ) (¡Gracias @Thomas-
Yu!)!)
Adición del bloque clean al bloque de script como elemento del mismo nivel a
begin , process y end para permitir una limpieza de recursos sencilla (n.º 15177 )
Se ha agregado el modificador -Amended al cmdlet Get-CimClass (n.º 17477 )
(¡Gracias @iSazonov)!)
Se ha cambiado ConvertFrom-Json -AsHashtable para usar la tabla hash ordenada
(n.º 17405 )
Se han quitado secuencias de escape ANSI en cadenas antes de enviarlas a Out-
GridView (n.º 17664 )
Se ha agregado el parámetro Milliseconds a New-TimeSpan (n.º 17621 ) (¡Gracias
@NoMoreFood!)!)
Visualización de parámetros opcionales al mostrar definiciones de método y
sobrecargas (n.º 13799 ) (¡Gracias @eugenesmlv!)!)
Permiso para que los comandos se sigan ejecutando incluso si el directorio de
trabajo actual ya no existe (n.º 17579 )
Se ha agregado compatibilidad con HTTPS con Set-AuthenticodeSignature -
TimeStampServer (n.º 16134 ) (¡Gracias @Ryan-Hutchison-USAF!)!)
Representación de números decimales en una tabla mediante la referencia cultural
actual (n.º 17650 )
Adición del acelerador de tipos ordenado para OrderedDictionary (n.º 17804 )
(¡Gracias @fflaten!)!)
Adición de find.exe al comportamiento de enlace de argumentos heredado para
Windows (n.º 17715 )
Adición de un modificador -noprofileloadtime a pwsh (n.º 17535 ) (¡Gracias
@rkeithhill!)!)

Para ver la lista completa de cambios, consulte el registro de cambios en el


repositorio de GitHub.

Características experimentales
En PowerShell 7.3, se han estandarizado las siguientes características experimentales:

PSAnsiRenderingFileInfo : Esta característica agrega el miembro $PSStyle.FileInfo

y permite colorear tipos de archivo específicos.

PSCleanBlock : agrega el bloque clean al bloque de script como nodo del mismo

nivel a begin , process y end para permitir una limpieza de recursos sencilla.

PSAMSIMethodInvocationLogging : extiende los datos que se envían a AMSI para su


inspección para incluir todas las invocaciones de miembros del método .NET.

PSNativeCommandArgumentPassing: ahora, PowerShell usa la propiedad


ArgumentList del objeto StartProcessInfo en lugar del mecanismo anterior de
reconstrucción de una cadena al invocar un ejecutable nativo.
PowerShell 7.3.1 agrega sqlcmd.exe a la lista de comandos nativos en Windows
que usan el estilo Legacy de paso de argumentos.

PSExec : agrega el nuevo cmdlet de Switch-Process (alias exec ) para ofrecer

compatibilidad con exec para sistemas que no son de Windows.

PowerShell 7.3.1 cambió el alias exec a una función que encapsula Switch-
Process . La función permite pasar parámetros al comando nativo que podría haber

enlazado erróneamente con el parámetro WithCommand.

PowerShell 7.3 presenta las siguientes características experimentales:

PSNativeCommandErrorActionPreference:
$PSNativeCommandUseErrorActionPreference agrega la variable para permitir que los

errores generados por los comandos nativos sean errores de PowerShell.

Se han eliminado las siguientes características experimentales de PowerShell 7.3:

La característica experimental PSNativePSPathResolution ya no se admite.


La característica experimental PSStrictModeAssignment ya no se admite.

Para más información sobre las características experimentales, consulte Uso de


características experimentales en PowerShell.
Novedades de PowerShell 7.2
Artículo • 13/04/2023

PowerShell 7.2 es la próxima versión de mantenimiento a largo plazo (LTS) que se basa
en .NET 6.0.

PowerShell 7.2 incluye las características, las actualizaciones y los cambios importantes
que se indican a continuación.

Nuevos paquetes de instalador universal para la mayoría de las distribuciones de


Linux admitidas
Soporte técnico de Microsoft Update en Windows
Dos nuevas características experimentales
Compatibilidad mejorada con el paso de argumentos de comandos nativos
Compatibilidad con colores ANSI FileInfo
Finalizaciones de pestañas mejoradas
PSReadLine 2.1 con IntelliSense predictivo.
Siete características experimentales promocionadas a estándar y una eliminada
Separación de DSC de PowerShell 7 para habilitar futuras mejoras
Varios cambios importantes para mejorar la usabilidad.

Para ver la lista completa de cambios, consulte el registro de cambios en el


repositorio de GitHub.

Actualizaciones de instalación
Consulte las instrucciones de instalación del sistema operativo que prefiera:

Windows
macOS
Linux

Además, PowerShell 7.2 admite las versiones ARM64 de Windows y macOS, y ARM32 y
ARM64 de Debian y Ubuntu.

Para más información actualizada sobre los sistemas operativos compatibles y el ciclo de
vida de soporte técnico, consulte Ciclo de vida de soporte técnico de PowerShell.

Nuevos paquetes de instalación universal para


distribuciones de Linux
Anteriormente, hemos creado paquetes de instalador independientes para cada versión
admitida de CentOS, RHEL, Debian y Ubuntu. El paquete del instalador universal
combina ocho paquetes diferentes en uno, lo que facilita la instalación en Linux. El
paquete universal instala las dependencias necesarias para la distribución de destino y
crea los cambios específicos de la plataforma para que PowerShell funcione.

Soporte técnico de Microsoft Update en Windows


PowerShell 7.2 agrega soporte técnico con Microsoft Update. Al habilitar esta
característica, se obtienen las actualizaciones más recientes de PowerShell 7 en el flujo
de administración tradicional de Windows Update (WU), ya sea con Windows Update for
Business, WSUS, SCCM o el cuadro de diálogo WU interactivo de Configuración.

El paquete MSI de PowerShell 7.2 incluye las siguientes opciones de línea de comandos:

USE_MU : esta propiedad tiene dos valores posibles:


1 (valor predeterminado): permite actualizar mediante Microsoft Update o

WSUS
0 : no permite realizar la actualización mediante Microsoft Update o WSUS
ENABLE_MU

1 (valor predeterminado): permite usar Microsoft Update para las


actualizaciones automáticas o Windows Update.
0 : no permite usar Microsoft Update para las actualizaciones automáticas o de

Windows Update

Características experimentales
Las características experimentales siguientes ya son estándares en esta versión:

Microsoft.PowerShell.Utility.PSImportPSDataFileSkipLimitCheck : consulte

Import-PowerShellDataFile
Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace

PSAnsiRendering : consulte about_ANSI_Terminals

PSAnsiProgress : consulte about_ANSI_Terminals


PSCultureInvariantReplaceOperator

PSNotApplyErrorActionToStderr
PSUnixFileStat

Las características experimentales siguientes se han agregado en esta versión:


PSNativeCommandArgumentPassing: cuando esta característica experimental está
habilitada, PowerShell usa la propiedad ArgumentList del objeto StartProcessInfo
en lugar de nuestro mecanismo actual de reconstrucción de una cadena al invocar
un ejecutable nativo. La característica agrega una nueva variable automática
$PSNativeCommandArgumentPassing que permite seleccionar el comportamiento en

tiempo de ejecución.

PSAnsiRenderingFileInfo: permite la personalización de color ANSI de la


información de archivo.

PSLoadAssemblyFromNativeCode: expone una API para permitir la carga de


ensamblados desde código nativo.

Para más información sobre las características experimentales, consulte Uso de


características experimentales en PowerShell.

Finalizaciones con tabulación mejoradas


PowerShell 7.2 incluye varias mejoras en la finalización con tabulación. Estos cambios
incluyen correcciones de errores y mejoran la facilidad de uso.

Se ha corregido la finalización con tabulación para temas acerca de* no localizados


(n.º 15265) (¡Gracias @MartinGC94)!)
Se ha corregido la plataforma que se trata como parámetro posicional en las
finalizaciones (n.º 14623) (¡Gracias @MartinGC94)!)
Se han agregado finalizaciones para palabras clave de ayuda basadas en
comentarios (n.º 15337) (¡Gracias @MartinGC94)!)
Se ha agregado la finalización para instrucciones Requires (n.º 14596) (¡Gracias
@MartinGC94)!)
Se ha agregado la finalización con tabulación para el parámetro View de los
cmdlets Format-* (n.º 14513) (¡Gracias @iSazonov)!)

IntelliSense predictivo de PSReadLine 2.1


PSReadLine 2.1 introdujo las API CommandPrediction que establecen un marco para
proporcionar predicciones para la finalización con la línea de comandos. La API permite
a los usuarios detectar, editar y ejecutar comandos completos en función de las
predicciones correspondientes del historial del usuario.

IntelliSense predictivo está desactivado de forma predeterminada. Ejecute el comando


siguiente para habilitar las predicciones:
PowerShell

Set-PSReadLineOption -PredictionSource History

Separación de DSC de PowerShell 7 para


habilitar futuras mejoras
El módulo PSDesiredStateConfiguration se quitó del paquete de PowerShell 7.2 y ahora
se publica en la Galería de PowerShell. Esto permite desarrollar el módulo
PSDesiredStateConfiguration independientemente de PowerShell y los usuarios pueden
combinar y buscar coincidencias con versiones de PowerShell y
PSDesiredStateConfiguration para su entorno. Para instalar
PSDesiredStateConfiguration 2.0.5 desde la Galería de PowerShell:

PowerShell

Install-Module -Name PSDesiredStateConfiguration -Repository PSGallery -


MaximumVersion 2.99

) Importante

Asegúrese de incluir el parámetro MaximumVersion o puede instalar la versión 3 (o


superior) de PSDesireStateConfiguration que contiene diferencias significativas.

Actualizaciones del motor


Se ha agregado la función LoadAssemblyFromNativeMemory para cargar ensamblados
en memoria desde un host nativo de PowerShell mediante la configuración
dinámica. Solicitud de incorporación de cambios #14652

Últimos cambios y mejoras


PSDesiredStateConfiguration se quitó del paquete de PowerShell 7.2
Se han convertido los paquetes deb y RPM de PowerShell en universales (#15109)
Característica experimental PSNativeCommandArgumentPassing : utilice ArgumentList
para la invocación del ejecutable nativo (#14692).
Asegúrese de que -PipelineVariable está establecido para todos los resultados de
los cmdlets de script (#12766).
Se emiten advertencias si ConvertTo-Json supera el valor de -Depth (#13692).
Se quita el alias D de -Directory switch CL-General #15171.
Se mejora la detección de tipos de valor mutable (#12495).
Se restringe New-Object en modo NoLanguage en bloqueo (#14140).
Se aplica la configuración de denegación de AppLocker antes de la configuración
de omisión de la directiva de ejecución (#15035).
Se cambia FileSystemInfo.Target de CodeProperty a un elemento AliasProperty
que apunta a FileSystemInfo.LinkTarget (#16165)
Migración de Windows PowerShell 5.1 a
PowerShell 7
Artículo • 25/03/2023

Diseñado para entornos híbridos, locales y en la nube, el paquete de PowerShell 7 incluye


mejoras y nuevas características.

Se instala y se ejecuta en paralelo con Windows PowerShell


Compatibilidad mejorada con los módulos de Windows PowerShell existentes
Nuevas características de lenguaje, como los operadores ternarios y ForEach-Object -
Parallel
rendimiento mejorado.
Comunicación remota basada en SSH
Interoperabilidad entre plataformas
Soporte para contenedores de Docker

PowerShell 7 funciona en paralelo con Windows PowerShell, lo que le permite probar y


comparar fácilmente las distintas ediciones antes de implementarlo. La migración es sencilla,
rápida y segura.

PowerShell 7 es compatible con los siguientes sistemas operativos Windows:

Windows 8.1, 10 y 11
Windows Server 2012, 2012 R2, 2016, 2019 y 2022

PowerShell 7 también se ejecuta en macOS y varias distribuciones Linux. Para ver una lista de
los sistemas operativos admitidos e información sobre el ciclo de vida de soporte técnico,
consulte Ciclo de vida de soporte técnico de PowerShell.

Instalación de PowerShell 7
Para ofrecer flexibilidad y satisfacer las necesidades del personal de TI, los ingenieros de
DevOps y los desarrolladores, PowerShell 7 cuenta con varias opciones de instalación. En la
mayoría de los casos, las opciones de instalación se pueden reducir a los siguientes métodos:

Implementación de PowerShell mediante el paquete MSI


Implementación de PowerShell mediante el paquete ZIP

7 Nota

El paquete MSI se puede implementar y actualizar con productos de administración


como System Center Configuration Manager (SCCM). Descargue los paquetes desde la
página de versiones de GitHub .
La implementación del paquete MSI requiere permisos de administrador. Cualquier usuario
puede implementar el paquete ZIP. El paquete ZIP es la forma más fácil de instalar
PowerShell 7 para probarlo antes de comprometerse a una instalación completa.

También puede instalar PowerShell 7 mediante Windows Store o winget . Para obtener más
información sobre ambos métodos, vea las instrucciones detalladas en Instalación de
PowerShell en Windows.

Uso de PowerShell 7 en paralelo con Windows


PowerShell 5.1
PowerShell 7 está diseñado para coexistir con Windows PowerShell 5.1. Las siguientes
características garantizan la protección de la inversión en PowerShell y la migración fácil a
PowerShell 7.

Ruta de instalación y nombre del archivo ejecutable independientes


PSModulePath independiente
Perfiles independientes para cada versión
Compatibilidad mejorada con los módulos
Nuevos puntos de conexión de comunicación remota
Compatibilidad con directiva de grupo
Registros de eventos independientes

Ruta de instalación y nombre del archivo ejecutable


independientes
PowerShell 7 se instala en un nuevo directorio, lo que permite que se ejecute en paralelo con
Windows PowerShell 5.1.

Ubicaciones de instalación por versión:

Windows PowerShell 5.1: $env:WINDIR\System32\WindowsPowerShell\v1.0


PowerShell 6.x: $env:ProgramFiles\PowerShell\6
PowerShell 7: $env:ProgramFiles\PowerShell\7

La nueva ubicación se agrega a la ruta de acceso, lo que le permite ejecutar tanto Windows
PowerShell 5.1 como PowerShell 7. Si va a migrar de PowerShell 6.x a PowerShell 7, se quita
PowerShell 6 y se reemplaza la ruta de acceso.

En Windows PowerShell, el archivo ejecutable de PowerShell se denomina powershell.exe .


En la versión 6 y posteriores, el archivo ejecutable se denomina pwsh.exe . El nuevo nombre
facilita la compatibilidad con la ejecución en paralelo de ambas versiones.
PSModulePath independiente
De forma predeterminada, Windows PowerShell y PowerShell 7 almacenan los módulos en
ubicaciones diferentes. PowerShell 7 combina esas ubicaciones en la variable de entorno
$Env:PSModulePath . Al importar un módulo por nombre, PowerShell comprueba la ubicación

especificada por $Env:PSModulePath . Esto permite que PowerShell 7 cargue tanto módulos
principales como de escritorio.

Ámbito de Windows PowerShell 5.1 PowerShell 7.0


instalación

Módulos de $env:WINDIR\system32\WindowsPowerShell\v1.0\Modules $PSHOME\Modules


PowerShell

Usuario $env:ProgramFiles\WindowsPowerShell\Modules $env:ProgramFiles\PowerShell\Modules


instalado
Ámbito
AllUsers

Usuario $HOME\Documents\WindowsPowerShell\Modules $HOME\Documents\PowerShell\Modules


instalado
Ámbito
CurrentUser

En los ejemplos siguientes se muestran los valores predeterminados de $Env:PSModulePath


para cada versión.

Para Windows PowerShell 5.1:

PowerShell

$Env:PSModulePath -split (';')

Output

C:\Users\<user>\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\WINDOWS\System32\WindowsPowerShell\v1.0\Modules

Para PowerShell 7:

PowerShell

$Env:PSModulePath -split (';')

Output
C:\Users\<user>\Documents\PowerShell\Modules
C:\Program Files\PowerShell\Modules
C:\Program Files\PowerShell\7\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\WINDOWS\System32\WindowsPowerShell\v1.0\Modules

Tenga en cuenta que PowerShell 7 incluye las rutas de acceso de Windows PowerShell y las
rutas de acceso de PowerShell 7 para proporcionar la carga automática de los módulos.

7 Nota

Pueden existir rutas de acceso adicionales si ha cambiado la variable de entorno


PSModulePath o ha instalado módulos o aplicaciones personalizados.

Para más información, consulte about_PSModulePath.

Para más información sobre los módulos, consulte about_Modules.

Perfiles independientes
Un perfil de PowerShell es un script que se ejecuta cuando se inicia PowerShell. Este script
agrega comandos, alias, funciones, variables, módulos y unidades de PowerShell para
personalizar el entorno. El script de perfil permite que estas personalizaciones estén
disponibles en cada sesión sin tener que volver a crearlas manualmente.

La ruta de acceso a la ubicación del perfil ha cambiado en PowerShell 7.

En Windows PowerShell 5.1, la ubicación del perfil es


$HOME\Documents\WindowsPowerShell .
En PowerShell 7, la ubicación del perfil es $HOME\Documents\PowerShell .

Los nombres de archivo de perfil también han cambiado:

PowerShell

PS> $PROFILE | Select-Object *Host* | Format-List

AllUsersAllHosts : C:\Program Files\PowerShell\7\profile.ps1


AllUsersCurrentHost : C:\Program
Files\PowerShell\7\Microsoft.PowerShell_profile.ps1
CurrentUserAllHosts : C:\Users\<user>\Documents\PowerShell\profile.ps1
CurrentUserCurrentHost : C:\Users\
<user>\Documents\PowerShell\Microsoft.PowerShell_profile.ps1

Para más información, consulte about_Profiles.


Compatibilidad de PowerShell 7 con los módulos de
Windows PowerShell 5.1
La mayoría de los módulos que usa en Windows PowerShell 5.1 ya funcionan con PowerShell
7, incluidos Azure PowerShell y Active Directory. Seguimos trabajando con otros equipos
para agregar compatibilidad nativa de PowerShell 7 con más módulos, como Microsoft
Graph, Office 365 y otros. Puede encontrar la lista actual de los módulos compatibles
admitidos en Compatibilidad del módulo de PowerShell 7.

7 Nota

En Windows, también hemos agregado un modificador UseWindowsPowerShell a


Import-Module para facilitar la transición a PowerShell 7 para aquellos que usan

módulos incompatibles. Para más información sobre esta funcionalidad, consulte


about_Windows_PowerShell_Compatibility.

Comunicación remota de PowerShell


La comunicación remota de PowerShell le permite ejecutar cualquier comando de PowerShell
en uno o varios equipos remotos. Puede establecer conexiones persistentes, iniciar sesiones
interactivas y ejecutar scripts en equipos remotos.

Comunicación remota de WS-Management

Windows PowerShell 5.1 y versiones anteriores usan el protocolo WS-Management


(WSMAN) para la negociación de la conexión y el transporte de datos. Administración
remota de Windows (WinRM) usa el protocolo WSMAN. Si se ha habilitado WinRM,
PowerShell 7 usa el punto de conexión de Windows PowerShell 5.1 existente denominado
Microsoft.PowerShell para las conexiones remotas. Para actualizar PowerShell 7 de forma

que incluya su propio punto de conexión, ejecute el cmdlet Enable-PSRemoting . Para


información sobre cómo conectarse a puntos de conexión específicos, consulte
Comunicación remota de WS-Management en PowerShell.

Para usar la comunicación remota de Windows PowerShell, el equipo remoto debe estar
configurado para la administración remota. Para más información y ver instrucciones,
consulte About Remote Requirements (Acerca de los requisitos remotos).

Para más información sobre la comunicación remota, consulte Acerca de la comunicación


remota.

Comunicación remota basada en SSH


La comunicación remota basada en SSH se agregó en PowerShell 6 para lograr la
compatibilidad con otros sistemas operativos que no pueden usar componentes nativos de
Windows como WinRM. La comunicación remota mediante SSH crea un proceso de host de
PowerShell en el equipo de destino como un subsistema SSH. Para más información y
ejemplos sobre cómo configurar la comunicación remota basada en SSH en Windows o
Linux, consulte: Comunicación remota de PowerShell a través de SSH.

7 Nota

La Galería de PowerShell (PSGallery) contiene un módulo y un cmdlet que configura


automáticamente la comunicación remota basada en SSH. Instale el módulo
Microsoft.PowerShell.RemotingTools desde PSGallery y ejecute el cmdlet Enable-SSH .

Los cmdlets New-PSSession , Enter-PSSession y Invoke-Command tienen nuevos conjuntos de


parámetros que admiten conexiones SSH.

PowerShell

[-HostName <string>] [-UserName <string>] [-KeyFilePath <string>]

Para crear una sesión remota, especifique el equipo de destino con el parámetro HostName
y proporcione el nombre de usuario con UserName. Al ejecutar los cmdlets de forma
interactiva, se le pedirá una contraseña.

PowerShell

Enter-PSSession -HostName <Computer> -UserName <Username>

Como alternativa, al usar el parámetro HostName, proporcione la información de nombre de


usuario seguida del signo de arroba ( @ ) y del nombre del equipo.

PowerShell

Enter-PSSession -HostName <Username>@<Computer>

Puede configurar la autenticación de la clave SSH mediante un archivo de clave privada con
el parámetro KeyFilePath. Para más información, consulte Administración de claves de
OpenSSH.

Compatibilidad con directiva de grupo


PowerShell incluye opciones de directiva de grupo para ayudarle a definir valores de opción
coherentes para los servidores de un entorno empresarial. Esta configuración incluye:
Configuración de la sesión de la consola: establece un punto de conexión de
configuración en el que se ejecuta PowerShell.
Activación del registro de módulos: establece la propiedad LogPipelineExecutionDetails
de los módulos.
Activación del registro del bloque de scripts de PowerShell: permite el registro
detallado de todos los scripts de PowerShell.
Activación de la ejecución de scripts: establece la directiva de ejecución de PowerShell.
Activación de la transcripción de PowerShell: permite la captura de la entrada y la salida
de comandos de PowerShell en transcripciones basadas en texto.
Establecimiento de la ruta de acceso de origen predeterminada para Update-Help:
establece el origen de la ayuda actualizable en un directorio, no en Internet.

Para más información, consulte about_Group_Policy_Settings.

PowerShell 7 incluye plantillas de directiva de grupo y un script de instalación en $PSHOME .

Las herramientas de directiva de grupo usan archivos de plantilla administrativa ( .admx ,


.adml ) para rellenar la configuración de directiva en la interfaz de usuario. Esto permite a los

administradores administrar la configuración de directiva basada en el registro. El script


InstallPSCorePolicyDefinitions.ps1 instala las plantillas administrativas de PowerShell en la
máquina local.

PowerShell

Get-ChildItem -Path $PSHOME -Filter *Core*Policy*

Output

Directory: C:\Program Files\PowerShell\7

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a--- 2/27/2020 12:38 AM 15861
InstallPSCorePolicyDefinitions.ps1
-a--- 2/27/2020 12:28 AM 9675
PowerShellCoreExecutionPolicy.adml
-a--- 2/27/2020 12:28 AM 6201
PowerShellCoreExecutionPolicy.admx

Registros de eventos independientes


Windows PowerShell y PowerShell 7 anotan los eventos en registros independientes. Use el
siguiente comando para obtener una lista de los registros de PowerShell.

PowerShell
Get-WinEvent -ListLog *PowerShell*

Para más información, consulte about_Logging_Windows.

Experiencia de edición mejorada con


Visual Studio Code
Visual Studio Code (VSCode) con la extensión de PowerShell es el entorno de scripting
admitido para PowerShell 7. El Entorno de script integrado (ISE) de Windows PowerShell solo
admite Windows PowerShell.

La extensión de PowerShell actualizada incluye:

Nuevo modo de compatibilidad con el ISE


PSReadLine en la consola integrada, que incluye el resaltado de la sintaxis, la edición de
varias líneas y la búsqueda inversa
Mejoras en el rendimiento y la estabilidad
Nueva integración de CodeLens
Finalización automática de la ruta de acceso mejorada

Para facilitar la transición a Visual Studio Code, use la función Enable ISE Mode (Habilitar el
modo ISE) disponible en la paleta de comandos. Esta función cambia VSCode a un diseño de
estilo ISE. El diseño de estilo ISE le proporciona todas las características y funcionalidades
nuevas de PowerShell en una experiencia de usuario conocida.

Para cambiar al nuevo diseño de ISE, presione Ctrl + Mayús + P para abrir la paleta de
comandos, escriba PowerShell y seleccione PowerShell: Enable ISE Mode (Habilitar el modo
ISE).

Para establecer el diseño en el diseño original, abra la paleta de comandos y seleccione


PowerShell: Disable ISE Mode (restore to defaults) (Deshabilitar el modo ISE [restaurar los
valores predeterminados]).

Para más información sobre cómo personalizar el diseño de VSCode a ISE, consulte Cómo
replicar la experiencia de ISE en Visual Studio Code.

7 Nota

No hay planes de actualizar el ISE con nuevas características. En las versiones más
recientes de Windows 10 o Windows Server 2019 y versiones superiores, el ISE ya es una
característica que puede desinstalar el usuario. No hay planes de quitar el ISE de forma
permanente. El equipo de PowerShell y sus asociados están centrados en mejorar la
experiencia de scripting en la extensión de PowerShell para Visual Studio Code.
Pasos siguientes
Ahora que posee los conocimientos para realizar la migración de forma efectiva, instale
PowerShell 7 ya mismo.
Diferencias entre
Windows PowerShell 5.1 y
PowerShell 7.x
Artículo • 28/06/2023

Windows PowerShell 5.1 se basa en .NET Framework v4.5. Con el lanzamiento de


PowerShell 6.0, PowerShell se convirtió en un proyecto de código abierto basado en
.NET Core 2.0. La migración de .NET Framework a .NET Core permitió a PowerShell
convertirse en una solución multiplataforma. PowerShell se ejecuta en Windows, macOS
y Linux.

Hay algunas diferencias en el lenguaje de PowerShell entre Windows PowerShell y


PowerShell. Las diferencias más notables son la disponibilidad y el comportamiento de
los cmdlets de PowerShell entre las plataformas Windows y no Windows y los cambios
que se derivan de las diferencias entre .NET Framework y .NET Core.

En este artículo se resumen las diferencias significativas y los cambios importantes entre
Windows PowerShell y la versión actual de PowerShell. El resumen no incluye nuevas
características ni cmdlets que se han agregado. En el artículo tampoco se habla de los
cambios entre versiones. El objetivo de este artículo es presentar el estado actual de
PowerShell y en qué difiere de Windows PowerShell. Para obtener una explicación
detallada de los cambios entre versiones y la incorporación de nuevas características,
vea los artículos Novedades de cada versión.

Novedades de PowerShell 7.4


Novedades de PowerShell 7.3
Novedades de PowerShell 7.2
Novedades de PowerShell 7.1
Novedades de PowerShell 7.0
Novedades de PowerShell 6.x

.NET Framework frente a .NET Core


PowerShell en Linux y macOS usa .NET Core, que es un subconjunto de la instancia
completa de .NET Framework en Microsoft Windows. Esto es importante, porque
PowerShell proporciona acceso directo a los tipos de marco subyacentes y los métodos.
Como resultado, los scripts que se ejecutan en Windows pueden no ejecutarse en
plataformas que no son de Windows por las diferencias en los marcos. Para obtener más
información sobre los cambios en .NET Core, vea Cambios importantes para la
migración desde .NET Framework a .NET Core.

Cada nueva versión de PowerShell se basa en una versión más reciente de .NET. Puede
haber cambios rotundos en .NET que afecten a PowerShell.

PowerShell 7.3: basado en .NET 7.0


PowerShell 7.2 (LTS-current): basado en .NET 6.0 (LTS-current)
PowerShell 7.1: basado en .NET 5.0
PowerShell 7.0 (LTS): basado en .NET Core 3.1 (LTS)
PowerShell 6.2: basado en .NET Core 2.1
PowerShell 6.1: basado en .NET Core 2.1
PowerShell 6.0: basado en .NET Core 2.0

Con el lanzamiento de .NET Standard 2.0 , PowerShell puede cargar muchos módulos
tradicionales de Windows PowerShell sin modificación. Además, PowerShell 7 incluye
una característica de compatibilidad de Windows PowerShell que permite usar módulos
de Windows PowerShell que todavía requieren el marco completo.

Para obtener más información, consulte:

about_Windows_PowerShell_Compatibility
Compatibilidad del módulo de PowerShell 7

Módulos que ya no se incluyen en PowerShell


Por distintas razones de compatibilidad, los módulos a continuación ya no se incluyen
en PowerShell.

ISE
Microsoft.PowerShell.LocalAccounts
Microsoft.PowerShell.ODataUtils
Microsoft.PowerShell.Operation.Validation
PSScheduledJob
PSWorkflow
PSWorkflowUtility

Flujo de trabajo de PowerShell


El flujo de trabajo de PowerShell es una característica de Windows PowerShell basada en
Windows Workflow Foundation (WF) que permite la creación de runbooks sólidos para
tareas de larga ejecución o paralelizadas.
Debido a la falta de compatibilidad con Windows Workflow Foundation en .NET Core, se
ha quitado de PowerShell el flujo de trabajo de PowerShell.

En el futuro, nos gustaría habilitar paralelismo nativo/simultaneidad en el lenguaje de


PowerShell sin la necesidad del flujo de trabajo de PowerShell.

Si es necesario usar puntos de control para reanudar un script una vez reiniciado el
sistema operativo, recomendamos usar Programador de tareas para ejecutar un script al
iniciarse el sistema operativo, pero el script debería mantener su propio estado (como
conservarlo en un archivo).

Cmdlets quitados de PowerShell


En los módulos incluidos en PowerShell, se han quitado los cmdlets de PowerShell a
continuación por distintos motivos de compatibilidad o el uso de API no admitidas.

CimCmdlets

Export-BinaryMiLog

Microsoft.PowerShell.Core

Add-PSSnapin

Export-Console
Get-PSSnapin

Remove-PSSnapin

Resume-Job
Suspend-Job

Microsoft.PowerShell.Diagnostics

Export-Counter

Import-Counter

Microsoft.PowerShell.Management

Add-Computer

Checkpoint-Computer
Clear-EventLog

Complete-Transaction

Disable-ComputerRestore
Enable-ComputerRestore

Get-ComputerRestorePoint
Get-ControlPanelItem

Get-EventLog
Get-Transaction

Get-WmiObject
Invoke-WmiMethod

Limit-EventLog

New-EventLog
New-WebServiceProxy

Register-WmiEvent
Remove-Computer

Remove-EventLog

Remove-WmiObject
Reset-ComputerMachinePassword

Restore-Computer
Set-WmiInstance

Show-ControlPanelItem

Show-EventLog
Start-Transaction

Test-ComputerSecureChannel
Undo-Transaction

Use-Transaction
Write-EventLog

Microsoft.PowerShell.Utility

Convert-String
ConvertFrom-String

PSDesiredStateConfiguration

Disable-DscDebug

Enable-DscDebug

Get-DscConfiguration
Get-DscConfigurationStatus

Get-DscLocalConfigurationManager
Publish-DscConfiguration

Remove-DscConfigurationDocument

Restore-DscConfiguration
Set-DscLocalConfigurationManager
Start-DscConfiguration

Stop-DscConfiguration
Test-DscConfiguration

Update-DscConfiguration

Cmdlets WMI v1
Los cmdlets de WMI v1 siguientes se han quitado de PowerShell:

Register-WmiEvent
Set-WmiInstance

Invoke-WmiMethod

Get-WmiObject
Remove-WmiObject

Los cmdlets del módulo CimCmdlets (también conocido como WMI v2) realizan la
misma función, y proporcionan nueva funcionalidad y una sintaxis rediseñada.

Cmdlet New-WebServiceProxy quitado


.NET Core no es compatible con Windows Communication Framework, que proporciona
servicios para usar el protocolo SOAP. Este cmdlet se quitó porque requiere SOAP.

*-Transaction cmdlets quitados

Estos cmdlets tenían un uso muy limitado. Se tomó la decisión de dejar de admitirlos.

Complete-Transaction

Get-Transaction
Start-Transaction

Undo-Transaction

Use-Transaction

Cmdlets de *-EventLog
Debido al uso de API no admitidas, los cmdlets de *-EventLog se han quitado de
PowerShell. Get-WinEvent y New-WinEvent están disponibles para obtener y crear
eventos en Windows.
Cmdlets que usan Windows Presentation Framework
(WPF)
.NET Core 3.1 incorporó compatibilidad con WPF, por lo que el lanzamiento de
PowerShell 7.0 ha restaurado las características específicas de Windows siguientes:

El cmdlet Show-Command
El cmdlet Out-GridView
El parámetro ShowWindow de Get-Help

Cambios de Desired State Configuration (DSC) de


PowerShell
Invoke-DscResource se restauró como característica experimental en PowerShell 7.0.

A partir de PowerShell 7.2, el módulo PSDesiredStateConfiguration se ha quitado de


PowerShell y se ha publicado en la Galería de PowerShell. Para obtener más información,
vea el anuncio en el blog del equipo de PowerShell.

Cambios en el archivo ejecutable de PowerShell

Cambio de nombre de powershell.exe a pwsh.exe


El nombre binario de PowerShell se ha cambiado de powershell(.exe) a pwsh(.exe) .
Este cambio proporciona una forma determinista de ejecutar PowerShell en las
máquinas y de admitir instalaciones en paralelo de Windows PowerShell y PowerShell.

Cambios adicionales en pwsh(.exe) con respecto a powershell.exe :

Se ha cambiado el primer parámetro posicional de -Command a -File . Este cambio


corrige el uso de #! (también conocido como par de caracteres shebang) en los
scripts de PowerShell que se ejecutan desde shells que no son de PowerShell en
plataformas distintas de Windows. También implica que se pueden ejecutar
comandos como pwsh foo.ps1 o pwsh fooScript sin especificar -File . Aun así,
este cambio requiere que se especifique explícitamente -c o -Command al intentar
ejecutar comandos como pwsh.exe -Command Get-Command .
pwsh acepta el modificador -i (o -Interactive ) para indicar un shell interactivo.

Esto permite usar PowerShell como shell predeterminado en plataformas Unix.


Se han quitado los parámetros -ImportSystemModules y -PSConsoleFile de
pwsh.exe .
Se ha cambiado pwsh -version y se ha integrado ayuda para pwsh.exe para que
sea acorde con otras herramientas nativas.
Mensajes de error de argumento no válido para -File y -Command y códigos de
salida coherentes con los estándares de Unix
Se ha agregado el parámetro -WindowStyle en Windows. De forma similar, las
actualizaciones de instalaciones basadas en paquete en plataformas no Windows
son actualizaciones en contexto.

El nombre abreviado también es coherente con la nomenclatura de los shells en las


plataformas que no son de Windows.

Compatibilidad con la ejecución de un script de


PowerShell con el parámetro bool
Anteriormente, el uso de pwsh.exe para ejecutar un script de PowerShell con -File no
proporcionaba ninguna forma de pasar $true / $false como valores de parámetro. La
compatibilidad con $true / $false como valores analizados de parámetros se agregó.
También se admiten valores de modificador.

Compatibilidad con versiones anteriores


mejoradas con Windows PowerShell
En Windows, se agrega un nuevo parámetro de modificador UseWindowsPowerShell a
Import-Module . Este modificador crea un módulo de proxy en PowerShell 7 que usa un

proceso local de Windows PowerShell para ejecutar implícitamente los cmdlets


contenidos en ese módulo. Para obtener más información, consulte Import-Module.

Para más información sobre qué módulos de Microsoft funcionan con PowerShell 7.0,
vea la tabla de compatibilidad de módulos .

Soporte técnico de Microsoft Update en Windows


PowerShell 7.2 incluyó soporte técnico con Microsoft Update. Al habilitar esta
característica, se obtienen las actualizaciones más recientes de PowerShell 7 en el flujo
de administración tradicional de Windows Update (WU), ya sea con Windows Update for
Business, WSUS, SCCM o el cuadro de diálogo WU interactivo de Configuración.

El paquete MSI de PowerShell 7.2 incluye las siguientes opciones de línea de comandos:

USE_MU : esta propiedad tiene dos valores posibles:


1 (valor predeterminado): permite actualizar mediante Microsoft Update o

WSUS
0 : no permite realizar la actualización mediante Microsoft Update o WSUS

ENABLE_MU
1 (valor predeterminado): permite usar Microsoft Update para las

actualizaciones automáticas o Windows Update.


0 : no permite usar Microsoft Update para las actualizaciones automáticas o
Windows Update

Cambios en el motor

Compatibilidad de PowerShell como shell de Unix


predeterminado
En Unix, es una convención para que los shells acepten -i para un shell interactivo y
muchas herramientas esperan este comportamiento ( script por ejemplo y al establecer
PowerShell como el shell predeterminado) y llama al shell con el conmutador -i . Este
cambio es importante en que -i podía usarse anteriormente como fórmula sencilla
para coincidir con -inputformat , que ahora debe ser -in .

Complementos personalizados
Los complementos de PowerShell son un predecesor de los módulos de PowerShell
cuya adopción en la comunidad de PowerShell no está generalizada.

Debido a la complejidad de admitir complementos y a su falta de uso en la comunidad,


ya no se admiten complementos personalizados en PowerShell.

Marcas de características experimentales


En PowerShell 6.2 ya habíamos habilitado la compatibilidad con las características
experimentales. Esto permite a los desarrolladores de PowerShell ofrecer nuevas
características y obtener comentarios antes de completar el diseño. De este modo,
evitamos realizar cambios importantes a medida que evoluciona el diseño.

Use Get-ExperimentalFeature para obtener una lista de las características


experimentales disponibles. Puede habilitar o deshabilitar estas características con
Enable-ExperimentalFeature y Disable-ExperimentalFeature .
Carga de un ensamblado desde la ruta de acceso base del
módulo antes de intentar cargar desde GAC
Anteriormente, si un módulo binario tenía el ensamblado de módulo en GAC, se
cargaba el ensamblado desde GAC antes de intentar cargarlo desde la ruta de acceso
base del módulo.

Omisión de la comprobación del elemento NULL en las


colecciones con un tipo de elemento de tipo de valor
En el parámetro Mandatory y los atributos ValidateNotNull y ValidateNotNullOrEmpty ,
omita la comprobación del elemento NULL si el tipo de elemento de la colección es tipo
de valor.

Conservación de $? en ParenExpression, SubExpression y


ArrayExpression
Esta solicitud de incorporación de cambios modifica la forma en que se compilan las
subcanalizaciones (...) , las subexpresiones $(...) y las expresiones de matriz @()
para que $? no sea automáticamente true. En su lugar, el valor de $? depende del
resultado de la canalización o las instrucciones ejecutadas.

Corrección de $? para que no sea $false cuando el


comando nativo escribe en stderr
$? no se establece en $false cuando el comando nativo escribe en stderr . Es habitual

que los comandos nativos escriban en stderr sin intención de indicar un error. $? se
establece en $false únicamente cuando el comando nativo tiene un código de salida
distinto de cero.

$ErrorActionPreference no afecta a la salida stderr de los


comandos nativos
Es habitual que los comandos nativos escriban en stderr sin intención de indicar un
error. Con este cambio, la salida de stderr se sigue capturando en los objetos
ErrorRecord, pero el entorno de ejecución ya no aplica $ErrorActionPreference si
ErrorRecord proviene de un comando nativo.
Cambio de $OutputEncoding para usar codificación UTF-8
NoBOM en lugar de ASCII

La codificación anterior, ASCII (7 bits), daría lugar a una alteración incorrecta de la salida
en algunos casos. Al convertir UTF-8 NoBOM en el valor predeterminado, se conserva la
salida Unicode con una codificación admitida por la mayoría de las herramientas y los
sistemas operativos.

Unificación de los cmdlets con el parámetro -Encoding


para que sean de tipo System.Text.Encoding
El valor -Encoding Byte se ha quitado de los cmdlets del proveedor del sistema de
archivos. Un nuevo parámetro, -AsByteStream , se usa ahora para especificar que un flujo
de bytes se necesita como entrada o que la salida es un flujo de bytes.

Cambio de la codificación New-ModuleManifest por


UTF8NoBOM en plataformas no Windows

Anteriormente, New-ModuleManifest creaba manifiestos psd1 en UTF-16 con BOM, lo


que creaba un problema para las herramientas de Linux. Este cambio importante cambia
la codificación de New-ModuleManifest para que sea UTF (sin BOM) en plataformas que
no son de Windows.

Eliminación de AllScope de la mayoría de los alias


predeterminados
Para acelerar la creación de ámbito, AllScope se quitó de la mayoría de los alias
predeterminados. AllScope se dejó para un alias no usado con frecuencia donde la
búsqueda era más rápida.

-Verbose y -Debug ya no invalidan $ErrorActionPreference

Anteriormente, si se especificaban -Verbose o -Debug , invalidaba el comportamiento de


$ErrorActionPreference . Con este cambio, -Verbose y -Debug ya no influyen en el
comportamiento de $ErrorActionPreference .

Además, el parámetro -Debug establece $DebugPreference en Continue en lugar de en


Inquire.
$PSCulture refleja de forma coherente los cambios en la
referencia cultural en la sesión
En Windows PowerShell, el valor actual de la referencia cultural se almacena en caché, lo
que puede permitir que el valor se desincronice si la referencia cultural se cambia
después de iniciar sesión. Este comportamiento de almacenamiento en caché se ha
corregido en PowerShell Core.

Permisos para que un parámetro con nombre


especificado explícitamente reemplace al mismo de la
expansión mediante tabla hash
Con este cambio, los parámetros con nombre de la expansión se mueven al final de la
lista de parámetros para que se enlacen después de que se hayan enlazado todos los
parámetros con nombre especificados explícitamente. El enlace de parámetros para
funciones simples no produce ningún error cuando no se puede encontrar un
parámetro con nombre especificado. Los parámetros con nombre desconocidos se
enlazan con el parámetro $args de la función simple. Al mover la expansión al final de
la lista de argumentos, se cambia el orden en el que aparecen los parámetros en $args .

Por ejemplo:

PowerShell

function SimpleTest {
param(
$Name,
$Path
)
"Name: $Name; Path: $Path; Args: $args"
}

En el comportamiento anterior, MyPath no está enlazado con -Path porque es el tercer


argumento de la lista de argumentos. ## Por lo tanto, termina rellenándose en "$args"
junto con Blah = "World" .

PowerShell

PS> $hash = @{ Name = "Hello"; Blah = "World" }


PS> SimpleTest @hash "MyPath"
Name: Hello; Path: ; Args: -Blah: World MyPath
Con este cambio, los argumentos de @hash se mueven al final de la lista de argumentos.
MyPath se convierte en el primer argumento de la lista, así que está enlazado con -
Path .

PowerShell

PS> SimpleTest @hash "MyPath"


Name: Hello; Path: MyPath; Args: -Blah: World

Cambios de idioma

Operador de fusión de NULL ??


El operador de fusión de NULL ?? devuelve el valor de su operando de la izquierda si
no es NULL. De lo contrario, evalúa el operando de la derecha y devuelve su resultado.
El operador ?? no evalúa su operando de la derecha si el operando de la izquierda se
evalúa como no NULL.

PowerShell

$x = $null
$x ?? 100

Output

100

En el ejemplo siguiente, el operando de la derecha no se evaluará.

PowerShell

[string] $todaysDate = '1/10/2020'


$todaysDate ?? (Get-Date).ToShortDateString()

Output

1/10/2020

Operador de asignación de coalescencia NULL ??=


El operador de asignación de coalescencia NULL ??= asigna el valor del operando de la
derecha a su operando de la izquierda solo si este último se evalúa como NULL. El
operador ??= no evalúa su operando de la derecha si el operando de la izquierda se
evalúa como no NULL.

PowerShell

$x = $null
$x ??= 100
$x

Output

100

En el ejemplo siguiente, el operando de la derecha no se evaluará.

PowerShell

[string] $todaysDate = '1/10/2020'


$todaysDate ??= (Get-Date).ToShortDateString()

Output

1/10/2020

Operadores condicionales NULL

7 Nota

Esta característica se movió de la rama experimental a la estándar en


PowerShell 7.1.

Un operador condicional NULL aplica un acceso a miembros, ?. , o el acceso a


elementos, ?[] , operación a su operando solo si ese operando se evalúa como no
NULL; de lo contrario, devuelve NULL.

Puesto que PowerShell permite que ? forme parte del nombre de la variable, se
requiere la especificación formal del nombre de la variable para utilizar estos
operadores. Por lo tanto, es necesario usar {} en torno a los nombres de variable como
${a} o cuando ? forma parte del nombre de la variable ${a?} .
En el siguiente ejemplo, se devuelve el valor de PropName.

PowerShell

$a = @{ PropName = 100 }
${a}?.PropName

Output

100

En el ejemplo siguiente se devolverá NULL, sin intentar acceder al nombre de miembro


PropName.

PowerShell

$a = $null
${a}?.PropName

Del mismo modo se devolverá el valor del elemento.

PowerShell

$a = 1..10
${a}?[0]

Output

Y cuando el operando es NULL, no se accede al elemento y se devuelve NULL.

PowerShell

$a = $null
${a}?[0]

7 Nota

La sintaxis de nombre de variable de ${<name>} no debe confundirse con el


operador de subexpresión $() . Para obtener más información, consulte la sección
Nombre de variable de about_Variables.
Incorporación del operador & para el control de un
trabajo
Cuando se incluye & al final de una canalización, esta se ejecuta como un trabajo de
PowerShell. Cuando una canalización se pasa a segundo plano, se devuelve un objeto
de trabajo. Una vez que la canalización se ejecuta como un trabajo, se pueden usar
todos los cmdlets *-Job estándar para administrar el trabajo. Las variables (se omiten
las específicas del proceso) que se usan en la canalización se copian automáticamente
en el trabajo para que funcione Copy-Item $foo $bar & . El trabajo también se ejecuta en
el directorio actual, en lugar del directorio principal del usuario.

Nuevos métodos y propiedades en PSCustomObject


Se han agregado nuevos métodos y propiedades a PSCustomObject . PSCustomObject
ahora incluye una propiedad Count / Length como otros objetos.

PowerShell

$PSCustomObject = [pscustomobject]@{foo = 1}

$PSCustomObject.Length

Output

PowerShell

$PSCustomObject.Count

Output

Este trabajo también incluye los métodos ForEach y Where que permiten operar y filtrar
en elementos PSCustomObject :

PowerShell

$PSCustomObject.ForEach({$_.foo + 1})
Output

PowerShell

$PSCustomObject.Where({$_.foo -gt 0})

Output

foo
---
1

Conversiones de PSMethod a delegado


Puede convertir PSMethod en un delegado. Esto permite hacer cosas como pasar
PSMethod [M]::DoubleStrLen como un valor de delegado en [M]::AggregateString :

PowerShell

class M {
static [int] DoubleStrLen([string] $value) { return 2 * $value.Length }

static [long] AggregateString([string[]] $values, [func[string, int]]


$selector) {
[long] $res = 0
foreach($s in $values){
$res += $selector.Invoke($s)
}
return $res
}
}

[M]::AggregateString((gci).Name, [M]::DoubleStrLen)

Comportamiento de comparación de cadenas cambiado


en PowerShell 7.1
PowerShell 7.1 se basa en .NET 5.0, que introdujo el siguiente cambio rotundo:

Cambios de comportamiento al comparar cadenas en .NET 5 +


A partir de .NET 5.0, las comparaciones de cadenas de referencia cultural invariable
omiten los caracteres de control no imprimibles.

Por ejemplo, las dos cadenas siguientes se consideran idénticas:

PowerShell

# Escape sequence "`a" is Ctrl-G or [char]7


'Food' -eq "Foo`ad"

Output

True

Nuevos cmdlets

Nuevo cmdlet Get-Uptime


El cmdlet Get-Uptime devuelve el tiempo transcurrido desde el último arranque del
sistema operativo. Este cmdlet se introdujo en PowerShell 6.0.

Nuevo cmdlet Remove-Alias


El cmdlet Remove-Alias quita un alias de la sesión actual de PowerShell. Este cmdlet se
introdujo en PowerShell 6.0.

Nuevo cmdlet Remove-Service


El cmdlet Remove-Service quita un servicio de Windows del Registro y de la base de
datos del servicio. El cmdlet Remove-Service se introdujo en PowerShell 6.0.

Nuevos cmdlets de Markdown


Markdown es un estándar para crear documentos de texto simple legible con el formato
básico que se puede representar en HTML.

Los siguientes cmdlets se agregaron en PowerShell 6.1:

ConvertFrom-Markdown: convierte el contenido de una cadena o un archivo en un


objeto MarkdownInfo.
Get-MarkdownOption: devuelve los colores y estilos actuales que se usan para
representar el contenido de Markdown en la consola.
Set-MarkdownOption: devuelve los colores y estilos actuales que se usan para
representar el contenido de Markdown en la consola.
Show-Markdown: muestra el contenido de Markdown en la consola o como HTML.

Nuevo cmdlet Test-Json


El cmdlet Test-Json prueba si una cadena es un documento válido de notación de
objetos JavaScript (JSON) y puede comprobar opcionalmente el documento JSON
según un esquema proporcionado.

Este cmdlet se introdujo en PowerShell 6.1.

Nuevos cmdlets para admitir características


experimentales
Los siguientes cmdlets se agregaron en PowerShell 6.2 para admitir características
experimentales.

Disable-ExperimentalFeature
Enable-ExperimentalFeature
Get-ExperimentalFeature

Nuevo cmdlet Join-String


El cmdlet Join-String combina objetos de la canalización en una sola cadena. Este
cmdlet se agregó en PowerShell 6.2.

Nueva vista ConciseView y cmdlet Get-Error


PowerShell 7.0 mejora la visualización de los mensajes de error para aumentar la
legibilidad de los errores interactivos y de script con una nueva vista predeterminada,
ConciseView. Las vistas las puede seleccionar el usuario a través de la variable de
preferencia $ErrorView .

Con ConciseView, si no se trata de un error de script o de analizador, se trata de un


mensaje de error de una sola línea:

PowerShell

Get-Childitem -Path c:\NotReal


Output

Get-ChildItem: Cannot find path 'C:\NotReal' because it does not exist

Si el error se produce durante la ejecución del script o es un error de análisis, PowerShell


devuelve un mensaje de error de varias líneas que contiene el error, un puntero y un
mensaje de error que muestra dónde se encuentra el error en esa línea. Si el terminal no
es compatible con las secuencias de escape de color ANSI (VT100), no se muestran los
colores.

La vista predeterminada de PowerShell 7 es ConciseView. La vista predeterminada


anterior era NormalView; para seleccionarla, el usuario puede establecer la variable de
preferencia $ErrorView .

PowerShell

$ErrorView = 'NormalView' # Sets the error view to NormalView


$ErrorView = 'ConciseView' # Sets the error view to ConciseView

7 Nota

Se agrega una nueva propiedad ErrorAccentColor a $Host.PrivateData para


admitir el cambio del color de énfasis del mensaje de error.

El nuevo cmdlet Get-Error proporciona una vista detallada del error completo cuando
se solicite. De forma predeterminada, el cmdlet muestra todos los detalles, incluidas las
excepciones internas, del último error que se produjo.

El cmdlet Get-Error admite la entrada desde la canalización mediante la variable


$Error integrada. Get-Error muestra todos los errores canalizados.

PowerShell

$Error | Get-Error

El cmdlet Get-Error admite el parámetro Newest, lo que le permite especificar el


número de errores de la sesión actual que desea mostrar.

PowerShell
Get-Error -Newest 3 # Displays the lst three errors that occurred in the
session

Para obtener más información, consulte Get-Error.

Cambios en el cmdlet

Ejecución en paralelo agregada a ForEach-Object


A partir de PowerShell 7.0, el cmdlet ForEach-Object , que itera los elementos de una
colección, ahora tiene un paralelismo integrado con el nuevo parámetro Parallel.

De forma predeterminada, los bloques de script paralelos usan el directorio de trabajo


actual del autor de la llamada que inició las tareas paralelas.

En este ejemplo se recuperan 50 000 entradas de registro de cinco registros del sistema
en una máquina local Windows:

PowerShell

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

$logEntries = $logNames | ForEach-Object -Parallel {


Get-WinEvent -LogName $_ -MaxEvents 10000
} -ThrottleLimit 5

$logEntries.Count

50000

El parámetro Parallel especifica el bloque de script que se ejecuta en paralelo para cada
nombre de registro de entrada.

El nuevo parámetro ThrottleLimit limita el número de bloques de scripts que se


ejecutan en paralelo en un momento dado. El valor predeterminado es 5.

Use la variable $_ para representar el objeto de entrada actual en el bloque de scripts.


Utilice el ámbito $using: para pasar las referencias de variable al bloque de script en
ejecución.

Para obtener más información, consulte ForEach-Object.


Comprobación de system32 para conocer los módulos
integrados compatibles en Windows
En la actualización 1809 de Windows 10 y Windows Server 2019 se han actualizado una
serie de módulos integrados de PowerShell para marcarlos como compatibles con
PowerShell.

Cuando PowerShell se inicia, incluye automáticamente $windir\System32 como parte de


la variable de entorno PSModulePath . Pero solo expone módulos a Get-Module y Import-
Module si su CompatiblePSEdition está marcado como compatible con Core .

Puede invalidar este comportamiento para que se muestren todos los módulos
mediante el parámetro de modificador -SkipEditionCheck . También hemos agregado
una propiedad PSEdition a la salida de la tabla.

Alias -lp para todos los parámetros -LiteralPath


Se ha creado un alias de parámetro estándar -lp para todos los cmdlets integrados de
PowerShell que tienen un parámetro -LiteralPath .

Corrección de Get-Item -LiteralPath a*b si a*b no existe


realmente para devolver un error
Anteriormente, -LiteralPath al que se le daba un carácter comodín lo trataría de la
misma forma que -Path y, si el carácter comodín no encontraba ningún archivo, existiría
en modo silencioso. El comportamiento correcto debería ser que -LiteralPath fuera
literal de modo que, de no existir el archivo, debería producir un error. El cambio
consiste en tratar los caracteres comodín usados con -Literal como literales.

Establecimiento del directorio de trabajo en el directorio


actual en Start-Job
El cmdlet Start-Job ahora usa el directorio actual como directorio de trabajo del nuevo
trabajo.

Eliminación de -Protocol de los cmdlets de *-Computer


Debido a problemas con la comunicación remota RPC en CoreFX (especialmente en
plataformas que no son de Windows) y la garantía de una experiencia de comunicación
remota coherente en PowerShell, el parámetro -Protocol se quitó de los cmdlets \*-
Computer . DCOM ya no se admite para la comunicación remota. Los cmdlets siguientes
solo admiten la comunicación remota mediante WSMAN:

Rename-Computer
Restart-Computer

Stop-Computer

Eliminación de -ComputerName de los cmdlets de *-Service


Para fomentar el uso coherente de PSRP, el parámetro -ComputerName se quitó de los
cmdlets *-Service .

Corrección de Get-Content -Delimiter para no incluir el


delimitador en las líneas devueltas
Anteriormente, la salida mientras se usaba Get-Content -Delimiter era incoherente e
incómoda, ya que requería un mayor procesamiento de los datos para quitar el
delimitador. Este cambio quita el delimitador en líneas devueltas.

Cambios en Format-Hex
El parámetro -Raw ahora es un "no-op" (ahí no hace nada). En adelante, toda salida se
muestra con una representación verdadera de números que incluye todos los bytes de
su tipo. Esto es lo que hacía el parámetro -Raw antes de este cambio.

Corrección de error de escritura en el nombre de la


propiedad Get-ComputerInfo
BiosSerialNumber se escribió incorrectamente como BiosSeralNumber y se ha cambiado
a la ortografía correcta.

Incorporación de los cmdlets Get-StringHash y Get-


FileHash

Este cambio consiste en que algunos algoritmos hash no son compatibles con CoreFX,
por lo que ya no están disponibles:

MACTripleDES
RIPEMD160

Incorporación de validación a los cmdlets de Get-*


donde al pasar $null se devuelven todos los objetos en
lugar de un error
Ahora, al pasar $null a cualquiera de los siguientes elementos, se muestra un error:

Get-Credential -UserName

Get-Event -SourceIdentifier
Get-EventSubscriber -SourceIdentifier

Get-Help -Name

Get-PSBreakpoint -Script
Get-PSProvider -PSProvider

Get-PSSessionConfiguration -Name
Get-Runspace -Name

Get-RunspaceDebug -RunspaceName

Get-Service -Name
Get-TraceSource -Name

Get-Variable -Name

Incorporación de compatibilidad con el formato de


archivo de registro extendido W3C en Import-Csv
Anteriormente, el cmdlet Import-Csv no se podía usar directamente para importar los
archivos de registro en el formato de registro extendido W3C y se requerían medidas
adicionales. Con este cambio, el formato de registro extendido W3C se admite.

Import-Csv aplica PSTypeNames durante la importación


cuando la información de tipo está presente en el CSV
Anteriormente, los objetos exportados mediante el uso de Export-CSV con
TypeInformation importado con ConvertFrom-Csv no retenían la información de tipo.
Este cambio agrega la información de tipo al miembro PSTypeNames si está disponible
desde el archivo CSV.

-NoTypeInformation es el valor predeterminado en


Export-Csv
Anteriormente, el cmdlet Export-CSV generaba un comentario como primera línea que
incluía el nombre de tipo del objeto. El cambio excluye la información de tipo de
manera predeterminada porque la mayoría de las herramientas CSV no la entienden.
Este cambio se ha realizado en respuesta a los comentarios de los clientes.

Use -IncludeTypeInformation para retener el comportamiento anterior.

Permiso para usar * en la ruta de acceso del Registro


para Remove-Item
Anteriormente, -LiteralPath al que se le daba un carácter comodín lo trataría de la
misma forma que -Path y, si el carácter comodín no encontraba ningún archivo, existiría
en modo silencioso. El comportamiento correcto debería ser que -LiteralPath fuera
literal de modo que, de no existir el archivo, debería producir un error. El cambio
consiste en tratar los caracteres comodín usados con -Literal como literales.

Ahora, Group-Object ordena los grupos


Como parte de la mejora del rendimiento, Group-Object ahora devuelve una lista
ordenada de los grupos. Aunque no debe confiar en el orden, podría verse interrumpida
por este cambio si quisiera el primer grupo. Decidimos que esta mejora en el
rendimiento valía la pena el cambio, ya que el impacto de depender del
comportamiento previo es bajo.

Desviación estándar en Measure-Object


La salida de Measure-Object ahora incluye una propiedad StandardDeviation .

PowerShell

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

Output

Count : 308
Average : 31.3720576298701
Sum : 9662.59375
Maximum : 4416.046875
Minimum :
StandardDeviation : 264.389544720926
Property : CPU
Get-PfxCertificate -Password

Get-PfxCertificate tiene ahora el parámetro Password , que toma SecureString . Esto

permite usarlo de forma no interactiva:

PowerShell

$certFile = '\\server\share\pwd-protected.pfx'
$certPass = Read-Host -AsSecureString -Prompt 'Enter the password for
certificate: '

$certThumbPrint = (Get-PfxCertificate -FilePath $certFile -Password


$certPass ).ThumbPrint

Eliminación de la función more


Antes, PowerShell incluía una función en Windows llamada more que encapsulaba
more.com . Se ha quitado esa función.

Además, se ha cambiado la función help para usar more.com en Windows o el elemento


de paginación del sistema predeterminado especificado por $env:PAGER en plataformas
que no sean Windows.

cd DriveName: ahora devuelve a los usuarios al directorio


de trabajo actual en esa unidad
Antes, al usar Set-Location o cd para volver a un PSDrive enviaba a los usuarios a la
ubicación predeterminada para esa unidad. Ahora se envía a los usuarios al último
directorio de trabajo actual conocido de esa sesión.

cd - vuelve al directorio anterior

PowerShell

C:\Windows\System32> cd C:\
C:\> cd -
C:\Windows\System32>

O en Linux:

ShellSession
PS /etc> cd /usr/bin
PS /usr/bin> cd -
PS /etc>

Además, cd y cd -- cambian a $HOME .

Update-Help como no administrador

Por petición popular, Update-Help ya no debe ejecutarse como administrador. Update-


Help ahora tiene como valor predeterminado guardar la Ayuda en una carpeta con

ámbito de usuario.

Where-Object -Not

Con la incorporación del parámetro -Not a Where-Object , puede filtrar un objeto en la


canalización para la no existencia de una propiedad o un valor de propiedad nula o
vacía.

Por ejemplo, este comando devuelve todos los servicios que no tienen los servicios
dependientes definidos:

PowerShell

Get-Service | Where-Object -Not DependentServices

Cambios en los cmdlets web


La API de .NET subyacente de los cmdlets web se ha cambiado a
System.Net.Http.HttpClient . Este cambio ofrece muchas ventajas. Sin embargo, este
cambio y una falta de interoperabilidad con Internet Explorer han dado lugar a varios
cambios importantes en Invoke-WebRequest y Invoke-RestMethod .

Invoke-WebRequest ahora solo admite un análisis básico de HTML. Invoke-


WebRequest siempre devuelve un objeto BasicHtmlWebResponseObject . Las

propiedades ParsedHtml y Forms se han quitado.


Los valores BasicHtmlWebResponseObject.Headers ahora son String[] en lugar de
String .

BasicHtmlWebResponseObject.BaseResponse ahora es un objeto


System.Net.Http.HttpResponseMessage .
La propiedad Response de excepciones de cmdlets web ahora es un objeto
System.Net.Http.HttpResponseMessage .
El análisis estricto del encabezado RFC ahora es el valor predeterminado de los
parámetros -Headers y -UserAgent . Esto se puede omitir con -
SkipHeaderValidation .

Los esquemas de URI file:// y ftp:// ya no se admiten.


La configuración System.Net.ServicePointManager ya no se admite.
Actualmente no hay ninguna autenticación disponible en macOS basada en
certificado.
El uso de -Credential sobre un URI http:// dará lugar a un error. Use un URI
https:// o proporcione el parámetro -AllowUnencryptedAuthentication para

suprimir el error.
-MaximumRedirection ahora genera un error de terminación cuando los intentos de

redirección superan el límite proporcionado en lugar de devolver los resultados de


la última redirección.
En PowerShell 6.2, se ha realizado un cambio para usar de forma predeterminada
la codificación UTF-8 en las respuestas JSON. Cuando no se proporciona un juego
de caracteres para una respuesta JSON, la codificación predeterminada debe ser
UTF-8 según la norma RFC 8259.
Codificación predeterminada establecida en UTF-8 para respuestas application-
json
Incorporación del parámetro -SkipHeaderValidation para permitir encabezados
Content-Type que no son compatibles con estándares

Incorporación del parámetro -Form para admitir compatibilidad con


multipart/form-data simplificada

Control compatible que distingue entre mayúsculas y minúsculas de claves de


relación
Incorporación del parámetro -Resume para cmdlets web

Invoke-RestMethod devuelve información útil cuando no


se devuelven datos
Cuando una API devolvía simplemente null , Invoke-RestMethod lo serializaba como la
cadena "null" en lugar de $null . Este cambio corrige la lógica en Invoke-RestMethod
para serializar correctamente un valor único válido JSON null literal como $null .

Los cmdlets web avisan cada vez que -Credential se


envía a través de conexiones sin cifrar
Al usar HTTP, el contenido y las contraseñas se envían como texto no cifrado. Este
cambio consiste en no permitir esto de forma predeterminada y devolver un error si las
credenciales se pasan de forma segura. Los usuarios pueden omitir esto con el
conmutador -AllowUnencryptedAuthentication .

Se ha creado el parámetro -OutFile en cmdlets web para


que funcione como -LiteralPath .
A partir de PowerShell 7.1, el parámetro OutFile de los cmdlets web funciona como
LiteralPath y no procesa caracteres comodín.

Cambios de API

Eliminación de la clase AddTypeCommandBase


La clase AddTypeCommandBase se quitó de Add-Type para mejorar el rendimiento. El
cmdlet Add-Type es el único que usa esta clase, por lo que no debe afectar a los
usuarios.

Se quitó VisualBasic como lenguaje compatible en Add-


Type
Antes, se podía compilar código de Visual Basic mediante el cmdlet Add-Type . Visual
Basic se usó rara vez con Add-Type . Hemos quitado esta característica para reducir el
tamaño de PowerShell.

Eliminación de la compatibilidad con


RunspaceConfiguration

Anteriormente, al crear un espacio de ejecución de PowerShell mediante programación


con la API, podía usar el elemento RunspaceConfiguration heredado o las clases
InitialSessionState más recientes. Este cambio quitó la compatibilidad con
RunspaceConfiguration y solo admite InitialSessionState .

CommandInvocationIntrinsics.InvokeScript enlaza
argumentos a $input en lugar de $args
Una posición incorrecta de un parámetro dio como resultado que los argumentos se
pasaran como entrada en lugar de como argumentos.

Eliminación de las propiedades ClrVersion y


BuildVersion de $PSVersionTable

La propiedad ClrVersion de $PSVersionTable no es útil con CoreCLR. Los usuarios


finales no deben usar ese valor para determinar la compatibilidad.

La propiedad BuildVersion estaba vinculada a la versión de compilación de Windows,


que no está disponible en plataformas no Windows. Use la propiedad GitCommitId para
recuperar la versión de compilación exacta de PowerShell.

Implementación de análisis de escape Unicode


`u#### o `u{####} se convierte en el carácter Unicode correspondiente. Para generar un
elemento `u literal, evite la tilde aguda: ``u .

Problema de enlace de parámetros con


ValueFromRemainingArguments en funciones de PS

ValueFromRemainingArguments ahora devuelve los valores como una matriz en lugar de


un solo valor que en sí mismo es una matriz.

Se limpiaron los usos de CommandTypes.Workflow y


WorkflowInfoCleaned

Limpie el código relacionado con los usos de CommandTypes.Workflow y WorkflowInfo en


System.Management.Automation.

Estos cambios importantes menores afectan principalmente al código del proveedor de


ayuda.

Cambie los constructores públicos de WorkflowInfo a internal. Ya no se admite el


flujo de trabajo, por lo que tiene sentido no permitir que los usuarios creen
instancias Workflow .
Quite el tipo System.Management.Automation.DebugSource, ya que solo se usa
para la depuración del flujo de trabajo.
Quite la sobrecarga de SetParent de la clase abstracta Debugger, que solo se usa
para la depuración del flujo de trabajo.
Quite la misma sobrecarga de SetParent de la clase derivada
RemotingJobDebugger.

No ajuste del resultado devuelto en PSObject al convertir


ScriptBlock en un delegado

Cuando un valor ScriptBlock se convierte en un tipo delegado que se debe usar en un


contexto de C#, al ajustar el resultado en un valor PSObject se producen problemas
innecesarios:

Cuando el valor se convierte en el tipo devuelto delegado, el valor PSObject ,


básicamente, se desajusta. Por lo tanto, no se necesita PSObject .
Cuando el tipo devuelto delegado es object , se ajusta en un valor PSObject , lo
que dificulta trabajar en un código de C#.

Después de este cambio, el objeto devuelto es el subyacente.

Compatibilidad con la comunicación remota


La comunicación remota de PowerShell (PSRP) mediante WinRM en plataformas Unix
requiere NTLM/Negotiate o autenticación básica a través de HTTPS. PSRP en macOS
solo admite autenticación básica a través de HTTPS. La autenticación basada en
Kerberos no se admite en las plataformas no Windows.

PowerShell también admite la comunicación remota de PowerShell (PSRP) a través de


SSH en todas las plataformas (Windows, macOS y Linux). Para obtener más información,
vea Comunicación remota de PowerShell a través de SSH.

PowerShell Direct para contenedores intenta usar primero


pwsh

PowerShell Direct es una característica de PowerShell e Hyper-V que permite


conectarse a una máquina virtual de Hyper-V o un contenedor sin conectividad de red u
otros servicios de administración remota.

Antes, PowerShell Direct se conectaba mediante la instancia de Windows PowerShell


integrada en el contenedor. Ahora, PowerShell Direct intenta primero conectarse usando
cualquier pwsh.exe disponible en la variable de entorno PATH . Si pwsh.exe no está
disponible, PowerShell Direct recurre a usar powershell.exe .
Enable-PSRemoting ahora crea puntos de conexión de
comunicación remota independientes para versiones
preliminares
Enable-PSRemoting ahora crea dos configuraciones de sesión de comunicación remota:

Una para la versión principal de PowerShell. Por ejemplo, PowerShell.6 . Este punto
de conexión en el que se puede confiar en todas las actualizaciones de versiones
secundarias como la configuración de sesión de PowerShell 6 "para todo el
sistema".
Una configuración de sesión específica de la versión, por ejemplo:
PowerShell.6.1.0

Este comportamiento es útil si quiere tener varias versiones de PowerShell 6 instaladas y


accesibles en la misma máquina.

Además, las versiones preliminares de PowerShell ahora obtienen sus propias


configuraciones de sesión de comunicación remota después de ejecutar el cmdlet
Enable-PSRemoting :

PowerShell

C:\WINDOWS\system32> Enable-PSRemoting

El resultado puede ser diferente si no ha configurado WinRM antes.

Output

WinRM is already set up to receive requests on this computer.


WinRM is already set up for remote management on this computer.

Después puede ver las configuraciones de sesión de PowerShell independientes para la


versión preliminar y compilaciones estables de PowerShell 6, para cada versión
específica.

PowerShell

Get-PSSessionConfiguration

Output

Name : PowerShell.6.2-preview.1
PSVersion : 6.2
StartupScript :
RunAsUser :
Permission : NT AUTHORITY\INTERACTIVE AccessAllowed,
BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users
AccessAllowed

Name : PowerShell.6-preview
PSVersion : 6.2
StartupScript :
RunAsUser :
Permission : NT AUTHORITY\INTERACTIVE AccessAllowed,
BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users
AccessAllowed

Name : powershell.6
PSVersion : 6.1
StartupScript :
RunAsUser :
Permission : NT AUTHORITY\INTERACTIVE AccessAllowed,
BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users
AccessAllowed

Name : powershell.6.1.0
PSVersion : 6.1
StartupScript :
RunAsUser :
Permission : NT AUTHORITY\INTERACTIVE AccessAllowed,
BUILTIN\Administrators AccessAllowed, BUILTIN\Remote Management Users
AccessAllowed

Sintaxis user@host:port para SSH


Los clientes SSH suelen admitir una cadena de conexión en el formato user@host:port .
Al agregar SSH como protocolo para la comunicación remota de PowerShell, se ha
agregado compatibilidad con este formato de cadena de conexión:

Enter-PSSession -HostName fooUser@ssh.contoso.com:2222

Solo se puede deshabilitar la telemetría con


una variable de entorno
PowerShell envía datos de telemetría básicos a Microsoft cuando se inicia. Los datos
incluyen el nombre del sistema operativo, la versión del sistema operativo y la versión
de PowerShell. Estos datos nos permiten comprender mejor los entornos donde se usa
PowerShell y nos permite dar prioridad a nuevas características y correcciones.
Para dejar de participar en esta telemetría, establezca la variable de entorno
POWERSHELL_TELEMETRY_OPTOUT en true , yes o 1 . Ya no se admite la eliminación del
archivo DELETE_ME_TO_DISABLE_CONSOLEHOST_TELEMETRY para deshabilitar la telemetría.
Diferencias de PowerShell en
plataformas diferentes de Windows
Artículo • 13/04/2023

PowerShell se esfuerza por proporcionar paridad de características en todas las


plataformas compatibles. Sin embargo, debido a las diferencias en .NET Core y a
diferencias específicas de plataformas, algunas características se comportan de forma
diferente o no están disponibles. Se han realizado cambios adicionales para mejorar la
interoperabilidad de PowerShell en plataformas no Windows.

.NET Framework frente a .NET Core


PowerShell en Linux y macOS usa .NET Core, que es un subconjunto de la instancia
completa de .NET Framework en Microsoft Windows. Como resultado, los scripts que se
ejecutan en Windows pueden no ejecutarse en plataformas que no son de Windows por
las diferencias en los marcos.

Para obtener más información sobre los cambios en .NET Core, vea Cambios
importantes para la migración desde .NET Framework a .NET Core.

Cambios generales de interoperabilidad de


Unix
Se ha agregado compatibilidad con el uso global de comandos nativos en
plataformas Unix. Esto significa que puede usar caracteres comodín con comandos
nativos como ls *.txt .
La funcionalidad more respeta el valor $PAGER de Linux y tiene como valor
predeterminado less .
Se agrega automáticamente un carácter de escape a la barra diagonal inversa final
cuando se trabaja con argumentos de comandos nativos.
Se ha corregido ConsoleHost para usar NoEcho en plataformas Unix.
No agregues la variable de entorno PATHEXT en Unix
Se incluye una página man powershell en el paquete

Directiva de ejecución
El parámetro -ExecutionPolicy se omite al ejecutar PowerShell en plataformas no
Windows. Get-ExecutionPolicy devuelve Unrestricted en Linux y macOS. Set-
ExecutionPolicy no hace nada en Linux y macOS.

Distinción de mayúsculas y minúsculas en


PowerShell
Históricamente, PowerShell ha distinguido entre mayúsculas y minúsculas de manera
uniforme, con algunas excepciones. En los sistemas operativos similares a UNIX, el
sistema de archivos mayormente distingue mayúsculas de minúsculas y PowerShell se
ajusta al estándar del sistema de archivos.

Al especificar un archivo en PowerShell, deben usarse las mayúsculas y minúsculas


correctas.
Si un script intenta cargar un módulo y el nombre del módulo no utiliza las
mayúsculas y minúsculas correctamente, no se cargará el módulo. Esto puede
provocar un problema con los scripts existentes si el nombre por el que se hace
referencia al módulo no coincide con las mayúsculas y minúsculas correctas del
nombre de archivo real.
Aunque los nombres del sistema de archivos distinguen mayúsculas de
minúsculas, la finalización con tabulación de los nombres de archivo no distingue
mayúsculas de minúsculas. La finalización con tabulación pasa por la lista de
nombres mediante coincidencia que no tiene en cuenta las mayúsculas y
minúsculas.
Get-Help admite la coincidencia de patrones que no distingue mayúsculas de

minúsculas en plataformas Unix.


Import-Module no distingue mayúsculas de minúsculas cuando usa un nombre de

archivo para determinar el nombre del módulo.

Compatibilidad del sistema de archivos con


Linux y macOS
Las rutas de acceso que se asignan a los cmdlets ahora son independientes de la
barra diagonal (tanto / como \ funcionan como separador de directorio).
Ahora se respeta la especificación de directorio base de XDG y se usa de forma
predeterminada:
La ruta de acceso al perfil de Linux/macOS se encuentra en
~/.config/powershell/profile.ps1 .
La ruta de acceso de almacenamiento del historial se encuentra en
~/.local/share/powershell/PSReadline/ConsoleHost_history.txt .
La ruta de acceso del módulo de usuario se encuentra en
~/.local/share/powershell/Modules .
Compatibilidad con nombres de archivo y carpeta que contienen el carácter de
dos puntos en Unix.
Compatibilidad con nombres de script o rutas de acceso completas que tienen
comas.
Se detecta cuándo se usa -LiteralPath para suprimir la expansión de caracteres
comodín para los cmdlets de navegación.
Se ha actualizado Get-ChildItem para que su funcionamiento se parezca más a ls
-R de *nix y los comandos nativos DIR /S de Windows. Get-ChildItem ahora
devuelve los vínculos simbólicos que se encuentran durante una búsqueda
recurrente y no busca en los directorios que esos vínculos tienen como destino.

Extensiones de archivo .PS1


Los scripts de PowerShell deben terminar en .ps1 para que el intérprete sepa cómo
cargarlos y ejecutarlos en el proceso actual. La ejecución de los scripts en el proceso
actual es el comportamiento habitual esperado de PowerShell. El número mágico #! se
puede agregar a un script que no tiene una extensión .ps1 , pero esto hace que el script
se ejecute en una nueva instancia de PowerShell que impedirá el correcto
funcionamiento del script al intercambiar objetos Este puede ser el comportamiento
deseable al ejecutar un script de PowerShell desde bash u otro shell.

Alias de conveniencia quitados


En Windows, PowerShell proporciona un conjunto de alias que se asignan a nombres de
comandos de Linux para la comodidad del usuario. En Linux y macOS, se han quitado
los "alias de conveniencia" de los comandos básicos ls , cp , mv , rm , cat , man , mount y
ps para permitir que el ejecutable nativo se ejecute sin especificar una ruta de acceso.

Registro
En macOS, PowerShell usa las API os_log nativas para registrar información en el
sistema de registro unificado de Apple. En Linux, PowerShell usa Syslog , una
solución de registro ubicua.
Control de trabajo
En PowerShell en Linux o macOS no hay ninguna compatibilidad de control de trabajo
de estilo Unix. Los comandos fg y bg no están disponibles. Puede usar trabajos de
PowerShell, que funcionan en todas las plataformas.

Cuando se incluye & al final de una canalización, esta se ejecuta como un trabajo de
PowerShell. Cuando una canalización se pasa a segundo plano, se devuelve un objeto
de trabajo. Una vez que la canalización se ejecuta como un trabajo, se pueden usar
todos los cmdlets *-Job para administrar el trabajo. Las variables (se omiten las
específicas del proceso) que se usan en la canalización se copian automáticamente en el
trabajo para que funcione Copy-Item $foo $bar & . El trabajo también se ejecuta en el
directorio actual, en lugar del directorio principal del usuario.

Compatibilidad con la comunicación remota


La comunicación remota de PowerShell (PSRP) mediante WinRM en plataformas Unix
requiere NTLM/Negotiate o autenticación básica a través de HTTPS. PSRP en macOS
solo admite autenticación básica a través de HTTPS. No se admite la autenticación
basada en Kerberos.

PowerShell admite la comunicación remota de PowerShell (PSRP) a través de SSH en


todas las plataformas (Windows, macOS y Linux). Para obtener más información, vea
Comunicación remota de PowerShell a través de SSH.

Compatibilidad con Just Enough


Administration (JEA)
La capacidad para crear puntos de conexión de comunicación remota de administración
restringida (JEA) no está disponible en PowerShell en sistemas Linux o macOS.

sudo , exec y PowerShell


Dado que PowerShell ejecuta la mayoría de los comandos en la memoria (como Python
o Ruby), no puedes usar sudo directamente con elementos integrados de PowerShell. Sí
puedes ejecutar pwsh desde sudo. Si es necesario ejecutar un cmdlet de PowerShell
desde dentro de PowerShell con sudo, por ejemplo, sudo Set-Date 8/18/2016 , tendrías
que sudo pwsh Set-Date 8/18/2016 .
Cmdlets que faltan
Un gran número de los comandos (cmdlets) normalmente disponibles en PowerShell no
lo están en sistemas Linux o macOS. En muchos casos, estos comandos no tienen
sentido en estas plataformas (p. ej., características específicas de Windows como el
registro). Otros comandos, como los de control de servicios, sí están presentes, pero no
son funcionales. Las versiones futuras pueden corregir estos problemas reparando los
cmdlets rotos y agregando nuevos con el tiempo.

Para obtener una lista completa de los módulos y cmdlets, y las plataformas que
admiten, vea Historial de versiones de módulos y cmdlets.

Módulos que ya no se incluyen en PowerShell


Por distintas razones de compatibilidad, los módulos a continuación ya no se incluyen
en PowerShell.

ISE
Microsoft.PowerShell.LocalAccounts
Microsoft.PowerShell.ODataUtils
Microsoft.PowerShell.Operation.Validation
PSScheduledJob
PSWorkflow
PSWorkflowUtility

Los siguientes módulos específicos de Windows no se incluyen en PowerShell para


sistemas Linux o macOS.

CimCmdlets
Microsoft.PowerShell.Diagnostics
Microsoft.WSMan.Management
PSDiagnostics

Cmdlets no disponibles en plataformas no


Windows
En las plataformas no Windows, PowerShell incluye los siguientes módulos:

Microsoft.PowerShell.Archive
Microsoft.PowerShell.Core
Microsoft.PowerShell.Host
Microsoft.PowerShell.Management
Microsoft.PowerShell.Security
Microsoft.PowerShell.Utility
PackageManagement
PowerShellGet
PSDesiredStateConfiguration
PSReadLine
ThreadJob

Sin embargo, algunos cmdlets se han eliminado de PowerShell, y otros no están


disponibles o funcionan de forma diferente en sistemas diferentes a Windows. Para
obtener una lista completa de los cmdlets quitados de PowerShell, vea Cmdlets
quitados de PowerShell.

Microsoft.PowerShell.Core
El parámetro ShowWindow de Get-Help no está disponible en sistemas diferentes a
Windows.

Cmdlets de Microsoft.PowerShell.Security
Los cmdlets siguientes no están disponibles en sistemas Linux o macOS:

Get-Acl
Set-Acl

Get-AuthenticodeSignature
Set-AuthenticodeSignature

New-FileCatalog

Test-FileCatalog

Estos cmdlets solo están disponibles a partir de PowerShell 7.1.

Get-CmsMessage
Protect-CmsMessage

Unprotect-CmsMessage

Cmdlets de Microsoft.PowerShell.Management
Los cmdlets siguientes no están disponibles en sistemas Linux y macOS:

Clear-RecycleBin
Get-HotFix

Los cmdlets siguientes están disponibles con limitaciones:

Get-Clipboard : disponible en Linux pero no admitido en macOS, Set-Clipboard :

disponible en PowerShell 7.0+, Restart-Computer : disponible para Linux y macOS en


PowerShell 7.1+, Stop-Computer : disponible para Linux y macOS en PowerShell 7.1+

Cmdlets de Microsoft.PowerShell.Utility
Los cmdlets siguientes no están disponibles en sistemas Linux y macOS:

Convert-String

ConvertFrom-String

Out-GridView
Out-Printer

Show-Command

Alias no disponibles en Linux o macOS


En la tabla siguiente se enumeran los alias disponibles para Windows que no están
disponibles en sistemas diferentes de Windows. Estos alias no están disponibles porque
el cmdlet de destino no está disponible o el alias entra en conflicto con un comando
nativo en esas plataformas.

Alias Cmdlet

ac Add-Content

cat Get-Content

clear Clear-Host

cnsn Connect-PSSession

compare Compare-Object

cp Copy-Item

cpp Copy-ItemProperty

diff Compare-Object

dnsn Disconnect-PSSession
Alias Cmdlet

gsv Get-Service

kill Stop-Process

ls Get-ChildItem

man help

mount New-PSDrive

mv Move-Item

ogv Out-GridView

ps Get-Process

rm Remove-Item

rmdir Remove-Item

sasv Start-Service

shcm Show-Command

sleep Start-Sleep

sort Sort-Object

spsv Stop-Service

start Start-Process

tee Tee-Object

write Write-Output

Desired State Configuration (DSC) de


PowerShell
Muchos cmdlets se han quitado del módulo PSDesiredStateConfiguration a partir de
PowerShell 6.0. La compatibilidad con DSC en plataformas no Windows es limitada y
principalmente experimental. El cmdlet Invoke-DscResource se restauró como
característica experimental en PowerShell 7.0.

DSC no se admite en macOS.


Para obtener más información sobre el uso de DSC en Linux, vea Introducción a DSC
para Linux.

A partir de PowerShell 7.2, el módulo PSDesiredStateConfiguration se ha eliminado de


PowerShell y se ha publicado en la Galería de PowerShell. Para obtener más información,
vea el anuncio en el blog del equipo de PowerShell.
Historial de versiones de módulos y
cmdlets
Artículo • 13/04/2023

En este artículo se muestran los módulos y cmdlets que se suministran con diversas
versiones de PowerShell. Este es un resumen de la información encontrada en las notas
de la versión. Puede encontrar información más detallada en las notas de la versión:

Novedades de PowerShell 7.4 (versión preliminar)


Novedades de PowerShell 7.3
Novedades de PowerShell 7.2
Novedades de PowerShell 7.1
Novedades de PowerShell 7.0

Se trata de un trabajo en curso. Ayúdenos a mantener esta información actualizada.

Historial de lanzamiento de módulos


ModuleName / PSVersion 5,1 7.2 7.3 7.4 Nota
(versión
preliminar)

CimCmdlets Solo Windows

ISE (introducido en 2.0) Solo Windows

Microsoft.PowerShell.Archive

Microsoft.PowerShell.Core

Microsoft.PowerShell.Diagnostics Solo Windows

Microsoft.PowerShell.Host

Microsoft.PowerShell.LocalAccounts Solo Windows


(únicamente 64 bits)

Microsoft.PowerShell.Management

Microsoft.PowerShell.ODataUtils Solo Windows

Microsoft.PowerShell.Operation.Validation Solo Windows

Microsoft.PowerShell.Security
ModuleName / PSVersion 5,1 7.2 7.3 7.4 Nota
(versión
preliminar)

Microsoft.PowerShell.Utility

Microsoft.WsMan.Management Solo Windows

PackageManagement

PowershellGet 1.1 Debe actualizar a


v2.x

PowershellGet 2.x Nuevas versiones


disponibles en la
Galería

PowershellGet 3.x Disponible en la


Galería

PSDesiredStateConfiguration 1.1 Quitado en la


versión 7.2;
disponible en la
Galería

PSDesiredStateConfiguration 2.x Quitado en la


versión 7.2;
disponible en la
Galería

PSDesiredStateConfiguration 3.x Versión preliminar


disponible en la
Galería

PSDiagnostics Solo Windows

PSReadLine v1.x v2.1 v2.1 v2.1 Nuevas versiones


disponibles en la
Galería

PSScheduledJob Solo Windows

PSWorkflow Solo Windows

PSWorkflowUtility Solo Windows

ThreadJob Se puede instalar en


PowerShell 5.1

Historial de versiones de cmdlets


CimCmdlets

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Export-BinaryMiLog Solo Windows

Get-CimAssociatedInstance Solo Windows

Get-CimClass Solo Windows

Get-CimInstance Solo Windows

Get-CimSession Solo Windows

Import-BinaryMiLog Solo Windows

Invoke-CimMethod Solo Windows

New-CimInstance Solo Windows

New-CimSession Solo Windows

New-CimSessionOption Solo Windows

Register-CimIndicationEvent Solo Windows

Remove-CimInstance Solo Windows

Remove-CimSession Solo Windows

Set-CimInstance Solo Windows

ISE (introducido en 2.0)


Estos módulos solo están disponibles en Windows PowerShell.

Nombre del cmdlet 5,1 Nota:

Get-IseSnippet

Import-IseSnippet

New-IseSnippet

Microsoft.PowerShell.Archive

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Compress-Archive
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Expand-Archive

Microsoft.PowerShell.Core

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:


preliminar)

Add-History

Add-PSSnapin Solo Windows

Clear-History

Clear-Host

Connect-PSSession Solo Windows

Debug-Job

Disable- Incorporado en la versión 6.2


ExperimentalFeature

Disable-PSRemoting Solo Windows

Disable- Solo Windows


PSSessionConfiguration

Disconnect-PSSession Solo Windows

Enable- Incorporado en la versión 6.2


ExperimentalFeature

Enable-PSRemoting Solo Windows

Enable- Solo Windows


PSSessionConfiguration

Enter-PSHostProcess Compatibilidad agregada con


Linux en 6.2

Enter-PSSession

Exit-PSHostProcess Compatibilidad agregada con


Linux en 6.2

Exit-PSSession

Export-Console Solo Windows


Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

Export-ModuleMember

ForEach-Object

Get-Command

Get-ExperimentalFeature Incorporado en la versión 6.2

Get-Help

Get-History

Get-Job

Get-Module

Get-PSHostProcessInfo Compatibilidad agregada con


Linux en 6.2

Get-PSSession

Get-PSSessionCapability

Get-
PSSessionConfiguration

Get-PSSnapin Solo Windows

Get-Verb Movido a
Microsoft.PowerShell.Utility
6.0+

Import-Module

Invoke-Command

Invoke-History

New-Module

New-ModuleManifest

New-PSRoleCapabilityFile

New-PSSession

New- Compatibilidad agregada con


PSSessionConfigurationFile Linux en 7.3

New-PSSessionOption
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

New-PSTransportOption

Out-Default

Out-Host

Out-Null

Receive-Job

Receive-PSSession Solo Windows

Register-
ArgumentCompleter

Register- Solo Windows


PSSessionConfiguration

Remove-Job

Remove-Module

Remove-PSSession

Remove-PSSnapin Solo Windows

Resume-Job

Save-Help

Set-PSDebug

Set- Solo Windows


PSSessionConfiguration

Set-StrictMode

Start-Job

Stop-Job

Switch-Process Solo Linux y macOS

Suspend-Job Solo Windows

Test-ModuleManifest

Test- Solo Windows


PSSessionConfigurationFile
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

Unregister- Solo Windows


PSSessionConfiguration

Update-Help

Wait-Job

Where-Object

Microsoft.PowerShell.Diagnostics

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Export-Counter Solo Windows

Get-Counter Solo Windows

Get-WinEvent Solo Windows

Import-Counter Solo Windows

New-WinEvent Solo Windows

Microsoft.PowerShell.Host

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Start-Transcript

Stop-Transcript

Microsoft.PowerShell.LocalAccounts (64-bit only)


Estos módulos solo están disponibles en Windows PowerShell.

Nombre del cmdlet 5,1 Nota:

Add-LocalGroupMember

Disable-LocalUser

Enable-LocalUser

Get-LocalGroup
Nombre del cmdlet 5,1 Nota:

Get-LocalGroupMember

Get-LocalUser

New-LocalGroup

New-LocalUser

Remove-LocalGroup

Remove-LocalGroupMember

Remove-LocalUser

Rename-LocalGroup

Rename-LocalUser

Set-LocalGroup

Set-LocalUser

Microsoft.PowerShell.Management

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:


preliminar)

Add-Computer Solo Windows

Add-Content

Checkpoint-Computer Solo Windows

Clear-Content

Clear-EventLog Solo Windows

Clear-Item

Clear-ItemProperty

Clear-RecycleBin Solo Windows

Complete-Transaction Solo Windows

Convert-Path

Copy-Item
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

Copy-ItemProperty

Debug-Process

Disable-ComputerRestore Solo Windows

Enable-ComputerRestore Solo Windows

Get-ChildItem

Get-Clipboard NotsupportedonmacOS

Get-ComputerInfo Solo Windows

Get-ComputerRestorePoint Solo Windows

Get-Content

Get-ControlPanelItem Solo Windows

Get-EventLog Solo Windows

Get-HotFix Solo Windows

Get-Item

Get-ItemProperty

Get-ItemPropertyValue

Get-Location

Get-Process

Get-PSDrive

Get-PSProvider

Get-Service Solo Windows

Get-TimeZone Solo Windows

Get-Transaction Solo Windows

Get-WmiObject Solo Windows

Invoke-Item

Invoke-WmiMethod Solo Windows

Join-Path
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

Limit-EventLog Solo Windows

Move-Item

Move-ItemProperty

New-EventLog Solo Windows

New-Item

New-ItemProperty

New-PSDrive

New-Service Solo Windows

New-WebServiceProxy Solo Windows

Pop-Location

Push-Location

Register-WmiEvent Solo Windows

Remove-Computer Solo Windows

Remove-EventLog Solo Windows

Remove-Item

Remove-ItemProperty

Remove-PSDrive

Remove-Service Solo Windows

Remove-WmiObject Solo Windows

Rename-Computer Solo Windows

Rename-Item

Rename-ItemProperty

Reset- Solo Windows


ComputerMachinePassword

Resolve-Path
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

Restart-Computer Compatibilidad con Linux/macOS


agregada en la versión 7.1

Restart-Service Solo Windows

Restore-Computer Solo Windows

Resume-Service Solo Windows

Set-Clipboard

Set-Content

Set-Item

Set-ItemProperty

Set-Location

Set-Service Solo Windows

Set-TimeZone Solo Windows

Set-WmiInstance Solo Windows

Show-ControlPanelItem Solo Windows

Show-EventLog Solo Windows

Split-Path

Start-Process

Start-Service Solo Windows

Start-Transaction Solo Windows

Stop-Computer Compatibilidad con Linux/macOS


agregada en la versión 7.1

Stop-Process

Stop-Service Solo Windows

Suspend-Service Solo Windows

Test- Solo Windows


ComputerSecureChannel

Test-Connection
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

Test-Path

Undo-Transaction Solo Windows

Use-Transaction Solo Windows

Wait-Process

Write-EventLog Solo Windows

Microsoft.PowerShell.ODataUtils
Estos módulos solo están disponibles en Windows PowerShell.

Nombre del cmdlet 5,1 Nota:

Export-ODataEndpointProxy

Microsoft.PowerShell.Operation.Validation
Estos módulos solo están disponibles en Windows PowerShell.

Nombre del cmdlet 5,1 Nota:

Get-OperationValidation

Invoke-OperationValidation

Microsoft.PowerShell.Security

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:


preliminar)

ConvertFrom-
SecureString

ConvertTo-
SecureString

Get-Acl Solo Windows

Get- Solo Windows


AuthenticodeSignature
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión Nota:
preliminar)

Get-CmsMessage Se ha agregado compatibilidad con


Linux/macOS en la versión 7.1.

Get-Credential

Get-ExecutionPolicy Devuelve Unrestricted en


Linux/macOS

Get-PfxCertificate

New-FileCatalog Solo Windows

Protect-CmsMessage Se ha agregado compatibilidad con


Linux/macOS en la versión 7.1.

Set-Acl Solo Windows

Set- Solo Windows


AuthenticodeSignature

Set-ExecutionPolicy No hace nada en Linux/macOS

Test-FileCatalog Solo Windows

Unprotect- Se ha agregado compatibilidad con


CmsMessage Linux/macOS en la versión 7.1.

Microsoft.PowerShell.Utility

Nombre del 5,1 7.2 7.3 7.4 (versión Nota:


cmdlet preliminar)

Add-Member

Add-Type

Clear-Variable

Compare-Object

ConvertFrom-Csv

ConvertFrom-Json

ConvertFrom- Incorporado en la versión 6.1


Markdown
Nombre del 5,1 7.2 7.3 7.4 (versión Nota:
cmdlet preliminar)

ConvertFrom- Solo Windows


SddlString

ConvertFrom-String

ConvertFrom-
StringData

Convert-String

ConvertTo-Csv

ConvertTo-Html

ConvertTo-Json

ConvertTo-Xml

Debug-Runspace

Disable-
PSBreakpoint

Disable-
RunspaceDebug

Enable-
PSBreakpoint

Enable-
RunspaceDebug

Export-Alias

Export-Clixml

Export-Csv

Export-FormatData

Export-PSSession

Format-Custom

Format-Hex

Format-List

Format-Table
Nombre del 5,1 7.2 7.3 7.4 (versión Nota:
cmdlet preliminar)

Format-Wide

Get-Alias

Get-Culture

Get-Date

Get-Error

Get-Event Ningún origen del evento disponible


en Linux/macOS

Get-
EventSubscriber

Get-FileHash

Get-FormatData

Get-Host

Get- Incorporado en la versión 6.1


MarkdownOption

Get-Member

Get-PSBreakpoint

Get-PSCallStack

Get-Random

Get-Runspace

Get-
RunspaceDebug

Get-SecureRandom Incorporado en la versión 7.4

Get-TraceSource

Get-TypeData

Get-UICulture

Get-Unique

Get-Uptime
Nombre del 5,1 7.2 7.3 7.4 (versión Nota:
cmdlet preliminar)

Get-Variable

Get-Verb Movido de Microsoft.PowerShell.Core

Group-Object

Import-Alias

Import-Clixml

Import-Csv

Import-
LocalizedData

Import-
PowerShellDataFile

Import-PSSession

Invoke-Expression

Invoke-RestMethod

Invoke-
WebRequest

Join-String

Measure-Command

Measure-Object

New-Alias

New-Event Ningún origen del evento disponible


en Linux/macOS

New-Guid

New-Object

New-TemporaryFile

New-TimeSpan

New-Variable

Out-File
Nombre del 5,1 7.2 7.3 7.4 (versión Nota:
cmdlet preliminar)

Out-Gridview Solo Windows

Out-Printer Solo Windows

Out-String

Read-Host

Register- Ningún origen del evento disponible


EngineEvent en Linux/macOS

Register-
ObjectEvent

Remove-Alias

Remove-Event Ningún origen del evento disponible


en Linux/macOS

Remove-
PSBreakpoint

Remove-TypeData

Remove-Variable

Select-Object

Select-String

Select-Xml

Send-MailMessage

Set-Alias

Set-Date

Set- Incorporado en la versión 6.1


MarkdownOption

Set-PSBreakpoint

Set-TraceSource

Set-Variable

Show-Command Solo Windows

Show-Markdown Incorporado en la versión 6.1


Nombre del 5,1 7.2 7.3 7.4 (versión Nota:
cmdlet preliminar)

Sort-Object

Start-Sleep

Tee-Object

Test-Json

Trace-Command

Unblock-File Compatibilidad agregada con macOS


en 7.0

Unregister-Event Ningún origen del evento disponible


en Linux/macOS

Update-
FormatData

Update-List

Update-TypeData

Wait-Debugger

Wait-Event

Write-Debug

Write-Error

Write-Host

Write-Information

Write-Output

Write-Progress

Write-Verbose

Write-Warning

Microsoft.WSMan.Management

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Connect-WSMan Solo Windows


Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Disable-WSManCredSSP Solo Windows

Disconnect-WSMan Solo Windows

Enable-WSManCredSSP Solo Windows

Get-WSManCredSSP Solo Windows

Get-WSManInstance Solo Windows

Invoke-WSManAction Solo Windows

New-WSManInstance Solo Windows

New-WSManSessionOption Solo Windows

Remove-WSManInstance Solo Windows

Set-WSManInstance Solo Windows

Set-WSManQuickConfig Solo Windows

Test-WSMan Solo Windows

PackageManagement

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Find-Package

Find-PackageProvider

Get-Package

Get-PackageProvider

Get-PackageSource

Import-PackageProvider

Install-Package

Install-PackageProvider

Register-PackageSource

Save-Package

Set-PackageSource
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Uninstall-Package

Unregister-PackageSource

PowershellGet 2.x

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Find-Command

Find-DscResource

Find-Module

Find-RoleCapability

Find-Script

Get-CredsFromCredentialProvider

Get-InstalledModule

Get-InstalledScript

Get-PSRepository

Install-Module

Install-Script

New-ScriptFileInfo

Publish-Module

Publish-Script

Register-PSRepository

Save-Module

Save-Script

Set-PSRepository

Test-ScriptFileInfo

Uninstall-Module

Uninstall-Script
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Unregister-PSRepository

Update-Module

Update-ModuleManifest

Update-Script

Update-ScriptFileInfo

PowershellGet 3.x: versión preliminar


Estos módulos solo están disponibles en la Galería de PowerShell.

Nombre Nota

Find-PSResource

Get-InstalledPSResource

Get-PSResourceRepository

Install-PSResource

Publish-PSResource

Register-PSResourceRepository

Save-PSResource

Set-PSResourceRepository

Uninstall-PSResource

Unregister-PSResourceRepository

Update-PSResource

PSDesiredStateConfiguration v1.1
Estos módulos solo están disponibles en Windows PowerShell.

Nombre del cmdlet 5,1 Nota

Configuración

Disable-DscDebug
Nombre del cmdlet 5,1 Nota

Enable-DscDebug

Get-DscConfiguration

Get-DscConfigurationStatus

Get-DscLocalConfigurationManager

Get-DscResource

Invoke-DscResource

New-DSCCheckSum

Publish-DscConfiguration

Remove-DscConfigurationDocument

Restore-DscConfiguration

Set-DscLocalConfigurationManager

Start-DscConfiguration

Stop-DscConfiguration

Test-DscConfiguration

Update-DscConfiguration

PSDesiredStateConfiguration v2.0.5
Estos módulos solo están disponibles en la Galería de PowerShell.

Nombre del cmdlet 2.0.5 Nota

Configuración

Get-DscResource

Invoke-DscResource Habilitación de características

New-DSCCheckSum

PSDesiredStateConfiguration v3.x: versión preliminar


Estos módulos solo están disponibles en la Galería de PowerShell.
Nombre del cmdlet 3.0 (versión preliminar) Nota

Configuración

ConvertTo-DscJsonSchema

Get-DscResource

Invoke-DscResource Habilitación de características

New-DscChecksum

PSDiagnostics

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota:

Disable-PSTrace Solo Windows

Disable-PSWSManCombinedTrace Solo Windows

Disable-WSManTrace Solo Windows

Enable-PSTrace Solo Windows

Enable-PSWSManCombinedTrace Solo Windows

Enable-WSManTrace Solo Windows

Get-LogProperties Solo Windows

Set-LogProperties Solo Windows

Start-Trace Solo Windows

Stop-Trace Solo Windows

PSReadLine

Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota

Get-PSReadLineKeyHandler

Get-PSReadLineOption

PSConsoleHostReadLine

Remove-PSReadLineKeyHandler

Set-PSReadLineKeyHandler
Nombre del cmdlet 5,1 7.2 7.3 7.4 (versión preliminar) Nota

Set-PSReadLineOption

PSScheduledJob
Estos módulos solo están disponibles en Windows PowerShell.

Nombre del cmdlet 5,1 Nota:

Add-JobTrigger

Disable-JobTrigger

Disable-ScheduledJob

Enable-JobTrigger

Enable-ScheduledJob

Get-JobTrigger

Get-ScheduledJob

Get-ScheduledJobOption

New-JobTrigger

New-ScheduledJobOption

Register-ScheduledJob

Remove-JobTrigger

Set-JobTrigger

Set-ScheduledJob

Set-ScheduledJobOption

Unregister-ScheduledJob

PSWorkflow & PSWorkflowUtility


Estos módulos solo están disponibles en Windows PowerShell.

Nombre del cmdlet 5,1 Nota:

New-PSWorkflowExecutionOption
Nombre del cmdlet 5,1 Nota:

New-PSWorkflowSession

Invoke-AsWorkflow

ThreadJob

Nombre del 5,1 7.2 7.3 7.4 (versión Nota:


cmdlet preliminar)

Start-ThreadJob Se puede instalar en


PowerShell 5.1
Compatibilidad del módulo de
PowerShell 7
Artículo • 28/06/2023

En este artículo se incluye una lista parcial de módulos de PowerShell publicados por
Microsoft.

El equipo de PowerShell está trabajando con los distintos equipos de características que
crean módulos de PowerShell para ayudarles a generar módulos que funcionan en
PowerShell 7. Estos módulos no son propiedad del equipo de PowerShell.

Se sabe que los módulos siguientes admiten PowerShell 7.

Azure PowerShell
El módulo Az de PowerShell es un conjunto de cmdlets para administrar los recursos de
Azure directamente desde PowerShell. PowerShell 7.0.6 LTS o cualquier versión posterior
son las versiones recomendadas para usarlas con el módulo Azure Az de PowerShell en
todas las plataformas.

Para más información, vea Presentación del módulo Azure Az de PowerShell.

SDK de PowerShell en MSGraph


Los SDK de Microsoft Graph se han diseñado para simplificar la compilación de
aplicaciones de alta calidad, eficaces y resistentes que acceden a Microsoft Graph.
PowerShell 7 y versiones posteriores son las versiones recomendadas de PowerShell
para usarlas con el SDK de PowerShell en Microsoft Graph.

Para más información, vea Instalación del SDK de PowerShell en Microsoft Graph.

Módulos de administración de Windows


Los módulos de administración de Windows proporcionan administración y soporte
técnico para diversas características y servicios de Windows. La mayoría de estos
módulos se han actualizado para funcionar de forma nativa con PowerShell 7 o se ha
probado su compatibilidad con PowerShell 7.

Estos módulos se instalan de distintas formas en función de la edición de Windows y de


cómo se haya empaquetado el módulo de esa edición.
Para más información sobre la instalación y compatibilidad, vea Compatibilidad del
módulo de PowerShell 7 en la documentación de Windows.

Administración de Exchange Online 2.0


El módulo PowerShell V2 de Exchange Online (EXO V2) se conecta a todos los entornos
de PowerShell relacionados con Exchange en Microsoft 365: Exchange Online
PowerShell, Security & Compliance PowerShell y Exchange Online Protection (EOP)
PowerShell independiente.

EXO v2.0.4 o posterior se admite en PowerShell 7.0.3 o posterior.

Para más información, vea Acerca del módulo Windows PowerShell V2 de Exchange
Online.

Módulos de PowerShell para SQL Server


Hay dos módulos de SQL Server PowerShell:

SqlServer: este módulo incluye cmdlets nuevos para admitir las últimas
características de SQL, incluidas las versiones actualizadas de los cmdlets en
SQLPS.
SQLPS: SQLPS es el módulo que usa el Agente SQL para ejecutar trabajos del
agente en pasos de trabajo del agente mediante el subsistema de PowerShell.

Los módulos SqlServer requieren PowerShell 5.0 o posterior.

Para más información, vea Instalación del módulo SQL Server PowerShell.

Búsqueda del estado de otros módulos


Puede encontrar una lista completa de módulos mediante el Explorador de módulos de
PowerShell. Con el Explorador de módulos, puede encontrar documentación para otros
módulos de PowerShell para determinar sus requisitos de versión de PowerShell.
Instalación de Windows PowerShell
Artículo • 06/02/2023

A partir de las ediciones Windows 7 SP1 y Windows Server 2008 R2 SP1, Windows
PowerShell viene instalado en Windows de forma predeterminada.

Si está interesado en PowerShell 7 y versiones posteriores, debe instalar PowerShell en


lugar de Windows PowerShell. Para más información, consulte Instalación de PowerShell
en Windows.

Búsqueda de PowerShell en Windows 11, 10, 8.1,


8.0 y 7
Encontrar la consola o el entorno de scripting integrado (ISE) de PowerShell en Windows
puede ser difícil, ya que su ubicación cambia en función de la versión del sistema.

En las tablas siguientes se proporciona información para poder encontrar PowerShell


según la versión de Windows que se esté usando. Todas las versiones que se muestran
aquí son las originales, tal y como se publican y sin actualizaciones.

Consola

Versión Location

Windows 10 Haga clic en el icono de Windows (esquina inferior izquierda en Windows 10, parte
y 11 inferior centra en Windows 11) y empiece a escribir PowerShell.

Windows En la pantalla Inicio, empiece a escribir PowerShell.


8.1 u 8.0 Si está en el escritorio, haga clic en el icono de Windows de la esquina inferior
izquierda y empiece a escribir PowerShell.

Windows 7 Haga clic en el icono de Windows de la esquina inferior izquierda y empiece a


SP1 escribir PowerShell en el cuadro de búsqueda.

ISE

Versión Location

Windows 10 Haga clic en el icono de Windows (esquina inferior izquierda en Windows 10, parte
y 11 inferior central en Windows 11) y empiece a escribir ISE.
Versión Location

Windows En la pantalla Inicio, escriba PowerShell ISE.


8.1 u 8.0 Si está en el escritorio, haga clic en el icono de Windows de la esquina inferior
izquierda y escriba PowerShell ISE.

Windows 7 Haga clic en el icono de Windows de la esquina inferior izquierda y empiece a


SP1 escribir PowerShell en el cuadro de búsqueda.

Búsqueda de PowerShell en versiones de


Windows Server
A partir de Windows Server 2008 R2, el sistema operativo Windows puede instalarse sin
la interfaz gráfica de usuario (GUI). Las ediciones de Windows Server sin GUI se conocen
como ediciones básicas, mientras que las que sí que tienen GUI se conocen como de
escritorio.

Ediciones básicas de Windows Server


En todas las ediciones básicas, se mostrará una ventana del símbolo del sistema de
Windows al iniciar sesión en el servidor.

Escriba powershell y pulse ENTRAR para iniciar PowerShell en la sesión del símbolo del
sistema. Escriba exit para cerrar la sesión de PowerShell y volver al símbolo del sistema.

Ediciones de escritorio de Windows Server


En todas las ediciones de escritorio, deberá hacer clic en el icono de Windows de la
esquina inferior izquierda y empezar a escribir PowerShell. Se mostrarán las opciones de
la consola y el ISE.

La única excepción a la regla anterior se produce en el caso del ISE en Windows Server
2008 R2 SP1. En ese caso, haga clic en el icono de Windows de la esquina inferior
izquierda y escriba PowerShell ISE.

Comprobación de la versión de PowerShell


Para consultar qué versión de PowerShell ha instalado, inicie una consola de PowerShell
(o el ISE), escriba $PSVersionTable y pulse ENTRAR . Busque el valor PSVersion .
Actualización de Windows PowerShell existente
El paquete de instalación de PowerShell está incluido en un instalador WMF. La versión
del instalador WMF coincide con la versión de PowerShell; no hay ningún instalador
independiente de Windows PowerShell.

Si debe actualizar la versión existente de PowerShell en Windows, use la tabla siguiente


para encontrar el instalador correspondiente a la versión de PowerShell que quiera
aplicar.

Windows PS 3.0 PS 4.0 PS 5.0 PS 5.1

Windows 11 - - - Instalado
Windows Server 2022

Windows 10 (consulte Nota 1) - - - Instalado


Windows Server 2016

Windows 8.1 - Instalado WMF 5.0 WMF 5.1


Windows Server 2012 R2

Windows 8 Instalado WMF 4.0 WMF 5.0 WMF 5.1


Windows Server 2012

Windows 7 SP1 WMF 3.0 WMF 4.0 WMF 5.0 WMF 5.1
Windows Server 2008 R2 SP1

7 Nota

En la versión inicial de Windows 10, con las actualizaciones automáticas habilitadas,


PowerShell se actualiza de la versión 5.0 a la 5.1. Si no se actualiza la versión
original de Windows 10 mediante las actualizaciones de Windows, la versión de
PowerShell será la 5.0.

Obtención de Azure PowerShell


Si está buscando Azure PowerShell, puede empezar por el artículo Overview of Azure
PowerShell (Información general sobre Azure PowerShell).

De lo contrario, consulte Install and configure Azure PowerShell (Instalación y


configuración de Azure PowerShell).

Consulte también
Requisitos del sistema de Windows PowerShell

Inicio de Windows PowerShell


Instalar el motor de Windows
PowerShell 2.0
Artículo • 06/02/2023

En este tema se explica cómo instalar el motor de Windows PowerShell 2.0.

Windows PowerShell 3.0 está diseñado para ser compatible con versiones anteriores de
Windows PowerShell 2.0. Los cmdlets, proveedores, complementos, módulos y scripts
escritos para Windows PowerShell 2.0 se ejecutan sin cambios en Windows PowerShell
3.0 y Windows PowerShell 4.0. Sin embargo, debido a un cambio en la directiva de
activación en tiempo de ejecución de Microsoft .NET Framework 4, los programas host
de Windows PowerShell escritos para Windows PowerShell 2.0 y compilados con
Common Language Runtime (CLR) 2.0 no se pueden ejecutar sin modificaciones en
versiones posteriores de Windows PowerShell, que está compilado con CLR 4.0.

Para mantener la compatibilidad con versiones anteriores de los comandos y los


programas host que se ven afectados por estos cambios, los motores de Windows
PowerShell 2.0, Windows PowerShell 3.0 y Windows PowerShell 4.0 están diseñados para
ejecutarse en paralelo. Además, el motor de Windows PowerShell 2.0 se incluye en
Windows Server 2012 R2, Windows 8.1, Windows 8, Windows Server 2012 y Windows
Management Framework 3.0. El motor de Windows PowerShell 2.0 está destinado a
usarse solo cuando un programa host o un script existente no se puede ejecutar porque
es incompatible con Windows PowerShell 3.0, Windows PowerShell 4.0 o Microsoft .NET
Framework 4. Estos casos deben ser infrecuentes.

El motor de Windows PowerShell 2.0 es una característica opcional de


Windows Server 2012 R2, Windows 8.1, Windows 8 y Windows Server 2012. En versiones
anteriores de Windows, al instalar Windows Management Framework 3.0, la instalación
de Windows PowerShell 3.0 reemplaza completamente la instalación de Windows
PowerShell 2.0 en el directorio de instalación de Windows PowerShell. Sin embargo, se
conserva el motor de Windows PowerShell 2.0.

Para obtener información sobre cómo iniciar el motor de Windows PowerShell 2.0, vea
Iniciar el motor de Windows PowerShell 2.0.

En Windows 8.1 y Windows 8


En Windows 8.1 y Windows 8, la característica del motor de Windows PowerShell 2.0
está activada de forma predeterminada. Sin embargo, para usarla, debe activar la opción
para Microsoft .NET Framework 3.5, que es necesaria. En esta sección también se explica
cómo activar y desactivar la característica del motor de Windows PowerShell 2.0.

Para activar .NET Framework 3.5


1. En la pantalla Inicio, escriba Características de Windows.

2. En la barra Aplicaciones, haga clic en Configuración y, después, en Activar o


desactivar las características de Windows.

3. En el cuadro Características de Windows, haga clic en .NET Framework 3.5


(incluye .NET 2.0 y 3.0) para seleccionar esta opción.

Al seleccionar .NET Framework 3.5 (incluye .NET 2.0 y 3.0), el cuadro se rellena
para indicar que solo una parte de la característica está seleccionada. Sin embargo,
esto es suficiente para el motor de Windows PowerShell 2.0.

Para activar y desactivar el motor de Windows PowerShell


2.0
1. En la pantalla Inicio, escriba Características de Windows.
2. En la barra Aplicaciones, haga clic en Configuración y, después, en Activar o
desactivar las características de Windows.
3. En el cuadro Características de Windows, expanda el nodo Windows PowerShell
2.0 y haga clic en la casilla Motor de Windows PowerShell 2.0 para activarla o
desactivarla.

En Windows Server 2012 R2 y Windows Server


2012
Use los procedimientos siguientes para agregar las características del motor de
Windows PowerShell 2.0 y Microsoft .NET Framework 3.5. El motor de Windows
PowerShell 2.0 requiere Microsoft .NET Framework 2.0.50727 como mínimo. Este
requisito se cumple con Microsoft .NET Framework 3.5.

Para agregar la característica de .NET Framework 3.5


1. En el menú Administrador del servidor del menú Administrar, haga clic en
Agregar roles y características.
O bien en Administrador del servidor, haga clic en Todos los servidores, haga clic
con el botón derecho en el nombre de un servidor y luego seleccione Agregar
roles y características.

2. En la página Tipo de instalación, seleccione Instalación basada en características


o en roles.

3. En la página Características, expanda el nodo Características de .NET Framework


3.5 y seleccione .NET Framework 3.5 (incluye .NET 2.0 y 3.0).

Las demás opciones bajo ese nodo no son necesarias para el motor de Windows
PowerShell 2.0.

Para agregar la característica del motor de Windows


PowerShell 2.0
En el menú Administrador del servidor del menú Administrar, haga clic en
Agregar roles y características.

En Administrador del servidor, haga clic en Todos los servidores, haga clic con el
botón derecho en el nombre de un servidor y luego seleccione Agregar roles y
características.

En la página Tipo de instalación, seleccione Instalación basada en características


o en roles.

En la página Características, expanda el nodo Windows PowerShell (instalado) y


seleccione Motor de Windows PowerShell 2.0.

Para obtener información sobre cómo iniciar el motor de Windows PowerShell 2.0, vea
Iniciar el motor de Windows PowerShell 2.0.

En sistemas anteriores
El paquete de Windows Management Framework 4.0 que instala Windows PowerShell
4.0 en Windows 7, Windows Server 2008 R2 y Windows Server 2012 incluye el motor de
Windows PowerShell 2.0. El motor de Windows PowerShell 2.0 está habilitado y listo
para usarlo, si es necesario, sin requerir otras operaciones de instalación o
configuración.

El paquete de Windows Management Framework 3.0 que instala Windows


PowerShell 3.0 en Windows 7, Windows Server 2008 R2 y Windows Server 2008 incluye
el motor de Windows PowerShell 2.0. El motor de Windows PowerShell 2.0 está
habilitado y listo para usarlo, si es necesario, sin requerir otras operaciones de
instalación o configuración.

Consulte también
Requisitos del sistema de Windows PowerShell
Instalación de Windows PowerShell
Inicio de Windows PowerShell
Iniciar el motor de Windows PowerShell 2.0
Requisitos del sistema de Windows
PowerShell
Artículo • 06/02/2023

En este artículo se enumeran los requisitos del sistema para Windows PowerShell 3.0,
Windows PowerShell 4.0, Windows PowerShell 5.0 y Windows PowerShell 5.1. Y,
características especiales, como el entorno de scripting integrado (ISE) de
Windows PowerShell, los comandos del Modelo de información común (CIM) y los flujos
de trabajo.

Windows 8.1 y Windows Server 2012 R2 incluyen todos los programas necesarios. Este
artículo está diseñado para usuarios de versiones anteriores de Windows.

Requisitos de sistema operativo

Windows PowerShell 5.1


Windows PowerShell 5.1 se ejecuta en las siguientes versiones de Windows. Para
ejecutar Windows PowerShell 5.1, instale Windows Management Framework 5.1. Para
más información, consulte Instalación y configuración de WMF 5.1.

Versión de Windows Requisito del sistema

Windows Server 2022 Instalado de forma predeterminada

Windows Server 2019 Instalado de forma predeterminada

Windows Server 2016 Instalado de forma predeterminada

Windows Server 2012 R2 Instalar Windows Management Framework 5.1

Windows Server 2012 Instalar Windows Management Framework 5.1

Windows Server 2008 R2 con Service Pack 1 Instalar Windows Management Framework 5.1

Windows 11 Instalado de forma predeterminada

Windows 10 versión 1607 y posteriores Instalado de forma predeterminada

Windows 10 versión 1507, 1511 Instalar Windows Management Framework 5.1

Windows 8.1 Instalar Windows Management Framework 5.1

Windows 7 con Service Pack 1 Instalar Windows Management Framework 5.1


Windows PowerShell 5.0
Windows PowerShell 5.0 se ejecuta en las siguientes versiones de Windows. Para
ejecutar Windows PowerShell 5.0, instale Windows Management Framework 5.1. Para
más información, consulte Instalación y configuración de WMF 5.1.
Windows Management Framework 5.1 sustituye a Windows Management Framework
5.0.

Versión de Windows Requisito del sistema

Windows Server 2022 Versión posterior instalada de forma


predeterminada

Windows Server 2019 Versión posterior instalada de forma


predeterminada

Windows Server 2016 Versión posterior instalada de forma


predeterminada

Windows Server 2012 R2 Instalar Windows Management Framework 5.1

Windows Server 2012 Instalar Windows Management Framework 5.1

Windows Server 2008 R2 con Service Pack Instalar Windows Management Framework 5.1
1

Windows 11 Versión posterior instalada de forma


predeterminada

Windows 10 versión 1607 y posteriores Versión posterior instalada de forma


predeterminada

Windows 10 versión 1507, 1511 Instalado de forma predeterminada

Windows 8.1 Instalar Windows Management Framework 5.1

Windows 7 con Service Pack 1 Instalar Windows Management Framework 5.1

Windows PowerShell 4.0


Windows PowerShell 4.0 se ejecuta en las siguientes versiones de Windows. Para
ejecutar Windows PowerShell 4.0, instale la versión especificada de
Windows Management Framework para el sistema operativo.

Versión de Windows Requisito del sistema

Windows 8.1 Instalado de forma predeterminada


Versión de Windows Requisito del sistema

Windows Server 2012 R2 Instalado de forma predeterminada

Windows 7 con Service Pack 1 Instalar Windows Management Framework 4.0

Windows Server 2008 R2 con Service Pack 1 Instalar Windows Management Framework 4.0

Windows PowerShell 3.0


Windows PowerShell 3.0 se ejecuta en las siguientes versiones de Windows. Para
ejecutar Windows PowerShell 3.0, instale la versión especificada de
Windows Management Framework para su sistema operativo.

Versión de Windows Requisito del sistema

Windows 8 Instalado de forma predeterminada

Windows Server 2012 Instalado de forma predeterminada

Windows 7 con Service Pack 1 Instalar Windows Management Framework 3.0

Windows Server 2008 R2 con Service Pack 1 Instalar Windows Management Framework 3.0

Windows Server 2008 con Service Pack 2 Instalar Windows Management Framework 3.0

Requisitos de Microsoft .NET Framework


En la tabla siguiente se muestran los requisitos de .NET Framework para
Windows PowerShell.

Versión Requisito de .NET

Windows PowerShell 5.1 Requiere la instalación completa de Microsoft .NET Framework 4.5.
Windows 8.1 y Windows Server 2012 R2 incluyen Microsoft .NET
Framework 4.5 de manera predeterminada.

Windows PowerShell 5.0 Requiere la instalación completa de Microsoft .NET Framework 4.5.
Windows 8.1 y Windows Server 2012 R2 incluyen Microsoft .NET
Framework 4.5 de manera predeterminada.

Windows PowerShell 4.0 Requiere la instalación completa de Microsoft .NET Framework 4.5.
Windows 8.1 y Windows Server 2012 R2 incluyen Microsoft .NET
Framework 4.5 de manera predeterminada.
Versión Requisito de .NET

Windows PowerShell 3.0 Requiere la instalación completa de Microsoft .NET Framework 4.


Windows 8 y Windows Server 2012 incluyen Microsoft .NET Framework
4.5 de manera predeterminada, con lo que se cumple este requisito.

Use los vínculos siguientes para descargar Microsoft .NET Framework desde el Centro
de descarga de Microsoft.

Versión Vínculo

.NET Framework 4.5 Microsoft .NET Framework 4.5


( dotNetFx45_Full_setup.exe )

.NET Framework 4 ( dotNetFx40_Full_setup.exe ) Microsoft .NET Framework 4 (instalador


web)

Windows Management Framework 4.0


Windows PowerShell 5.0 requiere que Windows Management Framework 4.0 esté
preinstalado en Windows Server 2008 R2 SP1 y Windows 7 SP1.

WS-Management 3.0
Windows PowerShell 3.0 y Windows PowerShell 4.0 requieren WS-Management 3.0, que
admite el servicio WinRM y el protocolo WSMan. Este programa está incluido en
Windows 8.1, Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows
Management Framework 4.0 y Windows Management Framework 3.0.

Instrumental de administración de Windows


3.0
Windows PowerShell 3.0 y Windows PowerShell 4.0 requiere Instrumental de
administración de Windows 3.0 (WMI). Este programa está incluido en Windows 8.1,
Windows Server 2012 R2, Windows 8, Windows Server 2012, Windows Management
Framework 4.0 y Windows Management Framework 3.0. Si este programa no está
instalado en el equipo, las características que requieren WMI, como los comandos CIM,
no se ejecutan.

Common Language Runtime 4.0


Windows PowerShell 3.0, Windows PowerShell 4.0 y Windows PowerShell 5.0 se
compilan en Common Language Runtime (CLR) 4.0.

Requisitos de la interfaz gráfica de usuario


Windows PowerShell es una aplicación basada en consola que no requiere una interfaz
gráfica de usuario. Es idónea para equipos que no tienen pantallas, monitores ni interfaz
de usuario, como las opciones de instalación de Server Core de
Windows Server 2012 R2 o Windows Server 2012.

Algunos elementos requieren una interfaz gráfica de usuario. Para obtener más
información, vea el artículo de ayuda de cada elemento.

Entorno de scripting integrado (ISE) de Windows PowerShell. Para obtener más


información, consulte Introducción a Windows PowerShell ISE.
Cmdlets
Out-GridView
Show-Command
Show-ControlPanelItem
Show-EventLog
Parámetros
Parámetro ShowWindow del cmdlet Get-Help.
Parámetro ShowSecurityDescriptorUI de los cmdlets Register-
PSSessionConfiguration y Set-PSSessionConfiguration.

Requisitos del motor de Windows PowerShell


Windows PowerShell 4.0 está diseñado para ser compatible con versiones anteriores de
Windows PowerShell 3.0 y Windows PowerShell 2.0. Los cmdlets, proveedores,
complementos, módulos y scripts escritos para Windows PowerShell 2.0 y Windows
PowerShell 3.0 se ejecutan sin cambios en Windows PowerShell 4.0.

Pero debido a un cambio en la directiva de activación de tiempo de ejecución en


Microsoft .NET Framework 4, los programas de host de Windows PowerShell escritos
para Windows PowerShell 2.0 y compilados con Common Language Runtime (CLR) 2.0
no se pueden ejecutar sin modificaciones en Windows PowerShell 3.0, que está
compilado con CLR 4.0.

El requisito mínimo del motor de Windows PowerShell 2.0 es Microsoft


.NET Framework 2.0.50727. Este requisito se cumple mediante Microsoft .NET
Framework 3.5 Service Pack 1. Este requisito no se cumple con Microsoft
.NET Framework 4 y versiones posteriores de Microsoft .NET Framework.

Para información sobre cómo agregar o instalar el motor de Windows PowerShell 2.0 y
agregar o instalar las versiones necesarias de Microsoft .NET Framework, consulte
Instalación del motor de Windows PowerShell 2.0. Para obtener información sobre cómo
iniciar el motor de Windows PowerShell 2.0, consulte Iniciar el motor de Windows
PowerShell 2.0.

Entorno de preinstalación de Windows


Windows PowerShell 2.0, Windows PowerShell 3.0 y Windows PowerShell 4.0 se ejecutan
en el Entorno de preinstalación de Windows (Windows PE). Pero no se admiten los
cmdlets siguientes.

Cmdlets del Servicio de transferencia inteligente en segundo plano (BITS). Para


más información, vea BitsTransfer.
Get-EventLog
Get-WinEvent
Save-Help
Update-Help

El servicio WinRM no está presente en Windows PE.

Consulte también
Instalación de Windows PowerShell

Inicio de Windows PowerShell

Windows Management Framework


Optimización de la experiencia del shell
Artículo • 13/04/2023

PowerShell es un shell de línea de comandos y un lenguaje de scripting, todo en uno.

En Wikipedia se incluye la siguiente descripción de un shell:

Un shell administra la interacción del sistema de usuario mediante la solicitud de


entrada a los usuarios, su interpretación y, después, el control de la salida desde el
sistema operativo subyacente (como un bucle de lectura, evaluación e impresión, o
REPL ).

De forma similar a otros shells como bash o cmd.exe , PowerShell le permite ejecutar
cualquier comando disponible en el sistema, no solo los de PowerShell.

Los comandos de PowerShell se conocen como cmdlets. Los cmdlets son comandos de
PowerShell, no ejecutables independientes. Los comandos de PowerShell no se pueden
ejecutar en otros shells sin ejecutar primero PowerShell.

Características de la interfaz de la línea de


comandos de PowerShell
PowerShell es un shell de comandos moderno que incluye las mejores características de
otros shells populares. A diferencia de la mayoría de los shells que solo aceptan y
devuelven texto, PowerShell acepta y devuelve objetos .NET. El shell tiene varias
características que puede usar para optimizar la experiencia interactiva del usuario.

Un historial de línea de comandos sólido.


Finalización con tabulación y predicción de comandos
Admite alias de comando y parámetro.
Canalización para encadenar comandos.
Sistema de ayuda en la consola, similar a las páginas man de UNIX.

6 Collaborate with us on PowerShell feedback


GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Novedades de Windows PowerShell 5.0
Artículo • 21/03/2023

Windows PowerShell 5.0 incluye nuevas características importantes que amplían y


mejoran su uso, permiten controlar y administrar entornos basados en Windows de
forma más sencilla y completa.

Windows PowerShell 5.0 es compatible con versiones anteriores. Los cmdlets,


proveedores, módulos, complementos, scripts, funciones y perfiles diseñados para
Windows PowerShell 4.0, Windows PowerShell 3.0 y Windows PowerShell 2.0 suelen
funcionar en Windows PowerShell 5.0 sin tener que cambiar nada.

Instalación de Windows PowerShell


Windows PowerShell 5.0 se instala de manera predeterminada en Windows Server 2016
Technical Preview y Windows 10.

Para instalar Windows PowerShell 5.0 en Windows Server 2012 R2, Windows 8.1
Enterprise o Windows 8.1 Pro, descargue e instale Windows Management Framework
5.0 . Procure leer los detalles de la descarga y cumplir todos los requisitos del sistema
antes de instalar Windows Management Framework 5.0.

En este tema
Actualizaciones de DSC de Windows PowerShell 4.0 en KB 3000850
Nuevas características de Windows PowerShell 5.0
Nuevas características de Windows PowerShell 4.0
Nuevas características de Windows PowerShell 3.0

Actualizaciones de Windows PowerShell 4.0 en


el paquete acumulativo de actualizaciones de
noviembre de 2014 (KB 3000850)
Muchas actualizaciones y mejoras en Desired State Configuration (DSC) de
Windows PowerShell en Windows PowerShell 4.0 están disponibles en el paquete
acumulativo de actualizaciones de noviembre de 2014 para Windows RT 8.1,
Windows 8.1 y Windows Server 2012 R2 (KB 3000850). Para determinar si KB 3000850
está instalado en el sistema, ejecute Get-Hotfix -Id KB3000850 en Windows PowerShell.
Actualizaciones para los cmdlets existentes en el módulo
PSDesiredStateConfiguration
Get-DscResource es más rápido (especialmente en el ISE).
Start-DscConfiguration tiene un nuevo parámetro, -UseExisting, que vuelve a
aplicar la última configuración aplicada.
Start-DscConfiguration -Force se ha corregido.
Get-DscLocalConfigurationManager muestra más información útil sobre el
estado del motor.
Test-DscConfiguration devuelve ahora el nombre del equipo junto con True o
False.
New-DscChecksum admite ahora rutas UNC.

Nuevos cmdlets en el módulo PSDesiredStateConfiguration


Update-DscConfiguration: realiza una comprobación del servidor de extracción
a petición.
Stop-DscConfiguration: detiene una configuración que ya se está ejecutando.
Remove-DscConfigurationDocument: permite quitar los documentos de
configuración en diversas etapas (pendientes, anteriores o actuales).

Mejoras en el lenguaje
DependsOn admite ahora recursos compuestos.
DependsOn admite ahora números en los nombres de instancia de recurso.
Las expresiones de nodo que se evalúan como vacías ya no producen errores.
Se ha corregido un error que se producía al evaluar una expresión de nodo
como vacía.
Las configuraciones que llaman a configuraciones funcionan ahora en la consola
de Windows PowerShell.

Mejoras en el modo de extracción


El modo de extracción admite ahora todos los archivos ZIP.
AllowModuleOverwrite funciona ahora correctamente.

Mejoras en la resistencia
El nuevo DebugMode permite volver a cargar los módulos de recursos.
Si se produce un error de configuración, el archivo pending.mof no se elimina.
El Administrador de configuración local (LCM) es ahora más resistente cuando
los valores de metaconfiguración dañados.

Mejoras de diagnóstico
Se muestra una advertencia cuando el LCM establece el temporizador en una
configuración diferente a la especificada.
Los archivos de registro de errores contienen ahora la pila de llamadas de los
recursos de Windows PowerShell.

Mejoras de escalabilidad
El recurso LocalConfigurationManager tiene una propiedad nueva,
ActionAfterReboot.
ContinueConfiguration (valor predeterminado): reanuda automáticamente
una configuración cuando se reinicia un nodo de destino.
StopConfiguration: no reanuda automáticamente una configuración cuando
se reinicia un nodo de destino.
Una ejecución de coherencia puede llevarse a cabo con mayor frecuencia que
una operación de extracción o viceversa.
Compatibilidad de versiones: DSC puede ahora reconocer un documento
generado en un cliente más reciente (incluido con WMF 5.0 ).

Mejoras en la prevención de errores


La versión del módulo se aplica ahora antes de aplicar una configuración.
DebugPreference está ahora establecido correctamente para las llamadas Get-,
Set- o Test-TargetResource.

Mejoras en la administración de credenciales


Ahora se usa un certificado, si se especifican ambas opciones Certificate y
PSDscAllowPlainTextPassword.
Las credenciales se descifran, incluso para Get-TargetResource.
Las credenciales de metaconfiguración se cifran y se descifran.
Los objetos PSCredentials se descifran cuando están en un objeto incrustado.

Mejoras en los recursos integrados


Recurso de paquete
Ya no instala el paquete incorrecto (ya sea de los orígenes web o local).
Ahora admite HTTPS.
Ahora se ofrece compatibilidad con HTTPS en el recurso de paquete.
El recurso de archivo admite ahora las credenciales.

Nuevas características de Windows PowerShell


5.0
Nuevas características de Windows PowerShell
Nuevas características de configuración de estado deseado de Windows
PowerShell
Nuevas características de Windows PowerShell ISE
Nuevas características de servicios web de Windows PowerShell
Correcciones de errores importantes en Windows PowerShell 5.0

Nuevas características de Windows PowerShell


A partir de Windows PowerShell 5.0, se admite el desarrollo mediante clases,
sintaxis formal y semántica que son similares a las de otros lenguajes de
programación orientados a objetos. Class, Enum y otras palabras clave se
agregaron al nuevo lenguaje de Windows PowerShell para admitir la nueva
característica. Para más información sobre el uso de las clases, consulte
about_Classes.

Windows PowerShell 5.0 presenta una nueva secuencia de información


estructurada que puede usar para transmitir datos estructurados entre un script y
los autores de la llamada (o el entorno de hospedaje). Ahora puede usar Write-
Host para emitir la salida en la secuencia de información. Las secuencias de
información también funcionan con PowerShell.Streams, los trabajos, los trabajos
programados y los flujos de trabajo. Las características siguientes admiten la
secuencia de información.
Un nuevo cmdlet Write-Information que permite especificar cómo Windows
PowerShell administra los datos de la secuencia de información de un comando.
Write-Host es un contenedor para Write-Information. Write-Information
también es una actividad de flujo de trabajo admitida.
Dos nuevos parámetros comunes, InformationVariable y InformationAction,
permiten determinar cómo se muestran las secuencias de información desde un
comando. Los valores válidos para InformationAction son Continuar sin
mensajes, Detener, Continuar, Consultar, Omitir o Suspender, siendo Continuar
sin mensajes el valor predeterminado. InformationVariable especifica una
cadena como el nombre de una variable en la que desea guardar los datos de
Write-Host de un comando.
Una nueva variable de preferencia, InformationPreference, especifica su
preferencia predeterminada para los datos de la secuencia de información en
una sesión de Windows PowerShell. El valor predeterminado es Continuar sin
mensajes.
Se agregaron dos nuevos parámetros de flujo de trabajo comunes,
PSInformation e InformationAction.
Cuando usa el comando Format-Table, las columnas de la tabla se formatean
ahora automáticamente evaluando los primeros 300 ms de datos que pasan a
través de la secuencia.
En colaboración con Microsoft Research , se ha agregado un nuevo cmdlet
ConvertFrom-String. ConvertFrom-String permite extraer y analizar objetos
estructurados del contenido de las cadenas de texto. Para más información,
consulte ConvertFrom-String.

Un nuevo cmdlet Convert-String formatea automáticamente el texto según un


ejemplo que se proporciona en un parámetro -Example.

Un nuevo módulo, Microsoft.PowerShell.Archive, incluye cmdlets que permiten


comprimir archivos y carpetas en archivos de almacenamiento (también conocidos
como ZIP), extraer los archivos de archivos ZIP existentes y actualizar archivos ZIP
con versiones más recientes de los archivos comprimidos que contienen.

Un nuevo módulo, PackageManagement, permite detectar e instalar paquetes de


software en Internet. El módulo PackageManagement (conocido anteriormente
como OneGet) es un administrador o multiplexor de administradores de paquetes
existentes (también denominados proveedores de paquetes) destinado a unificar
la administración de paquetes de Windows con una única interfaz de Windows
PowerShell.

Un nuevo módulo, PowerShellGet, permite buscar, instalar, publicar y actualizar los


módulos y recursos de DSC en la Galería de PowerShell , o en un repositorio de
módulos interno que puede configurar ejecutando el cmdlet Register-
PSRepository.

Una nueva palabra clave del lenguaje, Hidden, se agregó para especificar que un
miembro (una propiedad o un método) no se muestra en los resultados de Get-
Member de forma predeterminada (a menos que se agregue el parámetro -Force).
Las propiedades o los métodos marcados como ocultos no se muestran en los
resultados de IntelliSense, a menos que esté en un contexto donde el miembro
deba ser visible; por ejemplo, la variable automática $This debería mostrar los
miembros ocultos en el método de clase.

New-Item, Remove-Item y Get-ChildItem se han mejorado para admitir la creación


y administración de vínculos simbólicos . El parámetro ItemType de New-Item
acepta un nuevo valor, SymbolicLink. Ahora puede crear vínculos simbólicos en
una única línea ejecutando el cmdlet New-Item.

Get-ChildItem también tiene un nuevo parámetro -Depth, que se usa con el


parámetro -Recurse para limitar la recursión. Por ejemplo, Get-ChildItem -Recurse -
Depth 2 devuelve resultados de la carpeta actual, de todas las carpetas secundarias
dentro de la carpeta actual y de todas las carpetas dentro de las carpetas
secundarias.
Copy-Item permite ahora copiar archivos o carpetas de una sesión de Windows
PowerShell a otra, lo que significa que puede copiar archivos en sesiones
conectadas a equipos remotos (incluidos los equipos que ejecutan Nano Server y
que, por tanto, no tienen ninguna otra interfaz). Para copiar archivos, especifique
los identificadores de PSSession como el valor de los nuevos parámetros -
FromSession y -ToSession, y agregue -Path y -Destination para especificar la ruta
de acceso de origen y el destino, respectivamente. Por ejemplo, Copy-Item -Path
c:\myFile.txt -ToSession $s -Destination d:\carpetaDeDestino.

La transcripción de Windows PowerShell se mejoró para aplicarse a todas las


aplicaciones de hospedaje (como Windows PowerShell ISE) en lugar de solo al host
de consola (powershell.exe). Las opciones de transcripción (incluida la habilitación
de una transcripción de todo el sistema) pueden configurarse habilitando la
opción de directiva de grupo Activar la transcripción de PowerShell, que se
encuentra en Plantillas administrativas/Componentes de Windows/Windows
PowerShell.

Una nueva característica de seguimiento detallado de scripts permite habilitar el


seguimiento detallado y el análisis del uso de scripting de Windows PowerShell en
un sistema. Después de habilitar el seguimiento detallado de scripts, Windows
PowerShell registra todos los bloques de scripts en el registro de eventos de
Seguimiento de eventos para Windows (ETW), Microsoft-Windows-
PowerShell/Operational.

A partir de Windows PowerShell 5.0, los nuevos cmdlets de sintaxis de mensajes de


cifrado admiten el cifrado y descifrado de contenido mediante el formato estándar
IETF para proteger los mensajes de manera criptográfica según se documenta en
RFC5652 . Los cmdlets Get-CmsMessage, Protect-CmsMessage y Unprotect-
CmsMessage se han agregado al módulo Microsoft.PowerShell.Security.

Los nuevos cmdlets del módulo Microsoft.PowerShell.Utility, Get-Runspace,


Debug-Runspace, Get-RunspaceDebug, Enable-RunspaceDebug y Disable-
RunspaceDebug, permiten establecer opciones de depuración, así como iniciar y
detener la depuración, en un espacio de ejecución. Para depurar espacios de
ejecución arbitrarios, es decir, espacios de ejecución que no son el predeterminado
de una consola de Windows PowerShell o una sesión de Windows PowerShell ISE,
Windows PowerShell permite establecer puntos de interrupción en un script y
hacer que los puntos de interrupción agregados detengan la ejecución del script
hasta que se pueda conectar un depurador para depurar el script del espacio de
ejecución. Se ha agregado compatibilidad para la depuración anidada para los
espacios de ejecución arbitrarios en el depurador de scripts de Windows
PowerShell para los espacios de ejecución.
Un nuevo cmdlet Format-Hex se ha agregado al módulo
Microsoft.PowerShell.Utility. Format-Hex permite ver datos de texto o binarios en
formato hexadecimal.

Los cmdlets Get-Clipboard y Set-Clipboard se agregaron al módulo


Microsoft.PowerShell.Utility; estos facilitan la transferencia de contenido hacia y
desde la sesión de Windows PowerShell. Los cmdlets Clipboard admiten imágenes,
archivos de audio, listas de archivos y texto.

Se agregó un nuevo cmdlet, Clear-RecycleBin, al módulo


Microsoft.PowerShell.Management; este cmdlet vacía la Papelera de reciclaje de
una unidad fija, que incluye las unidades externas. De forma predeterminada, se le
pedirá que confirme un comando Clear-RecycleBin, porque la propiedad
ConfirmImpact del cmdlet está establecida en ConfirmImpact.High.

Un nuevo cmdlet, New-TemporaryFile, permite crear un archivo temporal como


parte del scripting. De forma predeterminada, el nuevo archivo temporal se crea en
C:\Users\<user name>\AppData\Local\Temp .

Los cmdlets Out-File, Add-Content y Set-Content tienen ahora un nuevo


parámetro -NoNewline, que omite una nueva línea después de la salida.

El cmdlet New-Guid aprovecha la clase Guid de .NET Framework para generar un


GUID, que resulta útil al escribir scripts o recursos de DSC.

Dado que la información de la versión de archivo puede ser confusa,


especialmente después de aplicar una revisión a un archivo, las nuevas
propiedades de script FileVersionRaw y ProductVersionRaw están disponibles para
los objetos FileInfo. Por ejemplo, puede ejecutar el siguiente comando para
mostrar los valores de estas propiedades de powershell.exe, donde $pid contiene
el identificador de proceso de una sesión en ejecución de Windows PowerShell:
Get-Process -Id $pid -FileVersionInfo | Format-List *version* -Force

Los nuevos cmdlets Enter-PSHostProcess y Exit-PSHostProcess le permiten depurar


scripts de Windows PowerShell en procesos independientes del proceso actual que
se ejecuta en la consola de Windows PowerShell. Ejecute Enter-PSHostProcess para
introducir, o establecer la asociación con, un identificador de proceso específico y
luego ejecute Get-Runspace para devolver los espacios de ejecución activos dentro
del proceso. Ejecute Exit-PSHostProcess para desasociarse del proceso cuando
acabe de depurar el script dentro del proceso.

Un nuevo cmdlet Wait-Debugger se ha agregado al módulo


Microsoft.PowerShell.Utility. Puede ejecutar Wait-Debugger para detener un script
en el depurador antes de ejecutar la siguiente instrucción del script.

El depurador del flujo de trabajo de Windows PowerShell admite ahora la


finalización con comando o tabulación y permite depurar funciones de flujo de
trabajo anidadas. Ahora puede presionar Ctrl+Interrumpir para introducir el
depurador en un script en ejecución, tanto en sesiones locales como remotas, así
como en un script de flujo de trabajo.

Se agregó un cmdlet Debug-Job al módulo Microsoft.PowerShell.Core para


depurar scripts de trabajos en ejecución del flujo de trabajo de Windows
PowerShell, trabajos en segundo plano y trabajos que se ejecutan en sesiones
remotas.

Se ha agregado un estado nuevo, AtBreakPoint, para los trabajos de Windows


PowerShell. El estado AtBreakpoint se aplica cuando un trabajo ejecuta un script
que incluye puntos de interrupción establecidos y el script alcanza un punto de
interrupción. Si un trabajo se detiene en un punto de interrupción de depuración,
debe depurar el trabajo ejecutando el cmdlet Debug-Job.

Windows PowerShell 5.0 implementa la compatibilidad con varias versiones de un


único módulo de Windows PowerShell en la misma carpeta en $PSModulePath. Se
ha agregado una propiedad RequiredVersion a la clase ModuleSpecification para
ayudarle a obtener la versión deseada de un módulo; esta propiedad es
mutuamente exclusiva con la propiedad ModuleVersion. RequiredVersion se
admite ahora como parte del valor del parámetro FullyQualifiedName de los
cmdlets Get-Module, Import-Module y Remove-Module.

Ahora puede realizar la validación de la versión de módulo ejecutando el cmdlet


Test-ModuleManifest.

Los resultados del cmdlet Get-Command muestran ahora una columna Version; se
ha agregado una nueva propiedad Version a la clase CommandInfo. Get-
Command muestra comandos de varias versiones del mismo módulo. La
propiedad Version también forma parte de las clases derivadas de CmdletInfo:
CmdletInfo y ApplicationInfo.

Get-Command tiene un nuevo parámetro, -ShowCommandInfo, que devuelve


información de ShowCommand como PSObjects. Esta funcionalidad es
especialmente útil cuando se ejecuta Show-Command en Windows PowerShell ISE
mediante la comunicación remota de Windows PowerShell. El parámetro -
ShowCommandInfo reemplaza la función Get-SerializedCommand existente en el
módulo Microsoft.PowerShell.Utility, pero el script Get-SerializedCommand sigue
estando disponible para admitir el scripting de nivel inferior.
Un nuevo cmdlet Get-ItemPropertyValue permite obtener el valor de una
propiedad sin usar la notación de puntos. Por ejemplo, en versiones anteriores de
Windows PowerShell, puede ejecutar el comando siguiente para obtener el valor
de la propiedad Application Base de la clave del registro de PowerShellEngine:
(Get-ItemProperty -Path
HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name
ApplicationBase).ApplicationBase. A partir de Windows PowerShell 5.0, puede
ejecutar Get-ItemPropertyValue -Path
HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name
ApplicationBase.

La consola de Windows PowerShell usa ahora el color de sintaxis, como en


Windows PowerShell ISE.

Un nuevo módulo NetworkSwitch contiene cmdlets que permiten aplicar la


configuración de modificador, LAN virtual (VLAN) y básica del puerto del
modificador de red de capa 2 a los modificadores de red certificados con el
logotipo de Windows Server 2012 R2.

El parámetro FullyQualifiedName se agregó a los cmdlets Import-Module y


Remove-Module para permitir el almacenamiento de varias versiones de un mismo
módulo.

Save-Help, Update-Help, Import-PSSession, Export-PSSession, y Get-Command


tienen un nuevo parámetro, FullyQualifiedModule, de tipo ModuleSpecification.
Agregue este parámetro para especificar un módulo con su nombre completo.

El valor de $PSVersionTable.PSVersion se ha actualizado a 5.0.

WMF 5.0 (PowerShell 5.0) incluye el módulo Pester. Pester es un marco de prueba
unitaria para PowerShell. Proporciona algunas palabras clave fáciles de usar que le
permiten crear pruebas para sus scripts.

Nuevas características de configuración de estado


deseado de Windows PowerShell
Las mejoras en el lenguaje de Windows PowerShell permiten definir los recursos
de Desired State Configuration (DSC) de Windows PowerShell mediante clases.
Import-DscResource es ahora una verdadera palabra clave dinámica; Windows
PowerShell analiza el módulo raíz del módulo especificado y busca las clases que
contienen el atributo DscResource. Ahora puede usar clases para definir recursos
de DSC, en los que no se requiere un archivo MOF ni una subcarpeta DSCResource
en la carpeta del módulo. Un archivo de módulo de Windows PowerShell puede
contener varias clases de recursos de DSC.
Se ha agregado un nuevo parámetro, ThrottleLimit, a los siguientes cmdlets en el
módulo PSDesiredStateConfiguration. Agregue el parámetro ThrottleLimit para
especificar el número de dispositivos o equipos de destino en los que quiere que
el comando funcione al mismo tiempo.
Get-DscConfiguration
Get-DscConfigurationStatus
Get-DscLocalConfigurationManager
Restore-DscConfiguration
Test-DscConfiguration
Compare-DscConfiguration
Publish-DscConfiguration
Set-DscLocalConfigurationManager
Start-DscConfiguration
Update-DscConfiguration
Con los informes de errores de DSC centralizados, no solo se registra información
de error completa en el registro de eventos, sino que también se envía a una
ubicación central para su posterior análisis. Puede usar esta ubicación central para
almacenar los errores de configuración de DSC que se han producido para
cualquier servidor de su entorno. Después de definir el servidor de informes en la
metaconfiguración, todos los errores se envían al servidor de informes y, luego, se
almacenan en una base de datos. Puede configurar esta funcionalidad
independientemente de si se configura un nodo de destino para extraer las
configuraciones de un servidor de extracción.
Las mejoras en Windows PowerShell ISE facilitan la creación de recursos de DSC.
Ahora puede hacer lo siguiente.
Enumeración de todos los recursos de DSC en un bloque de configuración o un
bloque de nodo escribiendo Ctrl+Space en una línea en blanco dentro del
bloque.
Finalización automática de propiedades de recurso de tipo enumeración.
Finalización automática de la propiedad DependsOn de los recursos de DSC, en
función de otras instancias de recurso de la configuración.
Finalización con tabulación mejorada de los valores de propiedad de recurso.
Un usuario puede ejecutar ahora un recurso en un conjunto de credenciales
especificado agregando el atributo PSDscRunAsCredential a un bloque de nodo.
Por ejemplo, PSDscRunAsCredential = Get-Credential Contoso\DscUser. Esta
funcionalidad es útil para crear configuraciones que ejecuten Windows Installer e
instaladores ejecutables, accedan al subárbol del Registro por usuario o realicen
otras tareas fuera del contexto del usuario actual.
Se agregó compatibilidad con la versión de 32 bits (basada en x86) para la palabra
clave Configuration.
Ahora Windows PowerShell ofrece compatibilidad con la ayuda personalizada para
configuraciones de DSC, que se define mediante la adición de [CmdletBinding()] a
la función de configuración generada.
Un nuevo atributo DscLocalConfigurationManager designa un bloque de
configuración como una metaconfiguración, que se usa para configurar el
Administrador de configuración local de DSC. Este atributo restringe una
configuración para que únicamente contenga elementos que configuren el
Administrador de configuración local de DSC. Durante el procesamiento, esta
configuración genera un archivo *.meta.mof que se envía a los nodos de destino
apropiados mediante el cmdlet Set-DscLocalConfigurationManager.
Ahora se admiten configuraciones parciales en Windows PowerShell 5.0. Puede
entregar documentos de configuración a un nodo en fragmentos. Para que un
nodo reciba varios fragmentos de un documento de configuración, su
administrador de configuración local debe estar establecido para especificar los
fragmentos esperados.
La sincronización entre equipos es una novedad de DSC en Windows PowerShell
5.0. Con los recursos integrados WaitFor* (WaitForAll, WaitForAny y
WaitForSome), ahora puede especificar dependencias entre equipos durante las
ejecuciones de configuración, sin orquestación externa. Estos recursos ofrecen
sincronización de nodo a nodo mediante conexiones CIM en el protocolo WS-
Man. Una configuración puede esperar el cambio de estado del recurso específico
de otro equipo.
Just Enough Administration (JEA), una nueva característica de seguridad de
delegación, aprovecha DSC y los espacios de ejecución restringidos de Windows
PowerShell para ayudar a las empresas a evitar la pérdida de datos o riesgos
causados por empleados, ya sea intencionada o de manera involuntaria. Para más
información sobre JEA, incluida la ubicación donde puede descargar el recurso
DSC de xJEA, consulte Just Enough Administration.
Se agregaron los siguientes cmdlets nuevos al módulo
PSDesiredStateConfiguration.
Un nuevo cmdlet Get-DscConfigurationStatus obtiene información de alto nivel
acerca del estado de configuración desde un nodo de destino. Puede obtener el
estado de todas las configuraciones o solo de la última.
Un nuevo cmdlet Compare-DscConfiguration compara una configuración
especificada con el estado real de uno o varios nodos de destino.
Un nuevo cmdlet Publish-DscConfiguration copia un archivo MOF de
configuración en un nodo de destino, pero no aplica la configuración. La
configuración se aplica durante el siguiente paso de coherencia o cuando se
ejecuta el cmdlet Update-DscConfiguration.
Un nuevo cmdlet Test-DscConfiguration permite comprobar si una
configuración resultante coincide con la configuración deseada, para lo cual
devuelve True si la configuración coincide con la configuración deseada o False
si no coincide.
Un nuevo cmdlet Update-DscConfiguration fuerza el procesamiento de una
configuración. Si el Administrador de configuración Local está en modo de
extracción, el cmdlet obtiene la configuración del servidor de extracción antes
de aplicarla.

Nuevas características de Windows PowerShell ISE


Ahora puede editar scripts y archivos de Windows PowerShell remoto en una copia
local de Windows PowerShell ISE. Para ello, debe ejecutar Enter-PSSession para
iniciar una sesión remota en el equipo que almacena los archivos que desea editar
y, después, ejecutar la ruta de acceso de PSEdit< y el nombre de archivo en el
equipo remoto>. Esta característica facilita la edición de archivos de Windows
PowerShell que están almacenados en la opción de instalación Server Core de
Windows Server, donde Windows PowerShell ISE no puede ejecutarse.
El cmdlet Start-Transcript se admite ahora en Windows PowerShell ISE.
Ahora puede depurar scripts remotos en Windows PowerShell ISE.
Un nuevo comando de menú, Break-All (Ctrl+B) entra en el depurador para los
scripts que se ejecutan de forma local y remota.

Nuevas características de servicios web de Windows


PowerShell (Extensión IIS Management OData)
A partir de Windows PowerShell 5.0, puede generar un conjunto de cmdlets de
Windows PowerShell según la funcionalidad expuesta por un punto de conexión
de OData determinado, mediante el cmdlet Export-ODataEndpointProxy, que se
encuentra en el nuevo módulo Microsoft.PowerShell.OdataUtils.

Correcciones de errores importantes en Windows


PowerShell 5.0
Windows PowerShell 5.0 incluye una nueva implementación de COM, que ofrece
importantes mejoras de rendimiento para el trabajo con objetos COM.
Se realizaron mejoras de rendimiento importantes en la primera finalización con
tabulación en una sesión de Windows PowerShell, lo que reduce el tiempo de
finalización con tabulación en casi 500 ms.

Nuevas características de Windows PowerShell


4.0
Windows PowerShell 4.0 es compatible con versiones anteriores. Los cmdlets,
proveedores, módulos, complementos, scripts, funciones y perfiles diseñados para
Windows PowerShell 3.0 y Windows PowerShell 2.0 funcionan en Windows PowerShell
4.0 sin tener que realizar ningún cambio.

Windows PowerShell 4.0 está instalado de manera predeterminada en Windows 8.1 y


Windows Server 2012 R2. Para instalar Windows PowerShell 4.0 en Windows 7 con SP1 o
Windows Server 2008 R2, descargue e instale Windows Management Framework 4.0.
Procure leer los detalles de la descarga y cumplir todos los requisitos del sistema antes
de instalar Windows Management Framework 4.0.

Nuevas características de Windows PowerShell


Nuevas características del Entorno de scripting integrado (ISE) de Windows
PowerShell
Nuevas características del flujo de trabajo de Windows PowerShell
Nuevas características de servicios web de Windows PowerShell
Nuevas características de Windows PowerShell Web Access
Correcciones de errores importantes en Windows PowerShell 4.0

Windows PowerShell 4.0 incluye las siguientes características nuevas.

Nuevas características de Windows PowerShell


La configuración de estado deseado (DSC) de Windows PowerShell es un nuevo
sistema de administración de Windows PowerShell 4.0 que permite implementar y
administrar los datos de configuración de servicios de software y el entorno en el
que se ejecutan estos servicios. Para más información sobre DSC, consulte
Introducción a la configuración de estado deseado de Windows PowerShell.
Save-Help permite guardar ahora la ayuda relativa a los módulos instalados en
equipos remotos. Puede usar Save-Help para descargar la Ayuda del módulo de un
cliente conectado a Internet (en el que no tienen por qué estar instalados todos los
módulos de los que desea obtener ayuda). Luego, puede copiar la Ayuda guardada
en una carpeta compartida remota o en un equipo remoto sin acceso a Internet.
El depurador de Windows PowerShell se mejoró para permitir la depuración de los
flujos de trabajo de Windows PowerShell, así como de los scripts que se ejecutan
en equipos remotos. Ahora, los flujos de trabajo de Windows PowerShell se
pueden depurar en el nivel de script tanto desde la línea de comandos de
Windows PowerShell como desde Windows PowerShell ISE. Ahora, los scripts de
Windows PowerShell (y también los flujos de trabajo de scripts) se pueden depurar
en sesiones remotas. Las sesiones de depuración remotas se conservan en
sesiones remotas de Windows PowerShell que se desconectan y, luego, se vuelven
a conectar.
Gracias al parámetro RunNow de Register-ScheduledJob y Set-ScheduledJob, ya
no es necesario definir la fecha y hora de inicio inmediatas en los trabajos con el
parámetro Trigger.
Ahora, Invoke-RestMethod e Invoke-WebRequest permiten definir todos los
encabezados con el parámetro Headers. Aunque este parámetro siempre ha
existido, era uno de los diversos parámetros para cmdlets web que provocaban
errores o excepciones.
Get-Module tiene un nuevo parámetro, FullyQualifiedName, del tipo
ModuleSpecification[]. Ahora, el parámetro FullyQualifiedName de Get-Module
permite especificar un módulo mediante su nombre, versión y, opcionalmente, su
GUID.
La configuración de directiva de ejecución predeterminada en Windows Server
2012 R2 es RemoteSigned. En Windows 8.1, no hay ningún cambio en la
configuración predeterminada.
A partir de Windows PowerShell 4.0, es posible invocar métodos mediante
nombres de método dinámicos. Así, se puede usar una variable para almacenar un
nombre de método y, luego, invocar dinámicamente el método llamando a esa
variable.
Los trabajos de flujo de trabajo asincrónicos ya no se eliminan cuando ha
transcurrido el tiempo de espera especificado en el parámetro común de flujo de
trabajo PSElapsedTimeoutSec.
Se ha agregado un nuevo parámetro (RepeatIndefinitely) a los cmdlets New-
JobTrigger y Set-JobTrigger. Con este parámetro, ya no es necesario especificar un
valor TimeSpan.MaxValue para el parámetro RepetitionDuration para que un
trabajo programado se ejecute de forma repetida durante un período indefinido.
Se ha agregado un parámetro Passthru a los cmdlets Enable-JobTrigger y Disable-
JobTrigger. El parámetro Passthru muestra los objetos que el comando crea o
modifica.
Ahora, los nombres de parámetro para especificar un grupo de trabajo en los
cmdlets Add-Computer y Remove-Computer son coherentes, ya que ambos
cmdlets usan el parámetro WorkgroupName.
Se ha agregado un nuevo parámetro común, PipelineVariable. PipelineVariable
permite guardar los resultados de un comando canalizado (o de parte de un
comando canalizado) como una variable que se puede pasar a través del resto de
la canalización.
Ahora se puede usar una sintaxis de método para filtrar colecciones. Esto significa
que una colección de objetos se puede filtrar usando una sintaxis simplificada,
similar a la de Where() o Where-Object, con el formato de una llamada a método.
A continuación se muestra un ejemplo: (Get-Process).where({$_.Name -match
'powershell'})
El cmdlet Get-Process tiene un nuevo parámetro de modificador,
IncludeUserName.
Se ha agregado un nuevo cmdlet, Get-FileHash, que devuelve un hash de archivo
en uno de los distintos formatos de un archivo concreto.
En Windows PowerShell 4.0, si un módulo usa la clave DefaultCommandPrefix en
su manifiesto, o si el usuario importa un módulo con el parámetro Prefix, la
propiedad ExportedCommands del módulo muestra los comandos en el módulo
con el prefijo. Cuando se ejecutan comandos usando la sintaxis de módulo
completo (nombreDelMódulo\nombreDelComando), los nombres de comando
deben incluir el prefijo.
El valor de $PSVersionTable.PSVersion se ha actualizado a 4.0.
El comportamiento del operador Where() ha cambiado. Ya no se admite que
Collection.Where('property -match name') acepte una expresión de cadena con el

formato "Property -CompareOperator Value" . Sin embargo, el operador Where() sí


sigue aceptando expresiones de cadena con formato de bloque de script.

Nuevas características del Entorno de scripting integrado


(ISE) de Windows PowerShell
Windows PowerShell ISE admite la depuración tanto del flujo de trabajo de
Windows PowerShell como de scripts remotos.
Se ha agregado compatibilidad con IntelliSense para los proveedores y
configuraciones de la configuración de estado deseado de Windows PowerShell.

Nuevas características del flujo de trabajo de Windows


PowerShell
Se ha agregado compatibilidad con un nuevo parámetro común PipelineVariable
en el contexto de las canalizaciones iterativas, como las que se usan en System
Center Orchestrator; es decir, canalizaciones que ejecutan comandos simplemente
de izquierda a derecha, en contraposición a la ejecución intercalada mediante
streaming.
El enlace de parámetros ha mejorado notablemente y ahora funciona fuera de
escenarios de finalización con tabulación, como sucede con los comandos que no
existen en el espacio de ejecución actual.
Se ha agregado compatibilidad con las actividades de contenedor personalizadas
al flujo de trabajo de Windows PowerShell. Si un parámetro de actividad es de tipo
Activity, Activity[] o es una colección genérica de actividades y el usuario ha
especificado un bloque de script como argumento, el flujo de trabajo de
Windows PowerShell convierte el bloque de script a XAML, como sucede con la
compilación de script a flujo de trabajo de Windows PowerShell normal.
Después de un bloqueo, el flujo de trabajo de Windows PowerShell vuelve a
conectarse automáticamente a los nodos administrados.
Ahora, puede limitar las instrucciones de actividad de Foreach -Parallel con la
propiedad ThrottleLimit.
El parámetro común ErrorAction tiene un nuevo valor válido, Suspend, exclusivo
para flujos de trabajo.
Ahora, un extremo de flujo de trabajo se cierra automáticamente si no hay
sesiones activas, trabajos en curso o trabajos pendientes. Esta característica
conserva los recursos en el equipo que actúa como servidor de flujo de trabajo
cuando se cumplen las condiciones de cierre automático.

Nuevas características de servicios web de Windows


PowerShell
Si se produce un error en los servicios web de Windows PowerShell (PSWS,
también denominado Extensión IIS Management OData) mientras se ejecuta un
cmdlet, los mensajes de error que recibe el autor de la llamada son más detallados.
Además, los códigos de error siguen las directrices de códigos de error de la API
de REST de Azure.
Ahora, un extremo puede definir la versión de API, así como exigir el uso de una
versión específica de la API. Si se produce una discrepancia de versión entre el
cliente y el servidor, los errores se muestran tanto en el cliente como en el
servidor.
La administración del esquema de distribución se ha simplificado, ya que ahora los
valores de los campos que faltan en el esquema se generan automáticamente. Los
valores se generan aunque el esquema de distribución no exista, lo que constituye
un punto de partida de gran ayuda.
El tratamiento de tipos en PSWS mejoró y ahora admite tipos que usan un
constructor diferente al constructor predeterminado, en un comportamiento
similar al de PSTypeConverter en Windows PowerShell. Esto permite usar tipos
complejos con PSWS.
Ahora, PSWS permite expandir una instancia asociada mientras una consulta se
ejecuta. El coste de transferencia de contenido binario de gran volumen (como
imágenes, audio o vídeos) es significativo, de modo que es mejor transferir datos
binarios sin codificación. PSWS usa secuencias de recurso con nombre para realizar
transferencias sin codificación. La secuencia de recurso con nombre es una
propiedad de una entidad de tipo Edm.Stream. Cada secuencia de recurso con
nombre tiene un URI diferente para las operaciones GET o UPDATE.
Ahora, las acciones de OData proporcionan un mecanismo para invocar métodos
distintos a Crear, Leer, Actualizar y Eliminar en un recurso. Se puede invocar una
acción enviando una solicitud HTTP POST al URI definido para la acción. Los
parámetros de la acción se definen en el cuerpo de la solicitud POST.
A fin de mantener la coherencia con las directrices de Microsoft Azure, es
necesario simplificar todas las direcciones URL. Un cambio incluido en Key As
Segment permite representar claves sencillas como segmentos. Tenga en cuenta
que, como antes, las referencias en las que se usan varios valores de clave
requieren valores separados por comas en la notación entre paréntesis.
Antes de esta versión de PSWS, la única forma de llevar a cabo operaciones de
creación, actualización y eliminación consistía en invocar Post, Put o Delete en un
recurso de primer nivel. La novedad en esta versión de PSWS es que las
operaciones de recursos incluidos permiten a los usuarios lograr los mismos
resultados cuando el acceso al mismo recurso es menos directo, como si ese
recurso fuera un recurso incluido.

Nuevas características de Windows PowerShell Web


Access
Puede desconectarse de sesiones existentes y volver a conectarse a ellas en la
consola de Windows PowerShell Web Access basada en web. Un botón Guardar en
la consola basada en web permite desconectarse de una sesión sin eliminarla y
volver a conectarse a ella.
Los parámetros predeterminados se pueden mostrar en la página de inicio de
sesión. Para mostrar los parámetros predeterminados, configure los valores de
todas las opciones recogidas en el área Configuración de conexión opcional de la
página de inicio de sesión en un archivo denominado web.config. Puede usar el
archivo web.config para configurar todas las opciones de conexión opcionales,
salvo otro conjunto de credenciales.
En Windows Server 2012 R2, las reglas de autorización de Windows PowerShell
Web Access se pueden administrar de manera remota. Ahora, los cmdlets Add-
PswaAuthorizationRule y Test-PswaAuthorizationRule incluyen un parámetro
Credential con el que los administradores pueden administrar reglas de
autorización desde un equipo remoto o en una sesión de Windows PowerShell
Web Access.
Ahora puede tener varias sesiones de Windows PowerShell Web Access en una
única sesión de explorador usando una nueva pestaña de explorador en cada
sesión. Ya no es necesario abrir una nueva sesión del explorador para conectarse a
una sesión nueva en la consola de Windows PowerShell basada en web.

Correcciones de errores importantes en Windows


PowerShell 4.0
Get-Counter puede ahora devolver contadores que contienen un carácter de
apóstrofo en las ediciones en francés de Windows.
Ahora el método GetType se puede ver en objetos deserializados.
Las instrucciones #Requires permiten ahora a los usuarios requerir derechos de
acceso de administrador si así lo precisan.
El cmdlet Import-Csv omite ahora las líneas vacías.
Se solucionó un problema en el que Windows PowerShell ISE usaba demasiada
memoria al ejecutar un comando Invoke-WebRequest.
Get-Module muestra ahora las versiones de módulo en una columna Version.
Remove-Item -Recurse ahora quita los elementos de las subcarpetas, como es de
esperar.
Se agregó una propiedad UserName a los objetos de salida Get-Process.
El cmdlet Invoke-RestMethod devuelve ahora todos los resultados disponibles.
Ahora, Add-Member surte efecto en las tablas hash, aun cuando no se haya tenido
acceso a esas tablas hash.
Select-Object -Expand ya no genera un error o una excepción si el valor de la
propiedad es NULL o está vacío.
Get-Process se puede usar ahora en una canalización con otros comandos que
obtienen la propiedad ComputerName de los objetos.
Ahora, ConverTo-Json y ConvertFrom-Json pueden aceptar términos entre
comillas dobles y sus mensajes de error son localizables.
Get-Job devuelve ahora cualquier trabajo programado completado, incluso en las
nuevas sesiones.
Se solucionaron los problemas con el montaje y desmontaje de VHD con el
proveedor FileSystem en Windows PowerShell 4.0. Ahora, Windows PowerShell es
capaz de detectar nuevas unidades de disco cuando se montan en la misma
sesión.
Ya no es necesario cargar explícitamente los módulos ScheduledJob o Workflow
para trabajar con sus tipos de trabajo.
Se han realizado mejoras de rendimiento en el proceso de importación de flujos
de trabajo que definen los flujos de trabajo anidados. Este proceso es ahora más
rápido.

Nuevas características de Windows PowerShell


3.0
Windows PowerShell 3.0 incluye las siguientes características nuevas.

Flujo de trabajo de Windows PowerShell


Windows PowerShell Web Access
Nuevas características de Windows PowerShell ISE
Compatibilidad con Microsoft .NET Framework 4.0
Compatibilidad con el Entorno de preinstalación de Windows
Sesiones desconectadas
Conectividad de sesiones sólida
Sistema de ayuda actualizable
Mejor ayuda en línea
Integración de CIM
Archivos de configuración de sesión
Integración de trabajos programados y del programador de tareas
Mejoras en el lenguaje de Windows PowerShell
Nuevos cmdlets principales
Mejoras en los proveedores y cmdlets principales existentes
Detección e importación de módulos remotos
Mejor finalización con tabulación
Carga automática de módulos
Mejoras en la experiencia de módulo
Detección de comandos simplificada
Mejor compatibilidad con registros, diagnósticos y directiva de grupo
Mejoras de formato y salida
Mejor experiencia de host de consola
Nuevas API de cmdlets y de hospedaje
Mejoras en el rendimiento
Compatibilidad con RunAs y host compartido
Mejoras en el tratamiento de caracteres especiales

Flujo de trabajo de Windows PowerShell


El flujo de trabajo de Windows PowerShell reúne toda la eficacia de Windows Workflow
Foundation en Windows PowerShell. Así, puede escribir flujos de trabajo en XAML o en
el lenguaje de Windows PowerShell y ejecutarlos tal y como ejecutaría un cmdlet. El
cmdlet Get-Command obtiene los comandos de flujo de trabajo y el cmdlet Get-Help
obtiene ayuda para los flujos de trabajo.

Los flujos de trabajo son secuencias de actividades de administración de varios equipos


de larga ejecución, repetibles, frecuentes y que se pueden paralelizar, interrumpir,
suspender y reiniciar. Los flujos de trabajo se pueden reanudar desde una interrupción
intencional o accidental, como un corte del suministro eléctrico, un reinicio de Windows
o una interrupción de la red.

Los flujos de trabajo son, además, portátiles. Pueden exportarse como archivos XAML o
importarse desde ellos. Puede escribir configuraciones de sesión personalizadas que
permitan que usuarios delegados o subordinados ejecuten el flujo de trabajo o las
actividades de un flujo de trabajo.

La siguiente lista describe muchos de los beneficios del flujo de trabajo de Windows
PowerShell.

Automatización de tareas secuenciadas y de larga ejecución.


Supervisión remota de tareas de larga ejecución. El estado y progreso de las
actividades están visibles en cualquier momento.
Administración de varios equipos. Ejecute tareas como flujos de trabajo
simultáneamente en cientos de nodos administrados. El flujo de trabajo de
Windows PowerShell incluye una biblioteca integrada de parámetros de
administración comunes, como PSComputerName, que hacen posibles escenarios
de administración de varios equipos.
Ejecución de procesos complejos con una tarea única. En un solo flujo de trabajo
se pueden combinar varios scripts relacionados que implementen un escenario
completo.
Persistencia: un flujo de trabajo se guarda (o se marca) en puntos específicos
definidos por su autor, de forma que ese flujo de trabajo se puede reanudar desde
la última tarea (o punto de comprobación) que se ha guardado, en lugar de tener
que reiniciarlo desde el principio.
Solidez. Recuperación de errores automatizada. Los flujos de trabajo son inmunes
a los reinicios, tanto si son planeados como si no. Por lo tanto, se puede suspender
la ejecución de un flujo de trabajo y después reanudar el flujo de trabajo desde el
último punto de persistencia. Los autores de flujos de trabajo pueden designar
actividades específicas para que se vuelvan a ejecutar en caso de error en uno o
más nodos administrados.
Capacidad para desconectarse, reconectarse y ejecutarse en sesiones
desconectadas. Los usuarios se pueden conectar y desconectar del servidor de
flujo de trabajo, pero este sigue ejecutándose de manera continua. Puede cerrar la
sesión en el equipo cliente o reiniciar el equipo cliente y supervisar la ejecución del
flujo de trabajo desde otro equipo sin interrumpirlo.
Programación. Las tareas de flujo de trabajo se pueden programar como cualquier
script o cmdlet de Windows PowerShell.
Limitación del flujo de trabajo y la conexión. La ejecución del flujo de trabajo y las
conexiones a los nodos se pueden limitar, lo que permite escenarios de alta
disponibilidad y escalabilidad.

Windows PowerShell Web Access


Windows PowerShell Web Access es una característica de Windows Server 2012 con la
que los usuarios pueden ejecutar comandos y scripts de Windows PowerShell en una
consola basada en web. Los dispositivos que usan la consola basada en web no
requieren la instalación de Windows PowerShell, de un software de administración
remota o de un complemento de explorador. Lo único que se necesita es una puerta de
enlace de Windows PowerShell Web Access correctamente configurada y un explorador
del dispositivo cliente que admita JavaScript y acepte cookies.

Para obtener más información, consulte Windows PowerShell Web Access.

Nuevas características de Windows PowerShell ISE


En Windows PowerShell 3.0, Entorno de scripting integrado de Windows PowerShell
(ISE) posee un gran número de características nuevas, como IntelliSense, la ventana
Show-Command, un panel de consola unificado, fragmentos de código, coincidencia de
llaves, expansión y contracción de secciones, guardado automático, lista de elementos
recientes, copia enriquecida, copia en bloque y plena compatibilidad para escribir flujos
de trabajo de scripts de Windows PowerShell. Para más información, consulte
about_Windows_PowerShell_ISE.

Compatibilidad con Microsoft .NET Framework 4


Windows PowerShell se basa en Common Language Runtime 4.0. Los autores de
cmdlets, scripts y flujos de trabajo pueden usar las nuevas clases de Microsoft .NET
Framework 4 en Windows PowerShell, con características como compatibilidad e
implementación de aplicaciones, Managed Extensibility Framework, informática en
paralelo, redes, Windows Communication Foundation y Windows Workflow Foundation.
Compatibilidad con el Entorno de preinstalación de
Windows
Windows PowerShell 3.0 es un componente opcional del Entorno de preinstalación de
Windows (Windows PE) 4.0 para Windows 8. Windows PE es un sistema operativo
mínimo que inicia un equipo que no tiene ningún sistema operativo y lo prepara para
instalar Windows. Windows PE se puede usar para particionar y formatear discos duros,
copiar imágenes de disco en un equipo e iniciar el programa de instalación de Windows
desde un recurso compartido de red. Windows PowerShell 3.0, a su vez, se puede usar
en Windows PE para administrar la implementación, los diagnósticos y los escenarios de
recuperación.

Sesiones desconectadas
A partir de Windows PowerShell 3.0, las sesiones persistentes administradas por el
usuario ("PSSessions") que se creen con el cmdlet New-PSSession se guardan en el
equipo remoto. Ya no son dependientes de la sesión en la que se han creado.

Ahora puede desconectarse de una sesión sin interrumpir los comandos que se ejecutan
en ella. Puede cerrar la sesión y apagar el equipo. Más adelante, puede volver a
conectarse a la sesión desde una sesión diferente en el mismo equipo o en otro
diferente.

El parámetro ComputerName del cmdlet Get-PSSession obtiene ahora todas las


sesiones del usuario que se conectan al equipo, aunque se hayan iniciado en una sesión
diferente en otro equipo. Puede conectarse a las sesiones, obtener los resultados de
comandos, iniciar nuevos comandos y, tras ello, desconectarse de la sesión.

Se han incorporado nuevos cmdlets para admitir la característica de sesiones


desconectadas, como Disconnect-PSSession , Connect-PSSession y Receive-PSSession , y
se han agregado nuevos parámetros a los cmdlets para administrar PSSessions, como el
parámetro InDisconnectedSession del cmdlet Invoke-Command .

La característica de sesiones desconectadas es posible únicamente cuando los equipos


en los extremos tanto de origen ("cliente") como de finalización ("servidor") de la
conexión ejecutan Windows PowerShell 3.0.

Conectividad de sesiones sólida


Windows PowerShell 3.0 detecta pérdidas inesperadas de conectividad entre el cliente y
el servidor e intenta restablecerla y reanudar la ejecución automáticamente. Si no se
puede restablecer la conexión cliente-servidor en el tiempo asignado, se notifica al
usuario y la sesión se desconecta. Durante el intento de reconexión, Windows
PowerShell ofrece información continuamente al usuario.

Si la sesión desconectada se inició con InvokeCommand, Windows PowerShell crea un


trabajo relativo a la sesión desconectada para que sea más fácil volver a conectarse y
reanudar la ejecución.

Estas características proporcionan una experiencia de comunicación remota más


confiable y recuperable y, asimismo, permiten a los usuarios realizar tareas de larga
ejecución que requieren sesiones sólidas, como los flujos de trabajo.

Sistema de ayuda actualizable


Ahora puede descargar archivos de ayuda actualizados correspondientes a los cmdlets
de sus módulos. El cmdlet Update-Help identifica los archivos de ayuda más recientes,
los descarga de Internet, los desempaqueta y valida y, por último, los instala en el
directorio específico del idioma pertinente del módulo.

Para usar los archivos de ayuda actualizados, basta con escribir Get-Help . No es
necesario reiniciar Windows ni Windows PowerShell. Para actualizar la ayuda de los
módulos en el directorio $pshome, inicie Windows PowerShell con la opción "Ejecutar
como administrador".

Para admitir usuarios que no tienen acceso a Internet y usuarios detrás de firewalls, el
nuevo cmdlet Save-Help descarga los archivos de ayuda en un directorio del sistema de
archivos, como un recurso compartido de archivos. De este modo, los usuarios pueden
usar el cmdlet Update-Help para obtener archivos de ayuda actualizados del recurso
compartido de archivos.

El cmdlet Update-Help se puede usar para actualizar los archivos de ayuda de todos los
módulos (o solo de algunos en particular) en todos los idiomas de la interfaz de usuario
compatibles. También puede incluir un comando Update-Help en su perfil de Windows
PowerShell. De manera predeterminada, Windows PowerShell descarga los archivos de
ayuda de un módulo no más de una vez al día.

Los módulos de Windows 8 y Windows Server 2012 no incluyen archivos de ayuda. Para
descargar los archivos de ayuda más recientes, escriba Update-Help . Para más
información, escriba Get-Help (sin parámetros) o consulte about_Updatable_Help.

Si los archivos de ayuda de un cmdlet no están instalados en el equipo, el cmdlet Get-


Help muestra ahora ayuda generada automáticamente. La ayuda generada
automáticamente incluye la sintaxis y las instrucciones de los comandos para usar el
cmdlet Update-Help para descargar archivos de ayuda.

Cualquier autor de módulos puede incluir compatibilidad con la ayuda actualizable en


su módulo. Puede incluir archivos de ayuda en el módulo y usar la ayuda actualizable
para actualizarlos u omitir los archivos de ayuda y usar la ayuda actualizable para
instalarlos. Para más información sobre cómo admitir la ayuda actualizable, consulte
Compatibilidad con la ayuda actualizable.

Mejor ayuda en línea


La ayuda en línea de Windows PowerShell es un recurso valioso para todos los usuarios,
pero es especialmente importante para los usuarios que no han instalado o no pueden
instalar archivos de ayuda actualizados.

Para ayuda en línea sobre cualquier cmdlet de Windows PowerShell, escriba:

Get-Help <cmdlet-name> -Online

Windows PowerShell abrirá la versión en línea de un tema de Ayuda en el explorador de


Internet predeterminado.

Ahora, la característica Get-Help -Online de Windows PowerShell 3.0 es todavía más


eficaz, puesto que funciona incluso cuando los archivos de ayuda del cmdlet no están
instalados en el equipo. La característica Get-Help -Online obtiene el URI del tema de
ayuda en línea de la propiedad HelpUri de los cmdlets y las funciones avanzadas.

PS C:\>(Get-Command Get-ScheduledJob).HelpUri
https://go.microsoft.com/fwlink/?LinkID=223923

A partir de Windows PowerShell 3.0, los autores de cmdlets de C# pueden rellenar la


propiedad HelpUri si crean un atributo HelpUri en la clase del cmdlet. Los autores de
funciones avanzadas pueden definir una propiedad HelpUri en el atributo
CmdletBinding. El valor de la propiedad HelpUri debe empezar por "http" o "https".

También puede incluir un valor de HelpUri en el primer vínculo relacionado de un


archivo de ayuda de cmdlet basado en XML o la directiva .Link de la ayuda basada en
comentarios de una función.
Para más información sobre cómo admitir la ayuda en línea, consulte Supporting Online
Help (Compatibilidad con la ayuda en línea).

Integración de CIM
Windows PowerShell 3.0 incluye compatibilidad con el Modelo de información común
(CIM), el que proporciona definiciones comunes de información de administración de
sistemas, redes, aplicaciones y servicios, lo que permite intercambiar información de
administración entre sistemas heterogéneos. La compatibilidad con CIM de Windows
PowerShell 3.0 incluye la posibilidad de crear cmdlets de Windows PowerShell basados
en clases de CIM nuevas o existentes, comandos basados en archivos XML de definición
de cmdlet, compatibilidad con la API de .NET de CIM. CIM, cmdlets de administración de
CIM y proveedores de WMI 2.0.

Archivos de configuración de sesión


A partir de Windows PowerShell 3.0, puede diseñar una configuración de sesión
personalizada con un archivo. Este nuevo archivo de configuración de sesión permite
definir el entorno de sesiones en el que se usa la configuración de sesión, incluido los
módulos, scripts y archivos de formato que se cargan en las sesiones, los cmdlets y
elementos de lenguaje que pueden usar los usuarios, los módulos y scripts que pueden
ejecutar y las variables que pueden ver.

Se puede diseñar una sesión en la que los usuarios solo pueden ejecutar los cmdlets de
un determinado módulo, o una sesión en la que los usuarios tienen acceso completo a
todos los módulos y acceso a scripts que realizan tareas avanzadas.

En versiones anteriores de Windows PowerShell, un control a este nivel solo lo poseían


aquellos que podían escribir un programa de C# o un script de inicio complejo. Ahora,
cualquier miembro del grupo Administradores del equipo puede personalizar una
configuración de sesión con un archivo de configuración.

Para crear un archivo de configuración de sesión, use el cmdlet New-


PSSessionConfigurationFile . Para aplicar el archivo de configuración de sesión a una

configuración de sesión, use los cmdlets Register-PSSessionConfiguration o "Set-


PSSessionConfiguration".

Para más información, consulte about_Session_Configuration_Files y New-


PSSessionConfigurationFile .
Integración de trabajos programados y del programador
de tareas
Ahora se pueden programar trabajos en segundo plano de Windows PowerShell y
administrarlos en Windows PowerShell y en el Programador de tareas.

Los trabajos programados de Windows PowerShell consisten en una mezcla muy


práctica de trabajos en segundo plano de Windows PowerShell y tareas del
Programador de tareas.

Como sucede con los trabajos en segundo plano de Windows PowerShell, los trabajos
programados se ejecutan de forma asincrónica en segundo plano. Las instancias de
trabajos programados que se han completado se pueden administrar con cmdlets de
trabajo, como Start-Job y Get-Job .

Al igual que las tareas del Programador de tareas, los trabajos programados se pueden
ejecutar según una programación periódica o puntual, o en respuesta a una acción o
evento. Los trabajos programados se pueden ver y administrar en el Programador de
tareas, habilitar y deshabilitar según sea necesario y ejecutar o usar como plantillas.
También se pueden definir las condiciones en las que los trabajos de inician.

Además, los trabajos programados vienen con un conjunto personalizado de cmdlets


para administrarlos. Los cmdlets permiten crear, editar, administrar, deshabilitar y volver
a habilitar trabajos programados, crear desencadenadores de trabajos programados y
establecer opciones de trabajo programado.

Para más información sobre los trabajos programados, consulte about_Scheduled_Jobs.

Mejoras en el lenguaje de Windows PowerShell


Windows PowerShell 3.0 incluye muchas características destinadas a hacer que su
lenguaje sea más sencillo y más fácil de usar, así como evita errores comunes. Entre
estas mejoras están la enumeración de propiedades, las propiedades de recuento y
longitud en objetos escalares, nuevos operadores de redirección, el modificador de
ámbito $Using, la variable automática PSItem, un formato de scripts flexible, atributos
de variables, argumentos de atributos simplificados, nombres de comandos numéricos,
el operador Stop-Parsing, una mejor expansión de matriz, nuevos operadores de bits,
diccionarios ordenados, conversión de PSCustomObject y una ayuda mejor basada en
comentarios.

Nuevos cmdlets principales


Se han agregado nuevos cmdlets a la instalación principal de Windows PowerShell,
incluidos cmdlets para administrar trabajos programados, sesiones desconectadas, la
integración de CIM y el sistema de ayuda actualizable.

CimCmdlets
Get-CimAssociatedInstance
Get-CimClass
Get-CimInstance
Get-CimSession
Invoke-CimMethod
New-CimInstance
New-CimSession
New-CimSessionOption
Register-CimIndicationEvent
Remove-CimInstance
Remove-CimSession
Set-CimInstance
Microsoft.PowerShell.Core
Connect-PSSession
Disconnect-PSSession
New-PSSessionConfigurationFile
New-PSTransportOption
Receive-PSSession
Resume-Job
Save-Help
Suspend-Job
Test-PSSessionConfigurationFile
Update-Help
Microsoft.PowerShell.Diagnostics
New-WinEvent
Microsoft.PowerShell.Management
Get-ControlPanelItem
Rename-Computer
Show-ControlPanelItem
Microsoft.PowerShell.Utility
ConvertFrom-Json
ConvertTo-Json
Get-TypeData
Invoke-RestMethod
Invoke-WebRequest
Remove-TypeData
Show-Command
Unblock-File
PSScheduledJob
Add-JobTrigger
Disable-JobTrigger
Disable-ScheduledJob
Enable-JobTrigger
Enable-ScheduledJob
Get-JobTrigger
Get-ScheduledJob
Get-ScheduledJobOption
New-JobTrigger
New-ScheduledJobOption
Register-ScheduledJob
Set-JobTrigger
Set-ScheduledJob
Set-ScheduledJobOption
Unregister-ScheduledJob
PSWorkflow
New-PSWorkflowExecutionOption
New-PSWorkflowSession
PSWorkflowUtility
Invoke-AsWorkflow
ISE
Get-IseSnippet
Import-IseSnippet
New-IseSnippet

Mejoras en los proveedores y cmdlets principales


existentes
Windows PowerShell 3.0 incluye nuevas características para los cmdlets existentes, como
una sintaxis simplificada y nuevos parámetros para los siguientes cmdlets: Cmdlets del
equipo, cmdlets de CSV, Get-ChildItem, Get-Command, Get-Content, Get-History,
Measure-Object, cmdlets de seguridad, Select-Object, Select-String, Split-Path, Start-
Process, Tee-Object, Test-Connection, Add-Member y cmdlets de WMI.

Los proveedores de Windows PowerShell también se han mejorado considerablemente,


incluida la posibilidad del proveedor de certificados de administrar certificados de Capa
de sockets seguros (SSL) para el hospedaje web, la compatibilidad con credenciales,
unidades de red persistentes y flujos de datos alternativos en las unidades del sistema
de archivos.

Detección e importación de módulos remotos


Windows PowerShell 3.0 amplía las funcionalidades de detección de módulos,
importación y comunicación remota implícita en los equipos remotos. Los cmdlets de
módulo obtienen los módulos de equipos remotos y los importa al equipo local o
remoto usando la comunicación remota de Windows PowerShell. La nueva
compatibilidad con sesiones CIM permite usar CIM y WMI para administrar equipos sin
Windows importando al equipo local comandos que se ejecutan de forma implícita en el
equipo remoto.

Para más información, consulte los temas de ayuda de los cmdlets Get-Module y Import-
Module .

Mejor finalización con tabulación


Ahora, la finalización con tabulación en la consola de Windows PowerShell completa los
nombres de los cmdlets, parámetros, valores de parámetro, enumeraciones, tipos de
.NET Framework, objetos COM, directorios ocultos y muchos otros elementos. La
característica de finalización con tabulación se ha reescrito completamente según un
analizador y árbol de sintaxis abstracta nuevos para dar cabida a más escenarios,
incluidos los árboles de análisis en memoria y la finalización con tabulación de línea
media.

Carga automática de módulos


Ahora, el cmdlet Get-Command obtiene todas las funciones y cmdlets de todos los
módulos instalados en el equipo, aun cuando el módulo no se haya importado en la
sesión actual.

Cuando obtenga el cmdlet que necesita, puede usarlo inmediatamente sin importar
módulos. Ahora, los módulos de Windows PowerShell se importan automáticamente
cuando se usa un cmdlet en el módulo. Por lo tanto, ya no es necesario buscar el
módulo e importarlo para usar sus cmdlets.

La importación automática de módulos se desencadena con el uso del cmdlet en un


comando, la ejecución de Get-Command para un cmdlet sin caracteres comodín o la
ejecución de Get-Help para un cmdlet sin caracteres comodín.
Para habilitar, deshabilitar y configurar la importación automática de módulos, use la
variable de preferencia $PSModuleAutoLoadingPreference.

Para más información, consulte about_Modules, about_Preference_Variables y los temas


de ayuda de los cmdlets Get-Command y Import-Module .

Mejoras en la experiencia de módulo


Windows PowerShell 3.0 incorpora compatibilidad de características avanzadas en los
módulos, incluidas las siguientes características nuevas:

1. Registro de módulos para módulos individuales (LogPipelineExecutionDetails) y la


nueva configuración de directiva de grupo "Activar registro de módulos".
2. Objetos de módulo extendidos que exponen los valores del manifiesto del
módulo.
3. Nueva propiedad ExportedCommands de los módulos (incluidos los módulos
anidados), que combina comandos de todos los tipos.
4. Mejor detección de los módulos (no importados) disponibles, incluido permitir los
parámetros Path y ListAvailable en el mismo comando.
5. Nueva clave DefaultCommandPrefix en los manifiestos del módulo, que evita
conflictos de nombres sin tener que cambiar el código del módulo.
6. Mejora de los requisitos de módulo, incluidos los módulos necesarios completos
con la versión y el GUID y la importación automática de los módulos necesarios.
7. Funcionamiento más silencioso y simplificado del cmdlet New-ModuleManifest .
8. Nuevo parámetro Module para #Requires
9. Cmdlet Import-Module mejorado con los parámetros MinimumVersion y
RequiredVersion.

Detección de comandos simplificada


Ya no necesitará importar todos los módulos para detectar los comandos disponibles en
la sesión. En Windows PowerShell 3.0, el cmdlet Get-Command obtiene todos los
comandos de todos los módulos instalados. Además, si usa un comando, el módulo que
exporta el comando se importa automáticamente en la sesión.

El nuevo cmdlet Show-Command está diseñado específicamente para principiantes. Puede


buscar comandos en una ventana. Puede ver todos los comandos o filtrar por módulo,
importar un módulo haciendo clic en un botón o usar cuadros de texto y listas
desplegables para construir un comando válido y, a continuación, copiarlo o ejecutarlo
sin salir de la ventana.
Mejor compatibilidad con registros, diagnósticos y
directiva de grupo
Windows PowerShell 3.0 mejora la compatibilidad del registro y seguimiento de
comandos y módulos al admitir registros de Seguimiento de eventos para Windows
(ETW), una propiedad LogPipelineExecutionDetails editable de los módulos y la
configuración de la directiva de grupo "Activar registro de módulos". Ahora puede
obtener valores de parámetro de los detalles de registro mostrando las propiedades del
registro.

Mejoras de formato y salida


Las nuevas mejoras de formato y salida disparan la eficacia de todos los usuarios de
Windows PowerShell. Estas mejoras incluyen la redirección de salida de todas las
secuencias, un cmdlet Update-Type mejorado que agrega tipos dinámicamente sin
archivos Format.ps1xml, ajuste de líneas en la salida, propiedades de formato
predeterminado de objetos personalizados, el tipo PSCustomObject, un mejor formato
de los objetos WMI y objetos heterogéneos y compatibilidad para detectar sobrecargas
de método.

Mejor experiencia de host de consola


El programa host de la consola de Windows PowerShell presenta nuevas características
en Windows PowerShell 3.0, como el contenedor uniproceso, de manera
predeterminada. La nueva opción "Ejecutar con PowerShell" en el Explorador de archivos
permite ejecutar scripts en una sesión sin restricciones, simplemente haciendo clic con
el botón secundario. La nueva lógica de inicio del host de consola inicia Windows
PowerShell con mayor rapidez, mientras que las nuevas fuentes permiten personalizar la
experiencia de ventana de consola ya conocida.

Nuevas API de cmdlets y de hospedaje


Las nuevas API de cmdlet y API de hospedaje incluyen API públicas de árbol de sintaxis
avanzada (AST) y API para la paginación de canalizaciones, canalizaciones anidadas,
finalización con tabulación de grupos de espacio de ejecución, Windows RT, el atributo
de cmdlet Obsolete y las propiedades Verb y Noun del objeto FunctionInfo.

Mejoras de rendimiento
Las notables mejoras de rendimiento de Windows PowerShell se deben al nuevo
analizador de lenguaje, que se basa en Dynamic Runtime Language (DLR) de .NET
Framework 4, además de a la compilación de scripts en tiempo de ejecución, a mejoras
en la confiabilidad del motor y a los cambios en el algoritmo de Get-ChildItem que
mejoran su rendimiento, especialmente al buscar recursos compartidos de red.

Compatibilidad con RunAs y host compartido


Windows PowerShell 3.0 incluye compatibilidad con las características RunAs y de host
compartido.

La característica RunAs, diseñada para el flujo de trabajo de Windows PowerShell,


permite a los usuarios de una configuración de sesión crear sesiones que se ejecutan
con el permiso de una cuenta de usuario compartida. Esto permite a los usuarios con
menos privilegios ejecutar determinados comandos y scripts con permisos de
administrador, al tiempo que reduce la necesidad de agregar usuarios con menos
experiencia al grupo Administradores.

La característica SharedHost permite que varios usuarios en diferentes equipos puedan


conectarse a una sesión de flujo de trabajo simultáneamente y supervisar el progreso de
un flujo de trabajo. Los usuarios pueden iniciar un flujo de trabajo en un equipo y
después conectarse a la sesión de flujo de trabajo en otro equipo sin desconectar la
sesión desde el equipo original. Los usuarios deben tener los mismos permisos y usar la
misma configuración de sesión. Para más información, consulte "Ejecutar un flujo de
trabajo de Windows PowerShell" en Introducción al flujo de trabajo de
Windows PowerShell.

Mejoras en el tratamiento de caracteres especiales


A fin de mejorar la capacidad de Windows PowerShell 3.0 de interpretar y tratar
correctamente los caracteres especiales, el parámetro LiteralPath (que trata los
caracteres especiales en las rutas de acceso) es válido en prácticamente todos los
cmdlets que tengan el parámetro Path, como los nuevos cmdlets Update-Help y Save-
Help . El analizador incluye también una lógica especial para mejorar el tratamiento del
carácter de acento grave ( ` ) y los corchetes en los nombres y rutas de acceso de
archivo.

Consulte también
about_Windows_PowerShell_5.0
Windows PowerShell
Novedades de Windows PowerShell 5.0
ISE
Artículo • 21/03/2023

En este artículo se explican las características nuevas y actualizadas que se introdujeron


en la versión 5.0 del Entorno de scripting integrado (ISE) de Windows PowerShell.

7 Nota

PowerShell ISE ya no se incluye en el desarrollo activo de características. Como


componente que se envía con Windows, sigue siendo compatible oficialmente con
las correcciones de servicios de seguridad y alta prioridad. Aunque actualmente no
está previsto quitar el ISE de Windows,

no existe ninguna compatibilidad con él a partir de PowerShell v6. Los usuarios que
quieran reemplazar el ISE deben usar Visual Studio Code con la extensión de
PowerShell .

Descripción de la característica
Windows PowerShell ISE es una aplicación host que permite escribir, ejecutar y probar
scripts y módulos en un entorno gráfico e intuitivo. Las características principales, como
el coloreado de la sintaxis, el procedimiento para completar con el tabulador, la
depuración visual, la compatibilidad con Unicode y la Ayuda contextual, proporcionan
una rica experiencia de scripting.

Para obtener más información, consulte Introducción a Windows PowerShell ISE.

En la tabla siguiente se enumeran las características nuevas y modificadas de esta


versión de Windows PowerShell ISE en Windows PowerShell.

IntelliSense
Agregado en ISE 3.0

IntelliSense es una característica de asistencia de finalización automática que forma


parte de Windows PowerShell ISE. Intellisense muestra menús en los que se pueden
hacer clic de los cmdlets, parámetros, valores de parámetros, archivos o carpetas
potencialmente coincidentes a medida que escribe.

¿Qué valor aporta este cambio?

Con la adición de IntelliSense, es más fácil detectar cmdlets y la sintaxis cuando se usa
Windows PowerShell ISE para crear scripts. También puede usar Windows PowerShell ISE
para obtener información sobre Windows PowerShell al crear nuevos scripts.

¿Qué funciona de manera diferente?

Si escribe cmdlets en Windows PowerShell ISE, se muestra un menú desplazable en el


que puede realizar sus selecciones, que permite examinar y seleccionar los comandos
adecuados.

Fragmentos de código
Agregado en ISE 3.0

Los fragmentos de código son secciones de código de Windows PowerShell breves que
puede insertar fácilmente en los scripts que crea en Windows PowerShell ISE. Windows
PowerShell ISE incluye un conjunto predeterminado de fragmentos de código. Los
fragmentos de código se pueden agregar mediante el cmdlet New-Snippet mientras se
trabaja en Windows PowerShell ISE.

¿Qué valor aporta este cambio?

El uso de fragmentos de código permite ensamblar y crear rápidamente scripts para


automatizar el entorno.

¿Qué funciona de manera diferente?

Para usar fragmentos de código en Windows PowerShell 3.0, o cualquier versión


posterior, en el menú Edición, haga clic en Iniciar fragmentos de código o presione
Ctrl + J .

Herramientas de complemento
Agregado en PowerShell 3.0

Windows PowerShell ISE ahora admite herramientas de complemento mediante el


modelo de objetos. Estos complementos son controles de Windows Presentation
Foundation (WPF) que se muestran como un panel vertical u horizontal en la consola. Si
hay varias herramientas de complemento en un panel, se mostrarán como un control de
pestaña. También puede agregar o quitar herramientas de complemento no producidas
por Microsoft. Para obtener más información, consulte Finalidad del modelo de objetos
de scripting de Windows PowerShell ISE.

¿Qué valor aporta este cambio?

Los complementos permiten ampliar y personalizar Windows PowerShell ISE con


herramientas que agregan funcionalidad y mejoran su experiencia de scripting.

¿Qué funciona de manera diferente?

Windows PowerShell ISE 3.0 y versiones posteriores incluyen el complemento


Commands. El complemento Commands permite examinar cmdlets y acceder a la
ayuda sobre los cmdlets en paralelo con los paneles de scripts y de consola.

Puede encontrar complementos adicionales mediante el comando Abrir sitio web de


herramientas de complemento del menú Complementos.

Administrador de reinicio y Autoguardar


Agregado en PowerShell 3.0

Windows PowerShell ISE ahora guarda automáticamente los scripts abiertos cada dos
minutos en una ubicación aparte. Al reiniciarse Windows PowerShell ISE tras un bloqueo
o reinicio inesperado, recupera scripts que se abrieron en la última sesión, incluso si
estos no se guardaron.

Para cambiar el intervalo de guardado automático, ejecute el siguiente comando en el


panel de consola: $psise.Options.AutoSaveMinuteInterval .

¿Qué valor aporta este cambio?

Ahora puede trabajar en Windows PowerShell ISE con la tranquilidad de saber que los
scripts abiertos se guardan automáticamente.

¿Qué funciona de manera diferente?

Windows PowerShell ISE 2.0 no guarda los scripts automáticamente.

Lista Usados más recientemente


Agregado en PowerShell 3.0

Windows PowerShell ISE tiene ahora una lista Usados más recientemente para los
archivos. Cuando se abre un archivo en Windows PowerShell ISE, este se agrega a la lista
Usados más recientemente en el menú Archivo.

Para cambiar el número predeterminado de archivos en la lista Usados más


recientemente, ejecute el siguiente comando en el panel de consola:
$psise.Options.MruCount .

¿Qué valor aporta este cambio?

Ahora puede usar la lista Usados más recientemente para acceder fácilmente a los
archivos que usa con frecuencia.

¿Qué funciona de manera diferente?

Windows PowerShell ISE 2.0 no tiene una lista Usados más recientemente.

Panel de consola
Agregado en PowerShell 3.0

Los paneles de comandos y de salida separados que estaban disponibles en la primera


versión de Windows PowerShell ISE se combinaron en un solo panel de consola. El panel
de consola es similar en funciones y apariencia a una consola típica de Windows
PowerShell, pero incluye las siguientes mejoras:

El color de la sintaxis del texto de entrada (no texto de salida), incluida la sintaxis
XML
IntelliSense
Coincidencia de llaves
Indicación de errores
Compatibilidad total con Unicode
F1 : ayuda contextual
Ctrl + F1 : cmdlet Show-Command contextual
Compatibilidad con scripts complejos y de derecha a izquierda
Compatibilidad con fuentes
Zoom
Modos de selección de líneas y bloques
Conservación del contenido escrito en la línea de comandos cuando presiona la
Flecha arriba para ver el historial en la consola
¿Qué valor aporta este cambio?

La adición de estos cambios del panel de consola proporciona una experiencia de


scripting más coherente con la interfaz de la consola.

¿Qué funciona de manera diferente?

Windows PowerShell ISE 2.0 presenta paneles de comandos y de salida independientes.

Modificadores de línea de comandos


Agregado en PowerShell 3.0

Si inicia Windows PowerShell ISE desde la línea de comandos (escribiendo


Powershell_ise.exe), puede agregar los siguientes modificadores de línea de comandos
nuevos.

-NoProfile : inicia Windows PowerShell ISE sin ejecutar $profile

-Help : muestra una ventana de Ayuda


-mta : inicia Windows PowerShell ISE en modo de contenedor multiproceso. El

modo de operación predeterminado de Windows PowerShell ISE es el modo de


contenedor uniproceso o -sta .

¿Qué valor aporta este cambio?

La adición de estos modificadores de línea de comandos permite controlar el entorno


en el que se ejecuta Windows PowerShell ISE.

¿Qué funciona de manera diferente?

Windows PowerShell ISE 2.0 no reconoce estos modificadores de línea de comandos.

Nuevas características del editor


Agregado en PowerShell 3.0

Otras características de edición de Windows PowerShell ISE son:

Color de la sintaxis XML: Windows PowerShell ISE ahora colorea la sintaxis XML de
la misma manera que la sintaxis de Windows PowerShell.
Coincidencia de llaves: Windows PowerShell ISE incluye la coincidencia de llaves y
el resaltado, y se pueden usar de las siguientes maneras: por ejemplo, con el
comando Ir a Igualar o Ctrl + ] se localiza la llave de cierre, si hay alguna llave de
apertura seleccionada.
Vista Esquema: el panel de scripts admite la esquematización, que permite
expandir y contraer secciones de código al hacer clic en los signos más o menos
en el margen izquierdo. Puede usar llaves o las etiquetas #region y #endregion
para marcar el inicio o el final de una sección contraíble. Para expandir o contraer
todas las regiones, presione Ctrl + M .
Edición de texto con arrastrar y colocar: Windows PowerShell ISE permite ahora la
edición de texto con arrastrar y colocar. Puede seleccionar cualquier bloque de
texto y arrastrar el texto a otra ubicación en el editor o la consola para mover el
texto. Si mantiene presionada la tecla Ctrl mientras arrastra el texto seleccionado,
al soltar el botón del mouse, el texto se copiará en la nueva ubicación. En esta
versión de Windows PowerShell ISE, al arrastrar y colocar archivos en Windows
PowerShell ISE, el archivo se abrirá.
Presentación de errores de análisis: los errores de análisis se indican con un
subrayado rojo. Cuando desplaza el cursor sobre un error indicado, el texto de
información sobre herramientas muestra el problema que se encontró en el
código.
Zoom: el porcentaje de zoom del contenido de la consola puede establecerse
mediante el control deslizante del zoom (en la esquina inferior derecha de la
ventana de Windows PowerShell ISE) o escribiendo el comando
$psise.options.Zoom en el panel de consola.

Copiar y pegar texto enriquecido: la copia en el Portapapeles de Windows


PowerShell ISE conserva la información de fuente, tamaño y color de la selección
original.
Selección de bloques: para seleccionar un bloque de texto puede mantener
presionada la tecla ALT y seleccionar texto en el panel de scripts con el mouse, o
bien presionar Alt + Mayús + Flecha .

¿Qué valor aporta este cambio?

Las características de edición adicionales proporcionan un entorno de edición más


coherente y eficaz.

¿Qué funciona de manera diferente?

Estas mejoras de edición no estaban presentes en Windows PowerShell ISE 2.0.

Ventana del nuevo visor de Ayuda


Agregado en PowerShell 3.0
Si presiona F1 cuando el cursor está en un cmdlet, o si tiene parte de un cmdlet
resaltado, el nuevo visor de Ayuda abre la ayuda contextual sobre el cmdlet resaltado.
Para ver la Ayuda acerca de Windows PowerShell, escriba operators en el panel de
consola y, después, presione F1 .

Antes de usar esta característica, descargue la versión más actual de los temas de Ayuda
de Windows PowerShell desde el sitio web de Microsoft. El método más sencillo para la
descarga de los temas de la Ayuda es ejecutar el cmdlet Update-Help en el panel de
consola al ejecutar Windows PowerShell ISE como administrador.

Puede modificar donde busca ayuda la tecla F1 . En el menú Herramientas/Opciones,


en la pestaña Configuración general, debajo de Otra configuración, puede activar o
desactivar la casilla Usar Ayuda local en lugar de contenido en línea. Al activarla, el
cliente busca la Ayuda del cmdlet en la Ayuda descargada en la carpeta de módulos. Si
la casilla está desactivada, el cliente busca ayuda en línea.

¿Qué valor aporta este cambio?

La ayuda contextual sin salir del cmdlet o script actual proporciona una experiencia de
aprendizaje integrada.

¿Qué funciona de manera diferente?

Al presionar F1 en versiones anteriores de Windows PowerShell ISE, se abría el archivo


de Ayuda en el equipo local. En Windows PowerShell ISE 3.0 y versiones posteriores, se
abre una ventana que contiene la Ayuda del cmdlet, que es configurable y permite
realizar búsquedas. Esta experiencia de la Ayuda es una novedad de Windows
PowerShell ISE 3.0 y la ayuda actualizable es una novedad de Windows PowerShell 3.0.

Cmdlet Show-Command
Agregado en PowerShell 3.0

El cmdlet Show-Command permite componer o ejecutar un cmdlet o una función


rellenando un formulario gráfico. El formato permite a los usuarios trabajar con
Windows PowerShell en un entorno gráfico. Show-Command también permite a los
generadores de scripts avanzados crear una GUI rápida basada en Windows PowerShell.

¿Qué valor aporta este cambio?

Si usa Show-Command en sus scripts de Windows PowerShell, puede proporcionar a los


usuarios el entorno gráfico con el que están familiarizados. Show-Command también
puede ayudar a los nuevos usuarios a aprender Windows PowerShell.

¿Qué funciona de manera diferente?

Show-Command es el nuevo Windows PowerShell ISE 3.0.

Consulte también
Para obtener más información sobre cómo usar Windows PowerShell ISE, consulte
Exploración del Entorno de scripting integrado de Windows PowerShell.
Windows PowerShell ISE
Artículo • 21/03/2023

Windows PowerShell Integrated Scripting Environment (ISE) es una aplicación host de


Windows PowerShell. En el ISE, puede ejecutar comandos y escribir, probar y depurar
scripts en una única interfaz gráfica de usuario basada en Windows. El ISE proporciona
edición de varias líneas, finalización con tabulación, color de sintaxis, ejecución selectiva,
ayuda contextual y compatibilidad con idiomas de derecha a izquierda. Los elementos
de menú y métodos abreviados de teclado se asignan a muchas de las mismas tareas
que realizaría en la consola de Windows PowerShell. Por ejemplo, al depurar un script en
el ISE, puede hacer clic con el botón derecho en una línea de código del panel de
edición para establecer un punto de interrupción.

Soporte técnico
El ISE se introdujo por primera vez con Windows PowerShell V2 y se rediseñó con
PowerShell V3. El ISE se admite en todas las versiones compatibles de Windows
PowerShell hasta Windows PowerShell V5.1 (inclusive).

7 Nota

PowerShell ISE ya no se incluye en el desarrollo activo de características. Como


componente que se envía con Windows, sigue siendo compatible oficialmente con
las correcciones de servicios de seguridad y alta prioridad. Aunque actualmente no
está previsto quitar el ISE de Windows,

no existe ninguna compatibilidad con él a partir de PowerShell v6. Los usuarios que
quieran reemplazar el ISE deben usar Visual Studio Code con la extensión de
PowerShell .

Principales características
Entre las principales características de Windows PowerShell ISE están las siguientes:

Edición de varias líneas: para insertar una línea en blanco debajo de la línea actual
en el panel de comandos, presione MAYÚS + ENTRAR .
Ejecución selectiva: para ejecutar parte de un script, seleccione el texto que quiera
ejecutar y, a continuación, haga clic en el botón Ejecutar script. También puede
presionar F5 .
Ayuda contextual: escriba Invoke-Item y, luego, presione F1 . El archivo de ayuda
se abre en el artículo correspondiente al cmdlet Invoke-Item .

Windows PowerShell ISE permite personalizar algunos aspectos de su apariencia.


También tiene su propio script de perfil de Windows PowerShell.

Para iniciar Windows PowerShell ISE


Haga clic en Inicio, seleccione Windows PowerShell y, después, haga clic en Windows
PowerShell ISE. Como alternativa, puede escribir powershell_ise.exe en cualquier shell
de comandos o en el cuadro Ejecutar.

Para obtener ayuda de Windows PowerShell ISE


En el menú Ayuda, haga clic en Ayuda de Windows PowerShell. También puede
presionar F1 . El archivo que se abre contiene información detallada sobre Windows
PowerShell ISE y Windows PowerShell, además de toda la ayuda disponible con el
cmdlet Get-Help .
Explorar Windows PowerShell ISE
Artículo • 04/05/2023

Puede usar el Entorno de scripting integrado (ISE) de Windows PowerShell para crear,
ejecutar y depurar scripts y comandos.

Windows PowerShell ISE consta de la barra de menús, las pestañas de Windows


PowerShell, la barra de herramientas, las pestañas de script, un panel de scripts, un
panel de consola, una barra de estado, un control deslizante de tamaño de texto y la
ayuda contextual.

Barra de menús
La barra de menús contiene los menús Archivo, Edición, Ver, Herramientas, Depurar,
Complementos y Ayuda.

Los botones de los menús permiten realizar tareas relacionadas con la escritura y
ejecución de scripts y la ejecución de comandos en Windows PowerShell ISE. Además, se
puede colocar una herramienta de complemento en la barra de menús mediante la
ejecución de scripts que usan la jerarquía del modelo de objetos de ISE.

Barra de herramientas

Los botones siguientes están ubicados en la barra de herramientas.

Botón Función

Nuevo Abre un nuevo script.

Abrir Abre un script o un archivo existente.

Guardar Guarda un script o un archivo.

Cortar Corta el texto seleccionado y lo copia en el Portapapeles.

Copy Copia el texto seleccionado en el portapapeles.

Pegar Pega el contenido del Portapapeles en la ubicación del cursor.

Borrar el panel Borra todo el contenido del panel de la consola.


de la consola

Deshacer Invierte la acción que se acaba de realizar.

Rehacer Realiza la acción que se acaba de deshacer.

Ejecutar script Ejecuta un script.

Ejecutar Ejecuta una parte seleccionada de un script.


selección

Detener Detiene un script que se está ejecutando.


operación

Nueva pestaña Crea una nueva pestaña de PowerShell que establece una sesión en un equipo
de PowerShell remoto. Aparece un cuadro de diálogo que le pide que escriba los detalles
en remoto necesarios para establecer la conexión remota.

Iniciar Abre una consola de PowerShell.


PowerShell.exe
Botón Función

Mostrar panel Mueve el panel de scripts a la parte superior de la pantalla.


de scripts
arriba

Mover panel Mueve el panel de scripts a la derecha de la pantalla.


de scripts a la
derecha

Mostrar panel Maximiza el panel de scripts.


de scripts
maximizado

Mostrar Muestra el panel de comandos de los módulos instalados como una ventana
ventana de independiente.
comandos

Mostrar Muestra el panel de comandos de los módulos instalados como complemento


complemento de barra lateral.
de comandos

Pestañas de Windows PowerShell

Una pestaña de Windows PowerShell es el entorno en el que se ejecuta un script de


Windows PowerShell. Puede abrir nuevas pestañas de Windows PowerShell en Windows
PowerShell ISE para crear entornos independientes en el equipo local o en equipos
remotos. Puede tener un máximo de ocho pestañas de PowerShell abiertas de forma
simultánea.

Para obtener más información, vea Cómo crear una pestaña de PowerShell en Windows
PowerShell ISE.

Pestaña Script
Muestra el nombre del script que se está editando. Puede hacer clic en una pestaña de
script para seleccionar el script que desea editar.

Cuando apunte a la pestaña de script, la ruta de acceso completa al archivo de script se


mostrará en una información sobre herramientas.

Panel de scripts

Permite crear y ejecutar scripts. Puede abrir, editar y ejecutar scripts existentes en el
panel de scripts. Para obtener más información, vea Cómo escribir y ejecutar scripts en
Windows PowerShell ISE.

Panel de consola
Muestra los resultados de los comandos y scripts que ha ejecutado. Puede ejecutar
comandos en el panel de consola. También puede copiar y borrar el contenido en el
panel de consola.

Para obtener más información, consulta los artículos siguientes:

Cómo usar el panel de consola en Windows PowerShell ISE


Cómo depurar scripts en ISE de Windows PowerShell
Cómo usar la finalización con tabulación en el panel de scripts y en el panel de
consola
Barra de estado
Permite ver si los comandos y scripts que ejecuta se han completado. La barra de estado
se encuentra en la parte inferior de la ventana. Las partes seleccionadas de los mensajes
de error se muestran en la barra de estado.

Control deslizante Tamaño del texto


Aumenta o disminuye el tamaño del texto en la pantalla.

Ayuda
La ayuda de Windows PowerShell ISE está disponible en Microsoft Learn. Para abrir la
Ayuda, haga clic en Ayuda de Windows PowerShell ISE en el menú Ayuda o presione la
tecla F1 en cualquier lugar excepto cuando el cursor esté en el nombre de un cmdlet
en el panel de scripts o en panel de consola. Desde el menú Ayuda también puede
ejecutar el cmdlet Update-Help y mostrar la ventana Comandos, que le muestra todos
los parámetros de un cmdlet para ayudarle a construir comandos, lo que permite
rellenar los parámetros en un formulario fácil de usar.

Consulte también
Presentación de Windows PowerShell ISE
Cómo usar perfiles en ISE de Windows PowerShell
Accesibilidad en ISE de Windows PowerShell
Métodos abreviados de teclado para Windows PowerShell ISE
Cómo crear una pestaña de PowerShell
en Windows PowerShell ISE
Artículo • 21/03/2023

Las pestañas del Entorno de scripting integrado de Windows PowerShell permiten crear
y usar varios entornos de ejecución simultáneamente dentro de la misma aplicación.
Cada pestaña de PowerShell corresponde a una sesión o un entorno de ejecución
independiente.

7 Nota

Las variables, las funciones y los alias que se crean en una pestaña no se mantienen
en otra. Son sesiones diferentes de Windows PowerShell.

Use los pasos siguientes para abrir o cerrar una pestaña en Windows PowerShell. Para
cambiar el nombre de una pestaña, configure la propiedad DisplayName del objeto de
scripting Tab de Windows PowerShell.

Para crear y usar una nueva pestaña de


PowerShell
En el menú Archivo, haga clic en Nueva pestaña de PowerShell. La nueva pestaña de
PowerShell se abre siempre como la ventana activa. Las pestañas de PowerShell se
numeran de forma incremental en el orden en que se abren. Cada pestaña está asociada
a su propia ventana de la consola de Windows PowerShell. Puede tener hasta 32
pestañas de PowerShell con su propia sesión abierta a la vez (este valor se limita a 8 en
Windows PowerShell ISE 2.0).

Tenga en cuenta que al hacer clic en los iconos Nuevo o Abrir de la barra de
herramientas no se crea una nueva pestaña con una sesión independiente. En su lugar,
estos botones abren un archivo de script nuevo o existente en la pestaña activa con una
sesión. Puede tener varios archivos de script abiertos con cada pestaña y cada sesión.
Las pestañas de script de una sesión solo aparecen debajo de las pestañas de la sesión
cuando la sesión asociada está activa.

Para activar una pestaña de PowerShell, haga clic en ella. Para seleccionar entre las
pestañas de PowerShell abiertas, en el menú Ver, haga clic en la pestaña de PowerShell
que quiera usar.
Para crear y usar una pestaña de PowerShell
remoto
En el menú Archivo, haga clic en Nueva pestaña de PowerShell en remoto para
establecer una sesión en un equipo remoto. Aparece un cuadro de diálogo que le pide
que escriba los detalles necesarios para establecer la conexión remota. La pestaña
remota funciona igual que una pestaña de PowerShell local, pero los comandos y los
scripts se ejecutan en el equipo remoto.

Para cerrar la pestaña de PowerShell


Para cerrar una pestaña, puede usar cualquiera de las técnicas siguientes:

Haga clic en la pestaña que quiera cerrar.

En el menú Archivo, haga clic en Cerrar pestaña de PowerShell, o bien haga clic
en el botón Cerrar (X) en una pestaña activa para cerrarla.

Si tiene archivos sin guardar abiertos en la pestaña de PowerShell que está cerrando, se
le pedirá que los guarde o los descarte. Para obtener más información acerca de cómo
guardar un script, consulte Cómo guardar un script.

Consulte también
Presentación de Windows PowerShell ISE
Cómo usar el panel de consola en Windows PowerShell ISE
Cómo depurar scripts en ISE de
Windows PowerShell
Artículo • 21/03/2023

En este artículo se describe cómo depurar scripts en un equipo local mediante las
características de depuración visual del Entorno de scripting integrado (ISE) de Windows
PowerShell.

Como administrar los puntos de interrupción


Un punto de interrupción es una zona designada en un script que desee que la
operación entre en pausa para poder examinar el estado actual de las variables y el
entorno en que se ejecuta el script. Cuando un punto de interrupción pausa un script,
puede ejecutar comandos en el panel de consola para examinar el estado del script.
Puede generar variables o ejecutar otros comandos. Incluso puede modificar el valor de
las variables que son visibles para el contexto del script que se está ejecutando. Después
de examinar lo que desea ver, puede reanudar la operación del script.

Puede establecer tres tipos de puntos de interrupción en el entorno de depuración de


Windows PowerShell:

1. Punto de interrupción de línea. El script se pausa cuando se alcanza la línea


designada durante la operación del script.

2. Punto de interrupción de variable. El script se pausa cuando cambia el valor de la


variable designada.

3. Punto de interrupción de comando. El script se pausa cada vez que el comando


designado está a punto de ejecutarse durante la operación del script. Puede incluir
parámetros para filtrar aún más el punto de interrupción solo para operación
deseada. El comando también puede ser una función que ha creado.

De estos, en el entorno de depuración Windows PowerShell ISE, solo se pueden


establecer puntos de interrupción de línea usando el menú o los métodos abreviados de
teclado. Los otros dos tipos de puntos de interrupción se pueden establecer, pero debe
hacerse desde el panel de consola mediante el cmdlet Set-PSBreakpoint. En esta sección
se describe cómo puede realizar la depuración de tareas en Windows PowerShell ISE
mediante los menús, cuando están disponibles, y ejecutar una serie más amplia de
comandos desde el panel de consola usando scripts.
Para establecer un punto de interrupción
Solo se puede establecer un punto de interrupción en un script después de guardarlo.
Haga clic con el botón derecho en la línea donde desee establecer un punto de
interrupción y después haga clic en Alternar punto de interrupción. O bien, haga clic en
la línea donde desee establecer un punto de interrupción y presione F9 o, en el menú
Depurar, haga clic en Alternar punto de interrupción.

El script siguiente es un ejemplo de cómo establecer un punto de interrupción de


variable desde el panel de consola mediante el cmdlet Set-PSBreakpoint.

PowerShell

# This command sets a breakpoint on the Server variable in the Sample.ps1


script.
Set-PSBreakpoint -Script sample.ps1 -Variable Server

Enumerar todos los puntos de interrupción


Muestra todos los puntos de interrupción de la sesión actual de Windows PowerShell.

En el menú Depurar, haga clic en Mostrar puntos de interrupción. El script siguiente es


un ejemplo de cómo enumerar todos los puntos de interrupción desde el panel de
consola mediante el cmdlet Get-PSBreakpoint.

PowerShell

# This command lists all breakpoints in the current session.


Get-PSBreakpoint

Quitar un punto de interrupción


Al quitar un punto de interrupción, este se elimina.

Si piensa que podría querer usarlo más adelante, considere la posibilidad de deshabilitar
un punto de interrupción en su lugar. Haga clic con el botón derecho en la línea donde
desee quitar un punto de interrupción y después haga clic en ToggleBreakpoint. O bien,
haga clic en la línea donde desee quitar un punto de interrupción y, en el menú
Depurar, haga clic en Alternar punto de interrupción. El script siguiente es un ejemplo
de cómo quitar un punto de interrupción con un identificador especificado en el panel
de consola mediante el cmdlet Remove-PSBreakpoint.

PowerShell
# This command deletes the breakpoint with breakpoint ID 2.
Remove-PSBreakpoint -Id 2

Quitar todos los puntos de interrupción


Para quitar todos los puntos de interrupción definidos en la sesión actual, en el menú
Depurar, haga clic en Quitar todos los puntos de interrupción.

El script siguiente es un ejemplo de cómo quitar todos los puntos de interrupción del
panel de consola mediante el cmdlet Remove-PSBreakpoint.

PowerShell

# This command deletes all of the breakpoints in the current session.


Get-PSBreakpoint | Remove-PSBreakpoint

Deshabilitar un punto de interrupción


Deshabilitar un punto de interrupción no lo quita. Lo desactiva hasta que se habilita.
Para deshabilitar un punto de interrupción de línea específico, haga clic con el botón
derecho en la línea donde desee deshabilitar un punto de interrupción y luego haga clic
en Deshabilitar punto de interrupción.

O bien, haga clic en la línea donde desee deshabilitar un punto de interrupción y


presione F9 o, en el menú Depurar, haga clic en Deshabilitar punto de interrupción. El
script siguiente es un ejemplo de cómo quitar un punto de interrupción con un
identificador especificado del panel de consola mediante el cmdlet Disable-
PSBreakpoint.

PowerShell

# This command disables the breakpoint with breakpoint ID 0.


Disable-PSBreakpoint -Id 0

Deshabilitar todos los puntos de interrupción


Al deshabilitar un punto de interrupción, este no se quita; permanece desactivado hasta
que se vuelve a habilitar. Para deshabilitar todos los puntos de interrupción de la sesión
actual, en el menú Depurar, haga clic en Deshabilitar todos los puntos de interrupción.
El script siguiente es un ejemplo de cómo deshabilitar todos los puntos de interrupción
desde el panel de consola mediante el cmdlet Disable-PSBreakpoint.
PowerShell

# This command disables all breakpoints in the current session.


# You can abbreviate this command as: "gbp | dbp".
Get-PSBreakpoint | Disable-PSBreakpoint

Habilitar un punto de interrupción


Para habilitar un punto de interrupción específico, haga clic con el botón derecho en la
línea donde desee habilitar un punto de interrupción y después haga clic en Habilitar
punto de interrupción. O bien, haga clic en la línea donde desee habilitar un punto de
interrupción y presione F9 o, en el menú Depurar, haga clic en Habilitar punto de
interrupción. El script siguiente es un ejemplo de cómo habilitar puntos de interrupción
desde el panel de consola mediante el cmdlet Enable-PSBreakpoint.

PowerShell

# This command enables breakpoints with breakpoint IDs 0, 1, and 5.


Enable-PSBreakpoint -Id 0, 1, 5

Habilitar todos los puntos de interrupción


Para habilitar todos los puntos de interrupción definidos en la sesión actual, en el menú
Depurar, haga clic en Habilitar todos los puntos de interrupción. El script siguiente es
un ejemplo de cómo habilitar todos los puntos de interrupción desde el panel de
consola mediante el cmdlet Enable-PSBreakpoint.

PowerShell

# This command enables all breakpoints in the current session.


# You can abbreviate the command by using their aliases: "gbp | ebp".
Get-PSBreakpoint | Enable-PSBreakpoint

Cómo administrar una sesión de depuración


Antes de iniciar la depuración, debe establecer uno o varios puntos de interrupción. No
se puede establecer un punto de interrupción si no se guarda el script que desea
depurar. Para obtener instrucciones acerca de cómo establecer un punto de
interrupción, vea Cómo administrar los puntos de interrupción o Set-PSBreakpoint.
Después de iniciar la depuración, no se puede editar un script hasta que la depuración
se detenga. Un script con uno o más puntos de interrupción establecidos se guarda
automáticamente antes de ejecutarse.

Para iniciar la depuración


Presione F5 o haga clic en el icono Ejecutar script en la barra de herramientas, o bien,
en el menú Depurar, haga clic en Ejecutar o continuar. El script se ejecuta hasta que
encuentra el primer punto de interrupción. Detiene la operación en este punto y resalta
la línea en la que se produce la pausa.

Para continuar con la depuración


Presione F5 o haga clic en el icono Ejecutar Script en la barra de herramientas, o bien,
en el menú Depurar, haga clic en Ejecutar o continuar. También puede escribir C en el
panel de consola y presionar ENTRAR . Esto hace que el script se siga ejecutando hasta el
punto de interrupción siguiente o hasta el final si no se encuentran más puntos de
interrupción.

Para ver la pila de llamadas


La pila de llamadas muestra la ubicación de ejecución actual en el script. Si el script se
ejecuta en una función que llamó una función diferente, se representa mediante filas
adicionales en la salida. La última fila muestra el script original y la línea en la que se
llamó a una función. La siguiente línea muestra esa función y la línea en la que se podría
haber llamado a otra función. La primera fila muestra el contexto actual de la línea
actual en la que se estableció el punto de interrupción.

Mientras está en pausa, para ver la pila de llamadas actual, presione CTRL + MAYÚS + D o,
en el menú Depurar, haga clic en Mostrar pila de llamadas. También puede escribir K
en el panel de consola y presionar ENTRAR .

Para detener la depuración


Presione MAYÚS + F5 o, en el menú Depurar, haga clic en Detener el depurador.
También puede escribir Q en el panel de consola y presionar ENTRAR .

Cómo depurar paso a paso por procedimientos,


por instrucciones y para salir durante la
depuración
La ejecución paso a paso es el proceso de ejecutar una instrucción cada vez. Puede
detenerse en una línea de código y examinar los valores de las variables y el estado del
sistema. En la tabla siguiente se describen las tareas de depuración comunes, como la
depuración paso a paso por procedimientos, por instrucciones y para salir.

Tarea de Descripción Cómo llevarla a cabo en


depuración PowerShell ISE

Depurar paso a Ejecuta la instrucción actual y, luego, se detiene Presione F11 o, en el


paso por en la instrucción siguiente. Si la instrucción menú Depurar, haga clic en
instrucciones actual es una llamada de función o script, el Paso a paso por
depurador ejecuta la depuración paso a paso instrucciones. También
por instrucciones en la función o el script. De lo puede escribir S en el
contrario, se detiene en la siguiente instrucción. panel de consola y
presionar ENTRAR .

Depurar paso a Ejecuta la instrucción actual y, luego, se detiene Presione F10 o, en el


paso por en la instrucción siguiente. Si la instrucción menú Depurar, haga clic en
procedimientos actual es una llamada de función o script, el Paso a paso por
depurador ejecuta la función o el script procedimientos. También
completo y se detiene en la siguiente instrucción puede escribir V en el
después de la llamada de función. panel de consola y
presionar ENTRAR .

Depurar paso a Sale de la función actual y sube un nivel si la Presione MAYÚS + F11 o,
paso para salir función está anidada. Si se encuentra en el en el menú Depurar, haga
cuerpo principal, el script se ejecuta hasta el final clic en Depurar paso a
o hasta el punto de interrupción siguiente. Las paso para salir. También
instrucciones omitidas se ejecutan, pero no se puede escribir O en el
depuran paso a paso. panel de consola y
presionar ENTRAR .

Continuar Continúa la ejecución hasta el final o hasta el Presione F5 o, en el menú


punto de interrupción siguiente. Las funciones Depurar, haga clic en
omitidas y las invocaciones se ejecutan, pero no Ejecutar o continuar.
se ejecutan paso a paso. También puede escribir C
en el panel de consola y
presionar ENTRAR .

Cómo mostrar los valores de variables durante


la depuración
Puede mostrar los valores actuales de las variables en el script mientras realiza la
depuración paso a paso del código.
Para mostrar los valores de las variables estándar
Utilice uno de los métodos siguientes:

En el panel de scripts, mantenga el puntero sobre la variable para mostrar su valor


como una información sobre herramientas.

En el panel de consola, escriba el nombre de la variable y presione ENTRAR .

Todos los paneles de ISE están siempre en el mismo ámbito. Por lo tanto, mientras está
depurando un script, los comandos que se escriben en el panel de consola se ejecutan
en el ámbito del script. Esto le permite usar el panel de consola para buscar los valores
de variables y llamar a funciones que solo se han definido en el script.

Para mostrar los valores de las variables automáticas


Puede usar el método anterior para mostrar el valor de casi todas las variables al
depurar un script. Sin embargo, estos métodos no funcionan con las siguientes variables
automáticas.

$_

$Input

$MyInvocation

$PSBoundParameters

$Args

Si intenta mostrar el valor de cualquiera de estas variables, obtendrá el valor de esa


variable en una canalización interna usada por el depurador, no el valor de la variable en
el script. Puede solucionar esto para algunas variables ( $_ , $Input , $MyInvocation ,
$PSBoundParameters y $Args ) con el método siguiente:

1. En el script, asigne el valor de la variable automática a una nueva variable.

2. Para mostrar el valor de la nueva variable, mantenga el puntero sobre la nueva


variable en el panel de scripts o escriba la nueva variable en el panel de consola.

Por ejemplo, para mostrar el valor de la variable $MyInvocation , en el script, asigne el


valor a una nueva variable, como $scriptName y, a continuación, mantenga el puntero
encima o escriba la variable $scriptName para mostrar su valor.
PowerShell

# In C:\ps-test\MyScript.ps1
$scriptName = $MyInvocation.PSCommandPath

PowerShell

# In the Console Pane:


.\MyScript.ps1
$scriptName

Output

C:\ps-test\MyScript.ps1

Consulte también
Explorar Windows PowerShell ISE
Cómo usar perfiles en ISE de Windows
PowerShell
Artículo • 21/03/2023

En este artículo se explica cómo usar perfiles en el Entorno de scripting integrado (ISE)
de Windows PowerShell. Antes de realizar las tareas de esta sección, se recomienda
consultar about_Profiles. O bien, en el panel de consola, escriba Get-Help
about_Profiles y presione ENTRAR .

Un perfil es un script de Windows PowerShell ISE que se ejecuta automáticamente


cuando se inicia una nueva sesión. Puede crear uno o varios perfiles de Windows
PowerShell para Windows PowerShell ISE y usarlos para configurar el entorno de
Windows PowerShell o Windows PowerShell ISE y prepararlo para su uso, con las
variables, los alias, las funciones, y las preferencias de color y fuente que desee que
estén disponibles. Un perfil afecta a todas las sesiones de Windows PowerShell ISE que
inicia.

7 Nota

La directiva de ejecución de Windows PowerShell determina si puede ejecutar


scripts y cargar un perfil. La directiva de ejecución predeterminada, "Restricted",
impide que se ejecuten todos los scripts, incluidos los perfiles. Si usa la directiva
"Restricted", no se puede cargar el perfil. Para obtener más información sobre la
directiva de ejecución, vea about_Execution_Policies.

Seleccionar un perfil para usarlo en Windows


PowerShell ISE
Windows PowerShell ISE admite perfiles para el usuario actual y para todos los usuarios.
También admite los perfiles de Windows PowerShell que se aplican a todos los hosts.

El perfil que use viene determinado por la forma en que se usa Windows PowerShell y
Windows PowerShell ISE.

Si solo usa Windows PowerShell ISE para ejecutar Windows PowerShell, guarde
todos los elementos en uno de los perfiles específicos de ISE, como el perfil
CurrentUserCurrentHost de Windows PowerShell ISE o el perfil
AllUsersCurrentHost de Windows PowerShell ISE.
Si usa varios programas host para ejecutar Windows PowerShell, guarde sus
funciones, alias, variables y comandos en un perfil que afecte a todos los
programas host, como el perfil CurrentUserAllHosts o AllUsersAllHosts y guarde
las características específicas de ISE, como la personalización de color y fuente en
el perfil CurrentUserCurrentHost de Windows PowerShell ISE o el perfil
AllUsersCurrentHost de Windows PowerShell ISE.

Los siguientes son perfiles que se pueden crear y usar en Windows PowerShell ISE. Cada
perfil se guarda en su propia ruta de acceso específica.

Tipo de perfil Ruta de acceso al perfil

Usuario actual, PowerShell ISE $PROFILE.CurrentUserCurrentHost o $PROFILE

Todos los usuarios, PowerShell ISE $PROFILE.AllUsersCurrentHost

Usuario actual, todos los hosts $PROFILE.CurrentUserAllHosts

Todos los usuarios, todos los hosts $PROFILE.AllUsersAllHosts

Para crear un nuevo perfil


Para crear un nuevo perfil "Usuario actual, Windows PowerShell ISE", ejecute este
comando:

PowerShell

if (!(Test-Path -Path $PROFILE ))


{ New-Item -Type File -Path $PROFILE -Force }

Para crear un nuevo perfil "Todos los usuarios, Windows PowerShell ISE", ejecute este
comando:

PowerShell

if (!(Test-Path -Path $PROFILE.AllUsersCurrentHost))


{ New-Item -Type File -Path $PROFILE.AllUsersCurrentHost -Force }

Para crear un nuevo perfil "Usuario actual, todos los hosts", ejecute este comando:

PowerShell

if (!(Test-Path -Path $PROFILE.CurrentUserAllHosts))


{ New-Item -Type File -Path $PROFILE.CurrentUserAllHosts -Force }
Para crear un nuevo perfil "Todos los usuarios, todos los hosts", escriba:

PowerShell

if (!(Test-Path -Path $PROFILE.AllUsersAllHosts))


{ New-Item -Type File -Path $PROFILE.AllUsersAllHosts -Force }

Para editar un perfil


1. Para abrir el perfil, ejecute el comando psEdit con la variable que especifica el
perfil que quiere editar. Por ejemplo, para abrir el perfil "Usuario actual, Windows
PowerShell ISE", escriba: psEdit $PROFILE

2. Agregue algunos elementos a su perfil. Estos son algunos ejemplos para


comenzar:

Para cambiar el color de fondo predeterminado del panel de consola a azul,


en el archivo de perfil, escriba: $psISE.Options.OutputPaneBackground =
'blue' . Para más información sobre la variable $psISE , consulte Referencia

del modelo de objetos de Windows PowerShell ISE.

Para cambiar el tamaño de fuente a 20, en el archivo de perfil, escriba:


$psISE.Options.FontSize =20

3. Para guardar el archivo de perfil, en el menú Archivo, haga clic en Guardar. La


próxima vez que abra Windows PowerShell ISE, se aplicarán sus opciones
personalizadas.

Consulte también
about_Profiles
Presentación de Windows PowerShell ISE
Cómo usar la finalización con tabulación
en el panel de scripts y en el panel de
consola
Artículo • 21/03/2023

La finalización con tabulación proporciona ayuda automática al escribir en el panel de


scripts o el panel de comandos. Para aprovechar esta característica, siga estos pasos:

Para completar automáticamente una entrada


de comando
En el panel de comandos o el panel de scripts, escriba algunos caracteres de un
comando y, después, presione la tecla TAB para seleccionar el texto de finalización
deseado. Si varios elementos empiezan por el texto que ha escrito inicialmente, siga
presionando la tecla TAB hasta que aparezca el elemento deseado. La finalización con
tabulación puede ayudarle a escribir un nombre de cmdlet, de parámetro, de variable o
de propiedad de objeto, o bien una ruta de acceso de archivo.

7 Nota

En el panel de scripts, al presionar TAB , se completa automáticamente un comando


solo cuando se editan archivos .ps1 , .psd1 o .psm1 . La finalización con tabulación
funciona siempre al escribir en el panel de comandos.

Para completar automáticamente la entrada de


un parámetro de cmdlet
En el panel de comandos o el panel de scripts, escriba un cmdlet seguido por un guion
y, después, presione la tecla TAB .

Por ejemplo, escriba Get-Process - y, a continuación, presione TAB varias veces para
mostrar cada uno de los parámetros del cmdlet de uno en uno.

Consulte también
Presentación de Windows PowerShell ISE
Cómo crear una pestaña de PowerShell
Cómo usar el panel de consola en
Windows PowerShell ISE
Artículo • 21/03/2023

El panel de consola del Entorno de scripting integrado (ISE) de Windows PowerShell


funciona exactamente igual que la ventana de consola independiente de Windows
PowerShell ISE.

Para ejecutar un comando en el panel de consola, escriba un comando y, a


continuación, presione ENTRAR . Para escribir varios comandos que quiera ejecutar en
secuencia, escriba MAYÚS + ENTRAR entre comandos. Consulte Cómo usar la finalización
con tabulación en el panel de scripts y en el panel de consola para obtener ayuda sobre
la escritura de los comandos.

Para detener un comando, en la barra de herramientas, haga clic en Detener la


operación o presione CTRL + Interrumpir . También puede usar CTRL + C para detener un
comando si el contexto no es ambiguo. Por ejemplo, si se ha seleccionado texto en el
panel actual, CTRL + C se asigna a la operación de copia.

A partir de Windows PowerShell v3, el panel de salida se combinó con el panel de


consola. La ventaja de esta combinación es que se comporta como la consola
independiente de Windows PowerShell y se eliminan las diferencias en los
procedimientos que eran necesarios cuando eran independientes. Puede:

Seleccionar y copiar texto del panel de consola en el Portapapeles para pegarlo en


cualquier otra ventana. Para seleccionar texto, mantenga presionado el botón del
ratón en el panel de salida mientras arrastra el mouse sobre el texto que quiere
capturar. También puede usar las teclas de dirección mientras mantiene presionada
la tecla MAYÚS para seleccionar texto. Después, pulse CTRL + C o haga clic en el
icono Copiar de la barra de herramientas.

Pegar el texto seleccionado en la posición actual del cursor. Haga clic en el icono
Pegar de la barra de herramientas.

Borrar todo el texto del panel de consola. Para borrar el panel de consola, puede
hacer clic en el icono Borrar panel de consola de la barra de herramientas, o bien
ejecutar el comando Clear-Host o su alias, cls .

Consulte también
Presentación de Windows PowerShell ISE
Cómo escribir y ejecutar scripts en
Windows PowerShell ISE
Artículo • 21/03/2023

En este artículo se describe cómo crear, editar, ejecutar y guardar scripts en el panel de
scripts.

Cómo crear y ejecutar scripts


Puede abrir y editar archivos de Windows PowerShell en el panel de scripts. Los tipos de
archivo de interés específicos de Windows PowerShell son los archivos de script ( .ps1 ),
los archivos de datos de script ( .psd1 ) y los archivos de módulo de script ( .psm1 ). Estos
tipos de archivo presentan color de sintaxis en el editor de panel de scripts. Otros tipos
de archivo comunes que puede abrir en el panel de scripts son los archivos de
configuración ( .ps1xml ), los archivos XML y los archivos de texto.

7 Nota

La directiva de ejecución de Windows PowerShell determina si puede ejecutar


scripts y cargar archivos de configuración y perfiles de Windows PowerShell. La
directiva de ejecución predeterminada, Restricted, impide que se ejecuten todos los
scripts y que se carguen perfiles. Para cambiar la directiva de ejecución a fin de
permitir cargar y usar perfiles, consulte Set-ExecutionPolicy y about_Signing.

Para crear un nuevo archivo de script


En la barra de herramientas, haga clic en Nuevo, o bien, en el menú Archivo, haga clic
en Nuevo. El archivo creado aparece en una nueva pestaña de archivo de la pestaña
actual de PowerShell. Recuerde que las pestañas de PowerShell solo son visibles cuando
hay más de una. De forma predeterminada, se crea un archivo de tipo script ( .ps1 ), pero
se puede guardar con un nombre y una extensión diferentes. Se pueden crear varios
archivos de script en la misma pestaña de PowerShell.

Para abrir un script existente


En la barra de herramientas, haga clic en Abrir, o bien, en el menú Archivo, haga clic en
Abrir. En el cuadro de diálogo Abrir, seleccione el archivo que quiera abrir. El archivo
abierto aparece en una nueva pestaña.

Para cerrar una pestaña de script


Haga clic en el icono Cerrar (X) de la pestaña del archivo que desea cerrar o bien
seleccione el menú Archivo y haga clic en Cerrar.

Si el archivo se ha modificado desde que se guardó por última vez, se le preguntará si


desea guardar o descartar los cambios.

Para mostrar la ruta de acceso del archivo


En la pestaña del archivo, señale el nombre de archivo. La ruta de acceso completa al
archivo de script se muestra en una información sobre herramientas.

Para ejecutar un script


En la barra de herramientas, haga clic en Ejecutar script, o bien, en el menú Archivo,
haga clic en Ejecutar.

Para ejecutar parte de un script


1. En el panel de scripts, seleccione una parte de un script.
2. En el menú Archivo, haga clic en Ejecutar selección, o bien haga clic en Ejecutar
selección en la barra de herramientas.

Para detener un script que se está ejecutando


Hay varias maneras para detener un script en ejecución.

Haga clic en Detener operación en la barra de herramientas


Presione CTRL + Interrumpir

Seleccione el menú Archivo y haga clic en Detener operación.

También funciona pulsar CTRL + C , a menos que ya haya texto seleccionado, en cuyo
caso CTRL + C se asigna a la función de copia del texto seleccionado.

Cómo escribir y editar texto en el panel de


scripts
Puede copiar, cortar, pegar, buscar y reemplazar texto en el panel de scripts. También
puede deshacer y rehacer la última acción que ha realizado. Los métodos abreviados de
teclado para estas acciones son los mismos que los usados para todas las aplicaciones
de Windows.

Para escribir texto en el panel de scripts


1. Mueva el cursor al panel de scripts haciendo clic en cualquier lugar del panel de
scripts o en Ir al panel de scripts en el menú Ver.
2. Cree un script. El color de sintaxis y la finalización con tabulación proporcionan una
experiencia de edición más rica en Windows PowerShell ISE.
3. Vea Cómo usar la finalización con tabulación en el panel de scripts y en el panel de
consola para obtener más información sobre el uso de la característica de
finalización de con tabulación para facilitar la escritura.

Para buscar texto en el panel de scripts


1. Para buscar texto en cualquier lugar, pulse CTRL + F o, en el menú Edición, haga
clic en Buscar en el script.
2. Para buscar texto después del cursor, presione F3 o, en el menú Edición, haga clic
en Buscar siguiente en el script.
3. Para buscar texto antes del cursor, pulse MAYÚS + F3 o, en el menú Edición, haga
clic en Buscar anterior en el script.

Para buscar y reemplazar texto en el panel de scripts


Presione CTRL + H o, en el menú Edición, haga clic en Reemplazar en script. Escriba el
texto que desea encontrar y el texto de reemplazo y, después, presione ENTRAR .

Para ir a una línea determinada de texto en el panel de


scripts
1. En el panel de scripts, pulse CTRL + G o, en el menú Edición, haga clic en Ir a la
línea.

2. Escriba un número de línea.

Para copiar texto en el panel de scripts


1. En el panel de scripts, seleccione el texto que desee copiar.
2. Pulse CTRL + C o haga clic en el icono Copiar de la barra de herramientas. O bien,
en el menú Edición, haga clic en Copiar.

Para cortar texto en el panel de scripts


1. En el panel de scripts, seleccione el texto que desee cortar.
2. Pulse CTRL + X o haga clic en el icono Cortar de la barra de herramientas. O bien,
en el menú Edición, haga clic en Cortar.

Para pegar texto en el panel de scripts


Pulse CTRL + V o haga clic en el icono Pegar de la barra de herramientas. O bien, en el
menú Edición, haga clic en Pegar.

Para deshacer una acción en el panel de scripts


Pulse CTRL + Z o haga clic en el icono Deshacer de la barra de herramientas. O bien, en
el menú Edición, haga clic en Deshacer.

Para rehacer una acción en el panel de scripts


Pulse CTRL + Y o haga clic en el icono Rehacer de la barra de herramientas. O bien, en
el menú Edición, haga clic en Rehacer.

Cómo guardar un script


Aparece un asterisco junto al nombre del script para marcar un archivo que no se ha
guardado desde que se modificó. El asterisco desaparecerá cuando se guarda el archivo.

Para guardar un script


Pulse CTRL + S o haga clic en el icono Guardar de la barra de herramientas. O bien, en
el menú Archivo, haga clic en Guardar.

Para guardar un script y asignarle un nombre


1. En el menú Archivo, haga clic en Guardar como. Se abre el cuadro de diálogo
Guardar como.
2. En el cuadro Nombre de archivo, escriba un nombre para el archivo.
3. En el cuadro Guardar como tipo, seleccione un tipo de archivo. Por ejemplo, en el
cuadro Guardar como tipo, seleccione "Scripts de PowerShell ( *.ps1 )".
4. Haga clic en Save(Guardar).

Para guardar un script en la codificación ASCII


De forma predeterminada, Windows PowerShell ISE guarda los nuevos archivos de script
( .ps1 ), los archivos de datos de script ( .psd1 ) y los archivos de módulo de script
( .psm1 ) como Unicode (BigEndianUnicode). Para guardar un script en otra codificación,
como ASCII (ANSI), use los métodos Save o SaveAs en el objeto $psISE.CurrentFile.

El siguiente comando guarda un nuevo script como MyScript.ps1 con la codificación


ASCII.

PowerShell

$psISE.CurrentFile.SaveAs("MyScript.ps1", [System.Text.Encoding]::ASCII)

El siguiente comando reemplaza el archivo de script actual con un archivo con el mismo
nombre, pero con la codificación ASCII.

PowerShell

$psISE.CurrentFile.Save([System.Text.Encoding]::ASCII)

El comando siguiente obtiene la codificación del archivo actual.

PowerShell

$psISE.CurrentFile.encoding

Windows PowerShell ISE admite las siguientes opciones de codificación: ASCII,


BigEndianUnicode, Unicode, UTF32, UTF7, UTF8 y predeterminada. El valor de la opción
predeterminada varía según el sistema.

Windows PowerShell ISE no cambia la codificación de los archivos de script cuando se


usan los comandos Guardar o Guardar como.

Consulte también
Explorar Windows PowerShell ISE
Métodos abreviados de teclado para
Windows PowerShell ISE
Artículo • 07/02/2023

Use los siguientes métodos abreviados de teclado para realizar acciones en el Entorno
de scripting integrado (ISE) de Windows PowerShell®. Windows PowerShell ISE está
disponible como parte de los sistemas operativos Windows Server y cliente de
Windows, pero también se puede instalar en algunos sistemas operativos anteriores de
Windows como parte del paquete de descarga de Windows Management Framework
4.0 .

Métodos abreviados de teclado para editar


texto
Puede usar los siguientes métodos abreviados de teclado cuando edite texto.

Acción Métodos Usar en


abreviados
de
teclado.

Ayuda F1 Panel de scripts Importante: Puede especificar que la ayuda de


F1 proceda de Microsoft Learn o de la ayuda descargada
(consulte Update-Help ). Para realizar la selección, haga clic en
Herramientas, Opciones y, a continuación, en la pestaña
Configuración General, active o desactive Usar Ayuda local en
lugar de contenido en línea.

Seleccionar todo CTRL + A Panel de scripts

Copy CTRL + C Panel de scripts, Panel de comandos y Panel de salida

Cortar CTRL + X Panel de scripts, Panel de comandos

Expandir o CTRL + M Panel de scripts


contraer la
esquematización

Buscar en el CTRL + F Panel de scripts


script

Buscar siguiente F3 Panel de scripts


en el script
Acción Métodos Usar en
abreviados
de
teclado.

Buscar anterior MAYÚS + Panel de scripts


en el script F3

Buscar llave que CTRL + ] Panel de scripts


coincida

Pegar CTRL + V Panel de scripts, Panel de comandos

Poner en CTRL + U Panel de scripts, Panel de comandos


minúsculas

Poner en CTRL + Panel de scripts, Panel de comandos


mayúsculas MAYÚS + U

Rehacer CTRL + Y Panel de scripts, Panel de comandos

Reemplazar en CTRL + H Panel de scripts


el script

Guardar CTRL + S Panel de scripts

Seleccionar todo CTRL + A Panel de scripts, Panel de comandos y Panel de salida

Mostrar CTRL + J Panel de scripts, Panel de comandos


fragmentos de
código

Deshacer CTRL + Z Panel de scripts, Panel de comandos

Mostrar ayuda CTRL + Panel de scripts


de IntelliSense Espacio

Eliminar una CTRL + Panel de scripts


palabra a la Retroceso
izquierda

Eliminar una CTRL + Panel de scripts


palabra a la Suprimir
derecha

Métodos abreviados de teclado para ejecutar


scripts
Puede usar los siguientes métodos abreviados de teclado cuando ejecute scripts en el
panel de scripts.

Acción Método abreviado de teclado

Nuevo CTRL + N

Abrir CTRL + O

Ejecutar F5

Ejecutar F8
selección

Detener la CTRL + INTERRUMPIR . CTRL + C se puede usar cuando el contexto no es ambiguo


ejecución (cuando no hay texto seleccionado).

Tabulación CTRL + TAB Nota: la tabulación al siguiente script solo funciona si tiene una sola
(para el pestaña de Windows PowerShell abierta, o bien si tiene más de una abierta pero el
siguiente foco está en el panel de scripts.
script)

Tabulación CTRL + MAYÚS + TAB Nota: la tabulación al script anterior solo funciona si tiene
(para el una sola pestaña de Windows PowerShell abierta, o bien si tiene más de una
script abierta pero el foco está en el panel de scripts.
anterior)

Métodos abreviados de teclado para


personalizar la vista
Puede usar los siguientes métodos abreviados de teclado cuando personalice la vista en
Windows PowerShell ISE. Son accesibles desde todos los paneles de la aplicación.

Acción Método abreviado de


teclado

Ir al panel de comandos (v2) o el panel de consola (v3 y versiones CTRL + D


posteriores)

Ir al panel de salida (solo v2) CTRL + MAYÚS + O

Ir al panel de scripts CTRL + I

Mostrar el panel de scripts CTRL + R

Ocultar el panel de scripts CTRL + R


Acción Método abreviado de
teclado

Subir el panel de scripts CTRL + 1

Mover el panel de scripts a la derecha CTRL + 2

Maximizar el panel de scripts CTRL + 3

Acercar CTRL + +

Alejar CTRL + -

Métodos abreviados de teclado para depurar


scripts
Puede usar los siguientes métodos abreviados de teclado cuando depure scripts.

Acción Método abreviado de Usar en


teclado

Ejecutar o continuar F5 Panel de scripts, al depurar un


script

Depurar paso a paso por F11 Panel de scripts, al depurar un


instrucciones script

Depurar paso a paso por F10 Panel de scripts, al depurar un


procedimientos script

Depurar paso a paso para salir MAYÚS + F11 Panel de scripts, al depurar un
script

Mostrar pila de llamadas CTRL + MAYÚS + D Panel de scripts, al depurar un


script

Mostrar puntos de interrupción CTRL + MAYÚS + L Panel de scripts, al depurar un


script

Alternar punto de interrupción F9 Panel de scripts, al depurar un


script

Quitar todos los puntos de CTRL + MAYÚS + F9 Panel de scripts, al depurar un


interrupción script

Detener el depurador MAYÚS + F5 Panel de scripts, al depurar un


script
7 Nota

También puede usar los métodos abreviados de teclado diseñados para la consola
de Windows PowerShell cuando depure scripts en Windows PowerShell ISE. Para
usar estos métodos abreviados, debe escribir el método abreviado en el panel de
comandos y presionar ENTRAR .

Acción Método Usar en


abreviado de
teclado

Continuar C Panel de consola, al


depurar un script

Depurar paso a paso por instrucciones S Panel de consola, al


depurar un script

Depurar paso a paso por procedimientos V Panel de consola, al


depurar un script

Depurar paso a paso para salir O Panel de consola, al


depurar un script

Repetir el último comando (para depurar paso a paso ENTRAR Panel de consola, al
por instrucciones o por procedimientos) depurar un script

Mostrar pila de llamadas K Panel de consola, al


depurar un script

Detener la depuración Q Panel de consola, al


depurar un script

Enumerar el script L Panel de consola, al


depurar un script

Mostrar los comandos de depuración de la consola H o ? Panel de consola, al


depurar un script

Métodos abreviados de teclado para las


pestañas de Windows PowerShell
Puede usar los siguientes métodos abreviados de teclado cuando use las pestañas de
Windows PowerShell.

Acción Método abreviado de teclado


Acción Método abreviado de teclado

Cerrar la pestaña de CTRL + W


PowerShell

Nueva pestaña de CTRL + T


PowerShell

Pestaña de CTRL + MAYÚS + TAB . Este método abreviado solo funciona si no hay
PowerShell anterior archivos abiertos en ninguna pestaña de Windows PowerShell.

Pestaña de Windows CTRL + TAB . Este método abreviado solo funciona si no hay archivos
PowerShell siguiente abiertos en ninguna pestaña de Windows PowerShell.

Métodos abreviados de teclado para iniciar y


salir
Puede usar los siguientes métodos abreviados de teclado para iniciar la consola de
Windows PowerShell (PowerShell.exe) o para salir de Windows PowerShell ISE.

Acción Método abreviado de teclado

Salir ALT + F4

Iniciar PowerShell.exe (consola de Windows PowerShell) CTRL + MAYÚS + P

Consulte también
PowerShell Magazine: The Complete List of Windows PowerShell ISE Keyboard
Shortcuts (Lista completa de métodos abreviados de teclado de Windows
PowerShell ISE)
Accesibilidad en ISE de Windows
PowerShell
Artículo • 21/03/2023

En este tema se describen las características de accesibilidad del Entorno de scripting


integrado (ISE) de Windows PowerShell que pueden resultar útiles.

Cómo cambiar el tamaño y la ubicación de los paneles de consola y de scripts


Métodos abreviados de teclado para editar texto
Métodos abreviados de teclado para ejecutar scripts
Métodos abreviados de teclado para personalizar la vista
Métodos abreviados de teclado para depurar scripts
Métodos abreviados de teclado para las pestañas de Windows PowerShell
Métodos abreviados de teclado para iniciar y salir
Administración de puntos de interrupción con cmdlets

Microsoft tiene el compromiso de que todas las personas puedan utilizar fácilmente sus
productos y servicios. En los siguientes temas se proporciona información sobre las
características, los productos y los servicios que permiten que Windows PowerShell ISE
sea más accesible para las personas con discapacidades.

Además de las características de accesibilidad y las utilidades de Microsoft Windows, las


siguientes características hacen que Windows PowerShell ISE sea más accesible para las
personas con discapacidades:

Métodos abreviados de teclado

La tabla de colores de sintaxis y la capacidad de modificar otras opciones de color


mediante el objeto de scripting $psISE.Options.

Cambio de tamaño del texto.

Cómo cambiar el tamaño y la ubicación de los


paneles de consola y de scripts
Puede usar los siguientes pasos para cambiar el tamaño y la ubicación del panel de
consola y el panel de scripts. Al abrir de nuevo Windows PowerShell ISE, se conservarán
los cambios realizados en el tamaño y la ubicación.
Para cambiar el tamaño del panel de scripts y el panel de
consola
1. Detenga el puntero en la línea de división entre el panel de scripts y el panel de
consola.

2. Cuando el puntero del ratón cambie a una flecha con dos puntas, arrastre el borde
para cambiar el tamaño del panel.

Para mover el panel de scripts y el panel de consola


Realice una de las siguientes acciones:

Para mover el panel de scripts encima del panel de consola, presione CTRL + 1 o,
en la barra de herramientas, haga clic en el icono Mostrar panel de scripts arriba
o, en el menú Ver, haga clic en Mostrar panel de scripts arriba.

Para mover el panel de scripts a la derecha del panel de consola, presione CTRL +
2 o, en la barra de herramientas, haga clic en el icono Mostrar panel de scripts a
la derecha o, en el menú Ver, haga clic en Mostrar panel de scripts a la derecha.

Para maximizar el panel de scripts, presione CTRL + 3 o, en la barra de


herramientas, haga clic en el icono Mostrar panel de scripts maximizado o, en el
menú Ver, haga clic en Mostrar panel de scripts maximizado.

Para maximizar el panel de consola y ocultar el panel de scripts, en el extremo


derecho de la fila de pestañas, haga clic en el icono Ocultar panel de scripts y, en
el menú Ver, haga clic para anular la selección de la opción de menú Mostrar
panel de scripts.

Para mostrar el panel de scripts cuando el panel de consola esté maximizado, en el


extremo derecho de la fila de pestañas, haga clic en el icono Mostrar panel de
scripts o, en el menú Ver, haga clic para seleccionar la opción de menú Mostrar
panel de scripts.

Métodos abreviados de teclado para editar


texto
Puede usar los siguientes métodos abreviados de teclado cuando edite texto.

Acción Métodos abreviados de Usar en


teclado.
Acción Métodos abreviados de Usar en
teclado.

Copy CTRL + C Panel de scripts, panel de


consola

Cortar CTRL + X Panel de scripts, panel de


consola

Buscar en el script CTRL + F Panel de scripts

Buscar siguiente en el F3 Panel de scripts


script

Buscar anterior en el script MAYÚS + F3 Panel de scripts

Pegar CTRL + V Panel de scripts, panel de


consola

Rehacer CTRL + Y Panel de scripts, panel de


consola

Reemplazar en el script CTRL + H Panel de scripts

Guardar CTRL + S Panel de scripts

Seleccionar todo CTRL + A Panel de scripts, panel de


consola

Deshacer CTRL + Z Panel de scripts, panel de


consola

Métodos abreviados de teclado para ejecutar


scripts
Puede usar los siguientes métodos abreviados de teclado cuando ejecute scripts en el
panel de scripts.

Acción Método abreviado de teclado

Nuevo CTRL + N

Abrir CTRL + O

Ejecutar F5

Ejecutar F8
selección
Acción Método abreviado de teclado

Detener la CTRL + INTERRUMPIR . CTRL + C se puede usar cuando el contexto no es ambiguo


ejecución (cuando no hay texto seleccionado).

Tabulación CTRL + TAB Nota: el desplazamiento con la tecla Tab al siguiente script solo
(para el funciona si hay una única pestaña de PowerShell abierta, o bien si hay más de una
siguiente abierta, pero el foco está en el panel de scripts.
script)

Tabulación CTRL + MAYÚS + TAB Nota: el desplazamiento con la tecla Tab al script anterior
(para el funciona si hay una única pestaña de PowerShell abierta, o bien si hay más de una
script abierta, pero el foco está en el panel de scripts.
anterior)

Métodos abreviados de teclado para


personalizar la vista
Puede usar los siguientes métodos abreviados de teclado cuando personalice la vista en
Windows PowerShell ISE. Son accesibles desde todos los paneles de la aplicación.

Acción Método abreviado de teclado

Ir a panel de consola CTRL + D

Ir al panel de scripts CTRL + I

Mostrar el panel de scripts CTRL + R

Ocultar el panel de scripts CTRL + R

Subir el panel de scripts CTRL + 1

Mover el panel de scripts a la derecha CTRL + 2

Maximizar el panel de scripts CTRL + 3

Acercar CTRL + MÁS

Alejar CTRL + MENOS

Métodos abreviados de teclado para depurar


scripts
Puede usar los siguientes métodos abreviados de teclado cuando depure scripts.
Acción Método abreviado de Usar en
teclado

Ejecutar o continuar F5 Panel de scripts, al depurar un


script

Depurar paso a paso por F11 Panel de scripts, al depurar un


instrucciones script

Depurar paso a paso por F10 Panel de scripts, al depurar un


procedimientos script

Depurar paso a paso para salir MAYÚS + F11 Panel de scripts, al depurar un
script

Mostrar pila de llamadas CTRL + MAYÚS + D Panel de scripts, al depurar un


script

Mostrar puntos de interrupción CTRL + MAYÚS + L Panel de scripts, al depurar un


script

Alternar punto de interrupción F9 Panel de scripts, al depurar un


script

Quitar todos los puntos de CTRL + MAYÚS + F9 Panel de scripts, al depurar un


interrupción script

Detener el depurador MAYÚS + F5 Panel de scripts, al depurar un


script

7 Nota

También puede usar los métodos abreviados de teclado diseñados para la consola
de Windows PowerShell cuando depure scripts en Windows PowerShell ISE. Para
usar estos métodos abreviados, debe escribir el método abreviado en el panel de la
consola y presionar ENTRAR .

Acción Método Usar en


abreviado de
teclado

Continuar C Panel de consola, al


depurar un script

Depurar paso a paso por instrucciones S Panel de consola, al


depurar un script
Acción Método Usar en
abreviado de
teclado

Depurar paso a paso por procedimientos V Panel de consola, al


depurar un script

Depurar paso a paso para salir O Panel de consola, al


depurar un script

Repetir el último comando(Depurar paso a paso ENTRAR Panel de consola, al


por instrucciones/por procedimientos) depurar un script

Mostrar pila de llamadas K Panel de consola, al


depurar un script

Detener la depuración Q Panel de consola, al


depurar un script

Enumerar el script L Panel de consola, al


depurar un script

Mostrar los comandos de depuración de la consola H o ? Panel de consola, al


depurar un script

Métodos abreviados de teclado para las


pestañas de Windows PowerShell
Puede usar los siguientes métodos abreviados de teclado cuando use las pestañas de
Windows PowerShell.

Acción Método abreviado de teclado

Cerrar la pestaña de CTRL + W


PowerShell

Nueva pestaña de PowerShell CTRL + T

Pestaña de PowerShell CTRL + MAYÚS + TAB (solo si no hay archivos abiertos en


anterior ninguna pestaña de PowerShell)

Pestaña de Windows CTRL + TAB (solo si no hay archivos abiertos en ninguna


PowerShell siguiente pestaña de PowerShell)
Métodos abreviados de teclado para iniciar y
salir
Puede usar los siguientes métodos abreviados de teclado para iniciar la consola de
Windows PowerShell (PowerShell.exe) o para salir de Windows PowerShell ISE.

Acción Método abreviado de teclado

Salir ALT + F4

Iniciar PowerShell.exe (consola de Windows PowerShell) CTRL + MAYÚS + P

Administración de puntos de interrupción


Para las personas con discapacidad visual, existe información de punto de interrupción
disponible a través de los cmdlets de administración de puntos de interrupción, como
Get-PSBreakpoint y Set-PSBreakpoint. Para obtener más información, consulte "Cómo
administrar los puntos de interrupción" en Cómo depurar scripts en ISE de Windows
PowerShell.

Consulte también
Presentación de Windows PowerShell ISE
Finalidad del modelo de objetos de
scripting de Windows PowerShell ISE
Artículo • 21/03/2023

Los objetos están asociados con la forma y la función de Windows PowerShell


Integrated Scripting Environment (ISE). La referencia del modelo de objeto proporciona
detalles sobre los métodos y las propiedades de los miembros que estos objetos
exponen. Se proporcionan ejemplos que muestran cómo puede utilizar scripts para
acceder directamente a estos métodos y propiedades. El modelo de objetos de scripting
facilita el siguiente intervalo de tareas.

Personalización de la apariencia de Windows


PowerShell ISE
Puede utilizar el modelo de objetos para modificar las opciones y la configuración de la
aplicación. Por ejemplo, puede modificarlas como sigue:

Cambie el color de los errores, las advertencias, los resultados detallados y los
resultados de depuración.
Obtenga o establezca los colores de fondo del panel de comandos, del panel de
resultados y del panel de scripts.
Establezca el color de primer plano del panel de resultados.
Establezca el nombre y el tamaño de la fuente para Windows PowerShell ISE.
Configure advertencias. Esta configuración incluye advertencias que se emiten
cuando se abre un archivo en varias pestañas de PowerShell o cuando se ejecuta
un script en el archivo antes de que se haya guardado el archivo.
Cambie entre una vista en la que el panel de scripts y el panel de resultados se
encuentran en paralelo y una vista en la que el panel de scripts está en la parte
superior del panel de resultados.
Acople el panel de comandos en la parte inferior o superior del panel de
resultados.

Mejora de la funcionalidad de Windows


PowerShell ISE
Puede utilizar el modelo de objetos para mejorar la funcionalidad de Windows
PowerShell ISE. Por ejemplo, puede:
Agregar y modificar la instancia del mismo Windows PowerShell ISE. Por ejemplo,
para cambiar los menús, puede agregar nuevos elementos de menú y asignarlos a
scripts.
Crear scripts que llevan a cabo algunas de las tareas que puede realizar mediante
el uso de los botones y comandos de menú en Windows PowerShell ISE. Por
ejemplo, puede agregar, quitar o seleccionar una pestaña de PowerShell.
Complementar tareas que se pueden realizar con el uso de botones y comandos
de menú. Por ejemplo, puede cambiar el nombre de una pestaña de PowerShell.
Manipular los búferes de texto para el panel de comandos, el panel de resultados y
el panel de scripts que están asociados a un archivo. Por ejemplo, puede:
Obtener o establecer todo el texto.
Obtener o establecer una selección de texto.
Ejecutar un script o una parte seleccionada de un script.
Desplazar una línea en la vista.
Insertar texto en una posición de intercalación.
Seleccionar un bloque de texto.
Obtener el último número de línea.
Realizar operaciones de archivo. Por ejemplo, puede:
Abrir un archivo, guardar un archivo o guardar un archivo con un nombre
diferente.
Determinar si un archivo ha cambiado desde que se guardó por última vez.
Obtener el nombre de archivo.
Seleccionar un archivo.

Automatización de tareas
Puede utilizar el modelo de objetos de scripting para crear métodos abreviados de
teclado para operaciones frecuentes.

Vea también
La jerarquía del modelo de objetos de ISE
La jerarquía del modelo de objetos de
ISE
Artículo • 21/03/2023

En este artículo se muestra la jerarquía de objetos que forman parte del Entorno de
scripting integrado (ISE) de Windows PowerShell. Windows PowerShell ISE se incluye en
Windows PowerShell 3.0, 4.0 y 5.1. Haga clic en un objeto para ir a la documentación de
referencia de la clase que define el objeto.

Objeto $psISE
El objeto $psISE es el objeto raíz de la jerarquía de objetos de Windows PowerShell ISE.
Ubicado en el nivel superior, este objeto hace que estén disponibles para scripting los
objetos siguientes:

$psISE.CurrentFile
El objeto $psISE.CurrentFile es una instancia de la clase ISEFile.

$psISE.CurrentPowerShellTab
El objeto $psISE.CurrentPowerShellTab es una instancia de la clase PowerShellTab.

$psISE.CurrentVisibleHorizontalTool
El objeto $psISE.CurrentVisibleHorizontalTool es una instancia de la clase
ISEAddOnTool. Representa la herramienta de complemento instalada que actualmente
está acoplada al borde superior de la ventana de Windows PowerShell ISE.

$psISE.CurrentVisibleVerticalTool
El objeto $psISE.CurrentVisibleHorizontalTool es una instancia de la clase
ISEAddOnTool. Representa la herramienta de complemento instalada que actualmente
está acoplada al borde derecho de la ventana de Windows PowerShell ISE.

$psISE.Options
El objeto $psISE.Options es una instancia de la clase ISEOptions. El objeto ISEOptions
representa distintas configuraciones de Windows PowerShell ISE. Es una instancia de la
clase Microsoft.PowerShell.Host.ISE.ISEOptions.

$psISE.PowerShellTabs
El objeto $psISE.PowerShellTabs es una instancia de la clase PowerShellTabCollection. Es
una colección de todas las pestañas de PowerShell abiertas actualmente que
representan los entornos de ejecución de Windows PowerShell disponibles en el equipo
local o en equipos remotos conectados. Cada miembro de la colección es una instancia
de la clase PowerShellTab.

Consulte también
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ObjectModelRoot
Artículo • 21/03/2023

El objeto $psISE , que es el objeto raíz de entidad de seguridad en


Windows PowerShell® ISE, es una instancia de la clase
Microsoft.PowerShell.Host.ISE.ObjectModelRoot. En este tema se describen las
propiedades del objeto ObjectModelRoot.

Propiedades

CurrentFile
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el archivo, que está asociado a este objeto
host que tiene actualmente el foco.

CurrentPowerShellTab
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene de la pestaña de PowerShell que tiene el foco.

CurrentVisibleHorizontalTool
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la herramienta de complemento de Windows


PowerShell ISE actualmente visible que se encuentra en el panel de herramientas
horizontal en la parte inferior del editor.

CurrentVisibleVerticalTool
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la herramienta de complemento de Windows


PowerShell ISE actualmente visible que se encuentra en el panel de herramientas vertical
en el lado derecho del editor.

Opciones
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene las distintas opciones que pueden cambiar la
configuración de Windows PowerShell ISE.

PowerShellTabs
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la colección de las pestañas de PowerShell


que están abiertas en Windows PowerShell ISE. De forma predeterminada, este objeto
contiene una pestaña de PowerShell. Sin embargo, puede agregar más pestañas de
PowerShell a este objeto mediante scripts o mediante los menús de Windows
PowerShell ISE.

Consulte también
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEAddOnToolCollection
Artículo • 21/03/2023

El objeto ISEAddOnToolCollection es una colección de objetos ISEAddOnTool. Un


ejemplo es el objeto $psISE.CurrentPowerShellTab.VerticalAddOnTools .

Métodos

Add( Nombre, TipoDeControl, [IsVisible] )


Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Agrega una nueva herramienta de complemento a la colección. Devuelve la herramienta


de complemento recién agregada. Antes de ejecutar este comando, debe instalar la
herramienta de complemento en el equipo local y cargar el ensamblado.

Name (cadena). Especifica el nombre para mostrar de la herramienta de complemento


que se agrega a Windows PowerShell ISE.

ControlType (tipo). Especifica el control que se agrega.

[IsVisible]: booleano opcional. Si se establece en $true , la herramienta de complemento


es visible inmediatamente en el panel de herramientas asociado.

PowerShell

# Load a DLL with an add-on and then add it to the ISE


[reflection.assembly]::LoadFile("c:\test\ISESimpleSolution\ISESimpleSolution
.dll")
$psISE.CurrentPowerShellTab.VerticalAddOnTools.Add("Solutions",
[ISESimpleSolution.Solution], $true)

Remove( Elemento )
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Quita de la colección la herramienta de complemento especificada.

Item (Microsoft.PowerShell.Host.ISE.ISEAddOnTool). Especifica el objeto que se quitará


de Windows PowerShell ISE.
PowerShell

# Load a DLL with an add-on and then add it to the ISE


[reflection.assembly]::LoadFile("c:\test\ISESimpleSolution\ISESimpleSolution
.dll")
$psISE.CurrentPowerShellTab.VerticalAddOnTools.Add("Solutions",
[ISESimpleSolution.Solution], $true)

SetSelectedPowerShellTab( psTab )
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Selecciona la pestaña de PowerShell que el parámetro psTab especifica.

psTab (Microsoft.PowerShell.Host.ISE.PowerShellTab). La pestaña de PowerShell que se


seleccionará.

PowerShell

$newTab = $psISE.PowerShellTabs.Add()
# Change the DisplayName of the new PowerShell tab.
$newTab.DisplayName = 'Brand New Tab'

Remove( psTab )
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Quita la pestaña de PowerShell que el parámetro psTab especifica.

psTab (Microsoft.PowerShell.Host.ISE.PowerShellTab). La pestaña de PowerShell que se


quitará.

PowerShell

$newTab = $psISE.PowerShellTabs.Add()
Change the DisplayName of the new PowerShell tab.
$newTab.DisplayName = 'This tab will go away in 5 seconds'
sleep 5
$psISE.PowerShellTabs.Remove($newTab)

Consulte también
El objeto PowerShellTab
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEAddOnTool
Artículo • 21/03/2023

Un objeto ISEAddonTool representa una herramienta de complemento instalada que


proporciona funcionalidad adicional al ISE de Windows PowerShell. Un ejemplo es la
herramienta Comandos que se puede mostrar haciendo clic en Ver y, después, en Show
Command Add-on (Mostrar complemento Comandos). Esta herramienta es accesible
mediante la manipulación de los distintos objetos ISEAddOnTool disponibles.

Cada herramienta de complemento se puede asociar al panel vertical o al panel


horizontal. El panel vertical está acoplado al borde derecho de Windows PowerShell ISE.
El panel horizontal está acoplado al borde inferior.

Cada pestaña de PowerShell en Windows PowerShell ISE puede tener instalado su


propio conjunto de herramientas de complemento. Consulte
$psISE.CurrentPowerShellTab.HorizontalAddOnTools y
$psISE.CurrentPowerShellTab.VerticalAddOnTools para tener acceso a la colección de
herramientas disponibles en la pestaña seleccionada actualmente o las mismas
propiedades en cualquiera de los objetos PowerShellTab del objeto de la colección
$psISE.PowerShellTabs.

Métodos
No hay disponible ningún método específico de Windows PowerShell ISE para los
objetos de esta clase.

Propiedades

Control
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

La propiedad Control proporciona acceso de lectura a muchos de los detalles de la


herramienta de complemento Comandos.

PowerShell

# View the properties of the Commands add-on tool.


# (assumes that it is visible in the vertical pane)
$psISE.CurrentVisibleVerticalTool.Control
Output

HostObject : Microsoft.PowerShell.Host.ISE.ObjectModelRoot
Content :
HasContent :
ContentTemplate :
ContentTemplateSelector :
ContentStringFormat :
BorderBrush :
BorderThickness :
Background :
Foreground :
FontFamily :
FontSize :
FontStretch :
FontStyle :
FontWeight :
HorizontalContentAlignment :
VerticalContentAlignment :
TabIndex :
IsTabStop :
Padding :
Template : System.Windows.Controls.ControlTemplate
Style :
OverridesDefaultStyle :
UseLayoutRounding :
Triggers : {}
TemplatedParent :
Resources : {System.Windows.Controls.TabItem}
DataContext :
BindingGroup :
Language :
Name :
Tag :
InputScope :
ActualWidth : 370.75
ActualHeight : 676.559097412109
LayoutTransform :
Width :
MinWidth :
MaxWidth :
Height :
MinHeight :
MaxHeight :
FlowDirection : LeftToRight
Margin :
HorizontalAlignment :
VerticalAlignment :
FocusVisualStyle :
Cursor :
ForceCursor :
IsInitialized : True
IsLoaded :
ToolTip :
ContextMenu :
Parent :
HasAnimatedProperties :
InputBindings :
CommandBindings :
AllowDrop :
DesiredSize : 227.66,676.559097412109
IsMeasureValid : True
IsArrangeValid : True
RenderSize : 370.75,676.559097412109
RenderTransform :
RenderTransformOrigin :
IsMouseDirectlyOver : False
IsMouseOver : False
IsStylusOver : False
IsKeyboardFocusWithin : False
IsMouseCaptured :
IsMouseCaptureWithin : False
IsStylusDirectlyOver : False
IsStylusCaptured :
IsStylusCaptureWithin : False
IsKeyboardFocused : False
IsInputMethodEnabled :
Opacity :
OpacityMask :
BitmapEffect :
Effect :
BitmapEffectInput :
CacheMode :
Uid :
Visibility : Visible
ClipToBounds : False
Clip :
SnapsToDevicePixels : False
IsFocused :
IsEnabled :
IsHitTestVisible :
IsVisible : True
Focusable :
PersistId : 1
IsManipulationEnabled :
AreAnyTouchesOver : False
AreAnyTouchesDirectlyOver :
AreAnyTouchesCapturedWithin : False
AreAnyTouchesCaptured :
TouchesCaptured : {}
TouchesCapturedWithin : {}
TouchesOver : {}
TouchesDirectlyOver : {}
DependencyObjectType : System.Windows.DependencyObjectType
IsSealed : False
Dispatcher : System.Windows.Threading.Dispatcher
IsVisible
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Propiedad booleana que indica si la herramienta de complemento está visible


actualmente en el panel asignado. Si está visible, puede establecer la propiedad
IsVisible en $false para ocultar la herramienta, o bien establecer la propiedad IsVisible
en $true para hacer que una herramienta de complemento esté visible en su pestaña
de PowerShell. Tenga en cuenta que al ocultar una herramienta de complemento, esta
deja de ser accesible a través de los objetos CurrentVisibleHorizontalTool o
CurrentVisibleVerticalTool y, por lo tanto, no puede hacerse visible usando esta
propiedad en ese objeto.

PowerShell

# Hide the current tool in the vertical tool pane


$psISE.CurrentVisibleVerticalTool.IsVisible = $false
# Show the first tool on the currently selected PowerShell tab
$psISE.CurrentPowerShellTab.VerticalAddOnTools[0].IsVisible = $true

Nombre
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Propiedad de solo lectura que obtiene el nombre de la herramienta de complemento.

PowerShell

# Gets the name of the visible vertical pane add-on tool.


$psISE.CurrentVisibleVerticalTool.Name

Output

Commands

Consulte también
El objeto ISEAddOnToolCollection
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEEditor
Artículo • 21/03/2023

Un objeto ISEEditor es una instancia de la clase Microsoft.PowerShell.Host.ISE.ISEEditor.


El panel de consola es un objeto ISEEditor. Cada objeto ISEFile tiene asociado un objeto
ISEEditor. En las secciones siguientes se enumeran los métodos y las propiedades de un
objeto ISEEditor.

Métodos

Clear()
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Borra el texto en el editor.

PowerShell

# Clears the text in the Console pane.


$psISE.CurrentPowerShellTab.ConsolePane.Clear()

EnsureVisible(int númeroDeLínea)
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Desplaza el editor de modo que la línea que corresponde al valor del parámetro
lineNumber especificado está visible. Produce una excepción si el número de línea
especificado está fuera del intervalo de 1, último número de línea, que define los
números de línea válidos.

lineNumber Número de la línea que se debe hacer visible.

PowerShell

# Scrolls the text in the Script pane so that the fifth line is in view.
$psISE.CurrentFile.Editor.EnsureVisible(5)

Focus()
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.
Establece el foco en el editor.

PowerShell

# Sets focus to the Console pane.


$psISE.CurrentPowerShellTab.ConsolePane.Focus()

GetLineLength(int númeroDeLínea )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Obtiene la longitud de línea como un entero de la línea especificada por el número de


línea.

lineNumber Número de la línea de la que se obtendrá la longitud.

Returns Longitud de la línea que corresponde al número de línea especificado.

PowerShell

# Gets the length of the first line in the text of the Command pane.
$psISE.CurrentPowerShellTab.ConsolePane.GetLineLength(1)

GoToMatch()
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Mueve el símbolo de intercalación al carácter coincidente si la propiedad


CanGoToMatch del objeto del editor es $true , lo que ocurre cuando el símbolo de
intercalación está inmediatamente antes de un paréntesis, corchete o llave de apertura
( ( , [ , { ) o inmediatamente después de un paréntesis, corchete o llave de cierre: ) , ] , } .
El símbolo de intercalación se coloca delante de un carácter de apertura o después de
un carácter de cierre. Si la propiedad CanGoToMatch es $false , el método no hace
nada.

PowerShell

# Goes to the matching character if CanGoToMatch() is $true


$psISE.CurrentPowerShellTab.ConsolePane.GoToMatch()

InsertText( texto )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Reemplaza la selección por texto o inserta texto en la posición del símbolo de


intercalación actual.

text (cadena); el texto que se inserta.

Vea Ejemplo de scripting más adelante en este tema.

Select( líneaInicial, columnaInicial, líneaFinal,


columnaFinal )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Selecciona el texto de los parámetros startLine, startColumn, endLine y endColumn.

startLine (entero); la línea donde comienza la selección.

startColumn (entero); la columna de la línea de inicio en que comienza la selección.

endLine (entero); la línea en que acaba la selección.

endColumn (entero); la columna de la línea de fin en que acaba la selección.

Vea Ejemplo de scripting más adelante en este tema.

SelectCaretLine()
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Selecciona toda la línea de texto que contiene actualmente el símbolo de intercalación.

PowerShell

# First, set the caret position on line 5.


$psISE.CurrentFile.Editor.SetCaretPosition(5,1)
# Now select that entire line of text
$psISE.CurrentFile.Editor.SelectCaretLine()

SetCaretPosition( númeroDeLínea, númeroDeColumna )


Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Establece la posición del símbolo de intercalación en el número de línea y el número de


columna. Produce una excepción si el número de línea del símbolo de intercalación o el
número de columna del símbolo de intercalación están fuera de sus intervalos válidos
respectivos.

lineNumber (entero); el número de línea del símbolo de intercalación.

columnNumber (entero); el número de columna del símbolo de intercalación.

PowerShell

# Set the CaretPosition.


$psISE.CurrentFile.Editor.SetCaretPosition(5,1)

ToggleOutliningExpansion()
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Hace que todas las secciones de esquema se expandan o se contraigan.

PowerShell

# Toggle the outlining expansion


$psISE.CurrentFile.Editor.ToggleOutliningExpansion()

Propiedades

CanGoToMatch
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Propiedad booleana de solo lectura que indica si el símbolo de intercalación está al lado
de paréntesis, corchetes o llaves: () , [] , {} . Si el símbolo de intercalación está
inmediatamente antes del carácter de apertura o inmediatamente después del carácter
de cierre de un par, el valor de esta propiedad es $true . De lo contrario, es $false .

PowerShell

# Test to see if the caret is next to a parenthesis, bracket, or brace


$psISE.CurrentFile.Editor.CanGoToMatch
CaretColumn
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Propiedad de solo lectura que obtiene el número de columna que corresponde a la


posición del símbolo de intercalación.

PowerShell

# Get the CaretColumn.


$psISE.CurrentFile.Editor.CaretColumn

CaretLine
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Propiedad de solo lectura que obtiene el número de la línea que contiene el símbolo de
intercalación.

PowerShell

# Get the CaretLine.


$psISE.CurrentFile.Editor.CaretLine

CaretLineText
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Propiedad de solo lectura que obtiene la línea de texto completa que contiene el
símbolo de intercalación.

PowerShell

# Get all of the text on the line that contains the caret.
$psISE.CurrentFile.Editor.CaretLineText

LineCount
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Propiedad de solo lectura que obtiene el recuento de líneas del editor.

PowerShell
# Get the LineCount.
$psISE.CurrentFile.Editor.LineCount

SelectedText
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Propiedad de solo lectura que obtiene el texto seleccionado del editor.

Vea Ejemplo de scripting más adelante en este tema.

Texto
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Propiedad de lectura y escritura que obtiene o establece el texto en el editor.

Vea Ejemplo de scripting más adelante en este tema.

Ejemplo de scripting
PowerShell

# This illustrates how you can use the length of a line to


# select the entire line and shows how you can make it lowercase.
# You must run this in the Console pane. It will not run in the Script pane.
# Begin by getting a variable that points to the editor.
$myEditor = $psISE.CurrentFile.Editor
# Clear the text in the current file editor.
$myEditor.Clear()

# Make sure the file has five lines of text.


$myEditor.InsertText("LINE1 `n")
$myEditor.InsertText("LINE2 `n")
$myEditor.InsertText("LINE3 `n")
$myEditor.InsertText("LINE4 `n")
$myEditor.InsertText("LINE5 `n")

# Use the GetLineLength method to get the length of the third line.
$endColumn = $myEditor.GetLineLength(3)
# Select the text in the first three lines.
$myEditor.Select(1, 1, 3, $endColumn + 1)
$selection = $myEditor.SelectedText
# Clear all the text in the editor.
$myEditor.Clear()
# Add the selected text back, but in lower case.
$myEditor.InsertText($selection.ToLower())
Consulte también
El objeto ISEFile
El objeto PowerShellTab
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEFileCollection
Artículo • 21/03/2023

El objeto ISEFileCollection es una colección de objetos ISEFile. Un ejemplo es la


colección $psISE.CurrentPowerShellTab.Files .

Métodos

Add( [RutaCompleta] )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Crea y devuelve un archivo sin título nuevo y lo agrega a la colección. La propiedad


IsUntitled del archivo recién creado es $true .

[RutaCompleta]: cadena opcional. La ruta completamente especificada del archivo. Se


genera una excepción si incluye el parámetro FullPath y una ruta de acceso relativa, o
bien si utiliza un nombre de archivo en lugar de la ruta de acceso completa.

PowerShell

# Adds a new untitled file to the collection of files in the current


PowerShell tab.
$newFile = $psISE.CurrentPowerShellTab.Files.Add()

# Adds a file specified by its full path to the collection of files in the
current PowerShell tab.
$psISE.CurrentPowerShellTab.Files.Add("$pshome\Examples\profile.ps1")

Remove( Archivo, [Force] )


Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Quita un archivo especificado en la pestaña actual de PowerShell.

File: cadena. Archivo ISEFile que quiere quitar de la colección. Si el archivo no se ha


guardado, este método inicia una excepción. Utilice el parámetro modificador Force
parámetro para forzar la eliminación de un archivo no guardado.

[Force]: booleano opcional. Si se establece en $true , concede permiso para quitar el


archivo incluso si no se ha guardado después del último uso. El valor predeterminado es
$false .
PowerShell

# Removes the first opened file from the file collection associated with the
current PowerShell tab.
# If the file has not yet been saved, then an exception is generated.
$firstfile = $psISE.CurrentPowerShellTab.Files[0]
$psISE.CurrentPowerShellTab.Files.Remove($firstfile)

# Removes the first opened file from the file collection associated with the
current PowerShell tab, even if it has not been saved.
$firstfile = $psISE.CurrentPowerShellTab.Files[0]
$psISE.CurrentPowerShellTab.Files.Remove($firstfile, $true)

SetSelectedFile( archivoSeleccionado )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Selecciona el archivo que especifica el parámetro SelectedFile.

SelectedFile: Microsoft.PowerShell.Host.ISE.ISEFile. Archivo ISEFile que quiere


seleccionar.

PowerShell

# Selects the specified file.


$firstfile = $psISE.CurrentPowerShellTab.Files[0]
$psISE.CurrentPowerShellTab.Files.SetSelectedFile($firstfile)

Consulte también
El objeto ISEFile
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEFile
Artículo • 21/03/2023

Un objeto ISEFile representa un archivo en el Entorno de scripting integrado (ISE) de


Windows PowerShell. Es una instancia de la clase Microsoft.PowerShell.Host.ISE.ISEFile.
Este tema enumera sus métodos de miembro y propiedades de miembro.
$psISE.CurrentFile y los archivos de la colección de archivos en una pestaña de

PowerShell son instancias de la clase **Microsoft.PowerShell.Host.ISE.ISEFile.

Métodos

Save( [codificaciónDeGuardado] )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Guarda el archivo en disco.

[saveEncoding] : System.Text.Encoding opcional. Un parámetro de codificación de

carácter opcional que se usará para el archivo guardado. El valor predeterminado es


UTF8.

Excepciones
System.IO.IOException: no se pudo guardar el archivo.

PowerShell

# Save the file using the default encoding (UTF8)


$psISE.CurrentFile.Save()

# Save the file as ASCII.


$psISE.CurrentFile.Save([System.Text.Encoding]::ASCII)

# Gets the current encoding.


$myfile = $psISE.CurrentFile
$myfile.Encoding

SaveAs(nombreDeArchivo, [codificaciónDeGuardado])
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Guarda el archivo con el nombre de archivo y codificación especificados.


filename: cadena. El nombre que se utilizará para guardar el archivo.

[saveEncoding] : System.Text.Encoding opcional. Un parámetro de codificación de


carácter opcional que se usará para el archivo guardado. El valor predeterminado es
UTF8.

Excepciones
System.ArgumentNullException: el parámetro nombre_de_archivo es null.
System.ArgumentException: el parámetro nombre_de_archivo está vacío.
System.IO.IOException: no se pudo guardar el archivo.

PowerShell

# Save the file with a full path and name.


$fullpath = "c:\temp\newname.txt"
$psISE.CurrentFile.SaveAs($fullPath)
# Save the file with a full path and name and explicitly as UTF8.
$psISE.CurrentFile.SaveAs($fullPath, [System.Text.Encoding]::UTF8)

Propiedades

DisplayName
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la cadena que contiene el nombre para
mostrar de este archivo. El nombre se muestra en la pestaña Archivo en la parte
superior del editor. La presencia de un asterisco (*) al final del nombre indica que el
archivo tiene cambios que no se han guardado.

PowerShell

# Shows the display name of the file.


$psISE.CurrentFile.DisplayName

Editor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el objeto de editor que se utiliza para el
archivo especificado.
PowerShell

# Gets the editor and the text.


$psISE.CurrentFile.Editor.Text

Encoding
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la codificación del archivo original. Se trata de
un objeto System.Text.Encoding.

PowerShell

# Shows the encoding for the file.


$psISE.CurrentFile.Encoding

FullPath
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la cadena que especifica la ruta de acceso
completa del archivo abierto.

PowerShell

# Shows the full path for the file.


$psISE.CurrentFile.FullPath

IsSaved
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad booleana de solo lectura que devuelve $true si el archivo se ha guardado


una vez que se modificó por última vez.

PowerShell

# Determines whether the file has been saved since it was last modified.
$myfile = $psISE.CurrentFile
$myfile.IsSaved
IsUntitled
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que devuelve $true si nunca se asignó un título al archivo.

PowerShell

# Determines whether the file has never been given a title.


$psISE.CurrentFile.IsUntitled
$psISE.CurrentFile.SaveAs("temp.txt")
$psISE.CurrentFile.IsUntitled

Consulte también
ISEFileCollectionObject
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEMenuItemCollection
Artículo • 21/03/2023

Un objeto ISEMenuItemCollection es una colección de objetos ISEMenuItem. Es una


instancia de la clase Microsoft.PowerShell.Host.ISE.ISEMenuItemCollection. Un ejemplo
es el objeto $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus que se usa para
personalizar el menú Complemento en Windows PowerShell® ISE.

Método

Add(string DisplayName,
System.Management.Automation.ScriptBlock Action,
System.Windows.Input.KeyGesture Shortcut )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Agrega un elemento de menú a la colección.

DisplayName El nombre para mostrar del menú que se va a agregar.

Action El objeto System.Management.Automation.ScriptBlock que especifica la acción


que está asociada con este elemento de menú.

Shortcut El método abreviado de teclado para la acción.

Returns El objeto ISEMenuItem que se acaba de agregar.

PowerShell

# Create an Add-ons menu with an fast access key and a shortcut.


# Note the use of "_" as opposed to the "&" for mapping to the fast access
key letter for the menu item.
$menuAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process',
{Get-Process}, 'Alt+P')

Clear()
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Quita todos los submenús del elemento de menú.

PowerShell
# Remove all custom submenu items from the AddOns menu
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()

Consulte también
El objeto ISEMenuItem
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEMenuItem
Artículo • 21/03/2023

Un objeto ISEMenuItem es una instancia de la clase


Microsoft.PowerShell.Host.ISE.ISEMenuItem. Todos los objetos de menú
Complementos son instancias de la clase Microsoft.PowerShell.Host.ISE.ISEMenuItem.

Propiedades

DisplayName
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el nombre para mostrar del elemento de
menú.

PowerShell

# Get the display name of the Add-ons menu item


$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.DisplayName

Acción
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el bloque del script. Invoca la acción al hacer
clic en el elemento de menú.

PowerShell

# Get the action associated with the first submenu item.


$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Action

# Invoke the script associated with the first submenu item


$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Action.Invoke()
Acceso directo
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el método abreviado de teclado de entrada de


Windows para el elemento de menú.

PowerShell

# Get the shortcut for the first submenu item.


$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Shortcut

Submenus
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la lista de submenús del elemento de menú.

PowerShell

# List the submenus of the Add-ons menu


$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus

Ejemplo de scripting
Para entender mejor el uso del menú de complementos y sus propiedades que admiten
scripts, consulte el siguiente ejemplo de scripting.

PowerShell

# This is a scripting example that shows the use of the Add-ons menu.
# Clear the Add-ons menu if any entries currently exist
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()

# Add an Add-ons menu item with an shortcut and fast access key.
# Note the use of "_" as opposed to the "&" for mapping to the fast access
key letter for the menu item.
$menuAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add('_Process',
{Get-Process}, 'Alt+P')
# Add a nested menu - a parent and a child submenu item.
$parentAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('Parent',
$null, $null)
$parentAdded.SubMenus.Add('_Dir', {dir}, 'Alt+D')

Consulte también
El objeto ISEMenuItemCollection
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISEOptions
Artículo • 21/03/2023

El objeto ISEOptions representa distintas configuraciones de Windows PowerShell ISE.


Es una instancia de la clase Microsoft.PowerShell.Host.ISE.ISEOptions.

El objeto ISEOptions proporciona los siguientes métodos y propiedades.

Métodos

RestoreDefaultConsoleTokenColors()
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Restaura los valores predeterminados de los colores de token en el panel de consola.

PowerShell

# Changes the color of the commands in the Console pane to red and then
restores it to its default value.
$psISE.Options.ConsoleTokenColors["Command"] = 'red'
$psISE.Options.RestoreDefaultConsoleTokenColors()

RestoreDefaults()
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Restaura los valores predeterminados de todas las configuraciones de opciones en el


panel de consola. También restablece el comportamiento de varios mensajes de
advertencia que proporcionan la casilla estándar para impedir que el mensaje se
muestre de nuevo.

PowerShell

# Changes the background color in the Console pane and then restores it to
its default value.
$psISE.Options.ConsolePaneBackgroundColor = 'orange'
$psISE.Options.RestoreDefaults()

RestoreDefaultTokenColors()
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Restaura los valores predeterminados de los colores de token en el panel de scripts.

PowerShell

# Changes the color of the comments in the Script pane to red and then
restores it to its default value.
$psISE.Options.TokenColors["Comment"] = 'red'
$psISE.Options.RestoreDefaultTokenColors()

RestoreDefaultXmlTokenColors()
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Restaura los valores predeterminados de los colores de token de elementos XML que se
muestran en Windows PowerShell ISE. Vea también XmlTokenColors.

PowerShell

# Changes the color of the comments in XML data to red and then restores it
to its default value.
$psISE.Options.XmlTokenColors["Comment"] = 'red'
$psISE.Options.RestoreDefaultXmlTokenColors()

Propiedades

AutoSaveMinuteInterval
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica el número de minutos entre operaciones de guardado automático de los


archivos realizadas por Windows PowerShell ISE. El valor predeterminado es 2 minutos.
El valor es un entero.

PowerShell

# Changes the number of minutes between automatic save operations to every 3


minutes.
$psISE.Options.AutoSaveMinuteInterval = 3
CommandPaneBackgroundColor
Esta característica está presente en Windows PowerShell ISE 2.0, pero se quitó o se
cambió de nombre en versiones posteriores del ISE. Para las versiones posteriores, vea
ConsolePaneBackgroundColor.

Especifica el color de fondo para el panel de comandos. Es una instancia de la clase


System.Windows.Media.Color.

PowerShell

# Changes the background color of the Command pane to orange.


$psISE.Options.CommandPaneBackgroundColor = 'orange'

CommandPaneUp
Esta característica está presente en Windows PowerShell ISE 2.0, pero se quitó o se
cambió de nombre en versiones posteriores del ISE.

Especifica si el panel de comandos se encuentra encima del panel de resultados.

PowerShell

# Moves the Command pane to the top of the screen.


$psISE.Options.CommandPaneUp = $true

ConsolePaneBackgroundColor
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica el color de fondo para el panel de consola. Es una instancia de la clase


System.Windows.Media.Color.

PowerShell

# Changes the background color of the Console pane to red.


$psISE.Options.ConsolePaneBackgroundColor = 'red'

ConsolePaneForegroundColor
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica el color de fondo del texto en el panel de consola.

PowerShell

# Changes the foreground color of the text in the Console pane to yellow.
$psISE.Options.ConsolePaneForegroundColor = 'yellow'

ConsolePaneTextBackgroundColor
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica el color de primer plano en el panel de consola.

PowerShell

# Changes the background color of the Console pane text to pink.


$psISE.Options.ConsolePaneTextBackgroundColor = 'pink'

ConsoleTokenColors
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica los colores de los token de IntelliSense en el panel de consola de Windows


PowerShell ISE. Esta propiedad es un objeto de diccionario que contiene pares nombre-
valor de tipos y colores de token para el panel de consola. Para cambiar los colores de
los token de IntelliSense en el panel de scripts, consulte TokenColors. Para restablecer
los valores predeterminados de los colores, consulte RestoreDefaultConsoleTokenColors.
Los colores de token se pueden establecer para lo siguiente: Attribute, Command,
CommandArgument, CommandParameter, Comment, GroupEnd, GroupStart, Keyword,
LineContinuation, LoopLabel, Member, NewLine, Number, Operator, Position,
StatementSeparator, String, Type, Unknown y Variable.

PowerShell

# Sets the color of commands to green.


$psISE.Options.ConsoleTokenColors["Command"] = 'green'
# Sets the color of keywords to magenta.
$psISE.Options.ConsoleTokenColors["Keyword"] = 'magenta'
DebugBackgroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de fondo para el texto de depuración que aparece en el panel de


consola. Es una instancia de la clase System.Windows.Media.Color.

PowerShell

# Changes the background color for the debug text that appears in the
Console pane to blue.
$psISE.Options.DebugBackgroundColor = '#0000FF'

DebugForegroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de primer plano para el texto de depuración que aparece en el panel
de consola. Es una instancia de la clase System.Windows.Media.Color.

PowerShell

# Changes the foreground color for the debug text that appears in the
Console pane to yellow.
$psISE.Options.DebugForegroundColor = 'yellow'

DefaultOptions
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Una colección de propiedades que especifica los valores predeterminados que se


utilizarán cuando se empleen los métodos Reset.

PowerShell

# Displays the name of the default options. This example is from ISE 4.0.
$psISE.Options.DefaultOptions

Output

SelectedScriptPaneState : Top
ShowDefaultSnippets : True
ShowToolBar : True
ShowOutlining : True
ShowLineNumbers : True
TokenColors : {[Attribute, #FF00BFFF],
[Command, #FF0000FF], [CommandArgument, #FF8A2BE2], [CommandParameter,
#FF000080]...}
ConsoleTokenColors : {[Attribute, #FFB0C4DE],
[Command, #FFE0FFFF], [CommandArgument, #FFEE82EE], [CommandParameter,
#FFFFE4B5]...}
XmlTokenColors : {[Comment, #FF006400],
[CommentDelimiter, #FF008000], [ElementName, #FF8B0000], [MarkupExtension,
#FFFF8C00]...}
DefaultOptions :
Microsoft.PowerShell.Host.ISE.ISEOptions
FontSize : 9
Zoom : 100
FontName : Lucida Console
ErrorForegroundColor : #FFFF0000
ErrorBackgroundColor : #00FFFFFF
WarningForegroundColor : #FFFF8C00
WarningBackgroundColor : #00FFFFFF
VerboseForegroundColor : #FF00FFFF
VerboseBackgroundColor : #00FFFFFF
DebugForegroundColor : #FF00FFFF
DebugBackgroundColor : #00FFFFFF
ConsolePaneBackgroundColor : #FF012456
ConsolePaneTextBackgroundColor : #FF012456
ConsolePaneForegroundColor : #FFF5F5F5
ScriptPaneBackgroundColor : #FFFFFFFF
ScriptPaneForegroundColor : #FF000000
ShowWarningForDuplicateFiles : True
ShowWarningBeforeSavingOnRun : True
UseLocalHelp : True
AutoSaveMinuteInterval : 2
MruCount : 10
ShowIntellisenseInConsolePane : True
ShowIntellisenseInScriptPane : True
UseEnterToSelectInConsolePaneIntellisense : True
UseEnterToSelectInScriptPaneIntellisense : True
IntellisenseTimeoutInSeconds : 3

ErrorBackgroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de fondo para el texto de error que aparece en el panel de consola. Es
una instancia de la clase System.Windows.Media.Color.

PowerShell

# Changes the background color for the error text that appears in the
Console pane to black.
$psISE.Options.ErrorBackgroundColor = 'black'
ErrorForegroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de primer plano para el texto de error que aparece en el panel de
consola. Es una instancia de la clase System.Windows.Media.Color.

PowerShell

# Changes the foreground color for the error text that appears in the
console pane to green.
$psISE.Options.ErrorForegroundColor = 'green'

FontName
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el nombre de fuente que se está usando actualmente tanto en el panel de


scripts como en el panel de consola.

PowerShell

# Changes the font used in both panes.


$psISE.Options.FontName = 'Courier New'

FontSize
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el tamaño de fuente como un entero. Se usa en el panel de scripts, en el


panel de comandos y en el panel de salida. El intervalo válido de valores es de 8 a 32.

PowerShell

# Changes the font size in all panes.


$psISE.Options.FontSize = 20

IntellisenseTimeoutInSeconds
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.
Especifica el número de segundos que IntelliSense usa para intentar resolver el texto
escrito actualmente. Transcurrido este número de segundos, el tiempo de espera de
IntelliSense se agota y le permite continuar escribiendo. El valor predeterminado es 3
segundos. El valor es un entero.

PowerShell

# Changes the number of seconds for IntelliSense syntax recognition to 5.


$psISE.Options.IntellisenseTimeoutInSeconds = 5

MruCount
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica el número de archivos abiertos recientemente que Windows PowerShell ISE


sigue y se muestra en la parte inferior del menú Archivo - Abrir. El valor
predeterminado es 10. El valor es un entero.

PowerShell

# Changes the number of recently used files that appear at the bottom of the
File Open menu to 5.
$psISE.Options.MruCount = 5

OutputPaneBackgroundColor
Esta característica está presente en Windows PowerShell ISE 2.0, pero se quitó o se
cambió de nombre en versiones posteriores del ISE. Para las versiones posteriores, vea
ConsolePaneBackgroundColor.

La propiedad de lectura y escritura que obtiene o establece el color de fondo para el


propio panel de resultado. Es una instancia de la clase System.Windows.Media.Color.

PowerShell

# Changes the background color of the Output pane to gold.


$psISE.Options.OutputPaneForegroundColor = 'gold'

OutputPaneTextForegroundColor
Esta característica está presente en Windows PowerShell ISE 2.0, pero se quitó o se
cambió de nombre en versiones posteriores del ISE. Para las versiones posteriores, vea
ConsolePaneForegroundColor.

La propiedad de lectura y escritura que cambia el color de primer plano del texto en el
panel de salida en Windows PowerShell ISE 2.0.

PowerShell

# Changes the foreground color of the text in the Output Pane to blue.
$psISE.Options.OutputPaneTextForegroundColor = 'blue'

OutputPaneTextBackgroundColor
Esta característica está presente en Windows PowerShell ISE 2.0, pero se quitó o se
cambió de nombre en versiones posteriores del ISE. Para las versiones posteriores, vea
ConsolePaneTextBackgroundColor.

La propiedad de lectura y escritura que cambia el color de fondo del texto en el panel
de salida.

PowerShell

# Changes the background color of the Output pane text to pink.


$psISE.Options.OutputPaneTextBackgroundColor = 'pink'

ScriptPaneBackgroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de lectura y escritura que obtiene o establece el color de fondo para los
archivos. Es una instancia de la clase System.Windows.Media.Color.

PowerShell

# Sets the color of the script pane background to yellow.


$psISE.Options.ScriptPaneBackgroundColor = 'yellow'

ScriptPaneForegroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.
La propiedad de lectura y escritura que obtiene o establece el color de primer plano
para archivos que no son de script en el panel de scripts. Para establecer el color de
primer plano para archivos de script, use la propiedad TokenColors.

PowerShell

# Sets the foreground to color of non-script files in the script pane to


green.
$psISE.Options.ScriptPaneBackgroundColor = 'green'

SelectedScriptPaneState
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de lectura y escritura que obtiene o establece la posición del panel de


scripts en la pantalla. La cadena puede ser "Maximized", "Top" o "Right".

PowerShell

# Moves the Script Pane to the top.


$psISE.Options.SelectedScriptPaneState = 'Top'
# Moves the Script Pane to the right.
$psISE.Options.SelectedScriptPaneState = 'Right'
# Maximizes the Script Pane
$psISE.Options.SelectedScriptPaneState = 'Maximized'

ShowDefaultSnippets
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica si la lista de fragmentos de código CTRL + J incluye el conjunto de inicio que


se incluye en Windows PowerShell. Cuando se establece en $false , en la lista CTRL + J

solo aparecen los fragmentos de código definidos por el usuario. El valor


predeterminado es $true .

PowerShell

# Hide the default snippets from the CTRL+J list.


$psISE.Options.ShowDefaultSnippets = $false

ShowIntellisenseInConsolePane
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica si IntelliSense ofrece sugerencias de sintaxis, parámetros y valores en el panel


de consola. El valor predeterminado es $true .

PowerShell

# Turn off IntelliSense in the console pane.


$psISE.Options.ShowIntellisenseInConsolePane = $false

ShowIntellisenseInScriptPane
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica si IntelliSense ofrece sugerencias de sintaxis, parámetros y valores en el panel


de scripts. El valor predeterminado es $true .

PowerShell

# Turn off IntelliSense in the Script pane.


$psISE.Options.ShowIntellisenseInScriptPane = $false

ShowLineNumbers
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica si el panel de scripts muestra los números de línea en el margen izquierdo. El


valor predeterminado es $true .

PowerShell

# Turn off line numbers in the Script pane.


$psISE.Options.ShowLineNumbers = $false

ShowOutlining
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.
Especifica si el panel de scripts muestra corchetes expandibles y que se puedan contraer
junto a las secciones de código en el margen izquierdo. Cuando se muestren, puede
hacer clic en los iconos de signo menos - junto a un bloque de texto para contraerlo o
en el icono de signo más + para expandir un bloque de texto. El valor predeterminado
es $true .

PowerShell

# Turn off outlining in the Script pane.


$psISE.Options.ShowOutlining = $false

ShowToolBar
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica si la barra de herramientas de ISE aparece en la parte superior de la ventana


de Windows PowerShell ISE. El valor predeterminado es $true .

PowerShell

# Show the toolbar.


$psISE.Options.ShowToolBar = $true

ShowWarningBeforeSavingOnRun
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica si aparece un mensaje de advertencia cuando un script se guarda


automáticamente antes de ejecutarse. El valor predeterminado es $true .

PowerShell

# Enable the warning message when an attempt


# is made to run a script without saving it first.
$psISE.Options.ShowWarningBeforeSavingOnRun = $true

ShowWarningForDuplicateFiles
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica si aparece un mensaje de advertencia cuando se abre el mismo archivo en


diferentes pestañas de PowerShell. Si se establece en $true , para abrir el mismo archivo
en varias pestañas se muestra este mensaje: "Una copia de este archivo está abierta en
otra pestaña de Windows PowerShell. Los cambios realizados en este archivo afectarán a
todas las copias abiertas". El valor predeterminado es $true .

PowerShell

# Enable the warning message when a file is


# opened in multiple PowerShell tabs.
$psISE.Options.ShowWarningForDuplicateFiles = $true

TokenColors
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica los colores de los token de IntelliSense en el panel de scripts de Windows


PowerShell ISE. Esta propiedad es un objeto de diccionario que contiene pares nombre-
valor de tipos y colores de token para el panel de scripts. Para cambiar los colores de los
token de IntelliSense en el panel de consola, consulte ConsoleTokenColors. Para
restablecer los valores predeterminados de los colores, consulte
RestoreDefaultTokenColors. Los colores de token se pueden establecer para lo siguiente:
Attribute, Command, CommandArgument, CommandParameter, Comment, GroupEnd,
GroupStart, Keyword, LineContinuation, LoopLabel, Member, NewLine, Number,
Operator, Position, StatementSeparator, String, Type, Unknown y Variable.

PowerShell

# Sets the color of commands to green.


$psISE.Options.TokenColors["Command"] = "green"
# Sets the color of keywords to magenta.
$psISE.Options.TokenColors["Keyword"] = "magenta"

UseEnterToSelectInConsolePaneIntellisense
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica si se puede utilizar la tecla Entrar para seleccionar un opción proporcionada


por IntelliSense en el panel de consola. El valor predeterminado es $true .

PowerShell

# Turn off using the ENTER key to select an IntelliSense provided option in
the Console pane.
$psISE.Options.UseEnterToSelectInConsolePaneIntellisense = $false

UseEnterToSelectInScriptPaneIntellisense
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica si se puede utilizar la tecla Entrar para seleccionar un opción proporcionada


por IntelliSense en el panel de scripts. El valor predeterminado es $true .

PowerShell

# Turn on using the Enter key to select an IntelliSense provided option in


the Console pane.
$psISE.Options.UseEnterToSelectInConsolePaneIntellisense = $true

UseLocalHelp
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica si la Ayuda instalada localmente o la Ayuda en línea aparecen cuando se


presiona F1 con el cursor situado en una palabra clave. Si establece en $true , una
ventana emergente muestra el contenido de la Ayuda instalada localmente. Puede
instalar los archivos de la Ayuda ejecutando el comando Update-Help . Si se establece en
$false , el explorador se abre en una página de Microsoft Learn.

PowerShell

# Sets the option for the online help to be displayed.


$psISE.Options.UseLocalHelp = $false
# Sets the option for the local Help to be displayed.
$psISE.Options.UseLocalHelp = $true

VerboseBackgroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de fondo para el texto detallado que aparece en el panel de consola.
Es un objeto System.Windows.Media.Color.

PowerShell
# Changes the background color for verbose text to blue.
$psISE.Options.VerboseBackgroundColor ='#0000FF'

VerboseForegroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de primer plano para el texto detallado que aparece en el panel de
consola. Es un objeto System.Windows.Media.Color.

PowerShell

# Changes the foreground color for verbose text to yellow.


$psISE.Options.VerboseForegroundColor = 'yellow'

WarningBackgroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de fondo para el texto de advertencia que aparece en el panel de


consola. Es un objeto System.Windows.Media.Color.

PowerShell

# Changes the background color for warning text to blue.


$psISE.Options.WarningBackgroundColor = '#0000FF'

WarningForegroundColor
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Especifica el color de primer plano para el texto de advertencia que aparece en el panel
de salida. Es un objeto System.Windows.Media.Color.

PowerShell

# Changes the foreground color for warning text to yellow.


$psISE.Options.WarningForegroundColor = 'yellow'

XmlTokenColors
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica un objeto de diccionario que contiene pares nombre-valor de tipos y colores


de token para el contenido XML que se muestra en Windows PowerShell ISE. Los colores
de token se pueden establecer para lo siguiente: Attribute, Command,
CommandArgument, CommandParameter, Comment, GroupEnd, GroupStart, Keyword,
LineContinuation, LoopLabel, Member, NewLine, Number, Operator, Position,
StatementSeparator, String, Type, Unknown y Variable. Consulte también
RestoreDefaultXmlTokenColors.

PowerShell

# Sets the color of XML element names to green.


$psISE.Options.XmlTokenColors["ElementName"] = 'green'
# Sets the color of XML comments to magenta.
$psISE.Options.XmlTokenColors["Comment"] = 'magenta'

Zoom
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Especifica el tamaño relativo del texto en los paneles de consola y scripts. El valor
predeterminado es 100. Los valores más pequeños hacen que el texto de Windows
PowerShell ISE sea menor, mientras que números más grandes hacen que el texto
aparezca más grande. El valor es un entero comprendido entre 20 y 400.

PowerShell

# Changes the text in the Windows PowerShell ISE to be double its normal
size.
$psISE.Options.Zoom = 200

Consulte también
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto ISESnippetCollection
Artículo • 21/03/2023

El objeto ISESnippetCollection es una colección de objetos ISESnippet. La colección de


archivos que está asociada con un objeto PowerShellTab es un miembro de esta clase.
Un ejemplo es la colección $psISE.CurrentPowerShellTab.Files .

Métodos

Load( FilePathName )
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Carga un archivo .snippets.ps1xml que contiene fragmentos de código definidos por el


usuario. La manera más fácil de crear fragmentos de código es usar el cmdlet New-
IseSnippet , que los almacena automáticamente en la carpeta de perfil para que se

carguen cada vez que inicie Windows PowerShell ISE.

FilePathName (cadena). La ruta de acceso y el nombre de un archivo .snippets.ps1xml


que contiene las definiciones de fragmento de código.

PowerShell

# Loads a custom snippet file into the current PowerShell tab.


$SnipFile = Join-Path ( Split-Path $profile)
'Snippets\MySnips.snippets.ps1xml'
$psISE.CurrentPowerShellTab.Snippets.Add($SnipPath)

Consulte también
ISESnippetObject
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
ISESnippetObject
Artículo • 21/03/2023

Un objeto ISESnippet es una instancia de la clase


Microsoft.PowerShell.Host.ISE.ISESnippet. Todos los miembros de la colección
$psISE.CurrentPowerShellTab.Snippets son ejemplos de objetos ISESnippet. La manera
más fácil de crear un fragmento de código es usar el cmdlet New-IseSnippet.

Propiedades

Autor
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

La propiedad de solo lectura que obtiene el nombre del autor del fragmento de código.

PowerShell

# Get the author of the first snippet item


$psISE.CurrentPowerShellTab.Snippets.Item(0).Author

CodeFragment
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

La propiedad de solo lectura que obtiene el fragmento de código que va a insertar en el


editor.

PowerShell

# Get the code fragment associated with the first snippet item.
$psISE.CurrentPowerShellTab.Snippets.Item(0).CodeFragment

Acceso directo
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.
La propiedad de solo lectura que obtiene el método abreviado de teclado de Windows
para el elemento de menú.

PowerShell

# Get the shortcut for the first submenu item.


$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Clear()
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus.Add('_Process', {Get-
Process}, 'Alt+P')
$psISE.CurrentPowerShellTab.AddOnsMenu.Submenus[0].Shortcut

Consulte también
El objeto ISESnippetCollection
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto PowerShellTabCollection
Artículo • 21/03/2023

El objeto de colección PowerShellTab es una colección de objetos PowerShellTab. Cada objeto


PowerShellTab funciona como un entorno de runtime independiente. Es una instancia de la clase
Microsoft.PowerShell.Host.ISE.PowerShellTabs. Un ejemplo es el objeto $psISE.PowerShellTabs .

Métodos

Add()
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Agrega una nueva pestaña de PowerShell a la colección. Devuelve la pestaña recién agregada.

PowerShell

$newTab = $psISE.PowerShellTabs.Add()
$newTab.DisplayName = 'Brand New Tab'

Remove(Microsoft.PowerShell.Host.ISE.PowerShellTab psTab)
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Quita la pestaña especificada por el parámetro psTab.

psTab Pestaña de PowerShell que se quitará.

PowerShell

$newTab = $psISE.PowerShellTabs.Add()
Change the DisplayName of the new PowerShell tab.
$newTab.DisplayName = 'This tab will go away in 5 seconds'
sleep 5
$psISE.PowerShellTabs.Remove($newTab)

SetSelectedPowerShellTab(Microsoft.PowerShell.Host.ISE.PowerShellTab
psTab)
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Selecciona la pestaña de PowerShell especificada por el parámetro psTab para que sea la pestaña
activa de PowerShell.

psTab Pestaña de PowerShell que se seleccionará.

PowerShell
# Save the current tab in a variable and rename it
$oldTab = $psISE.CurrentPowerShellTab
$psISE.CurrentPowerShellTab.DisplayName = 'Old Tab'
# Create a new tab and give it a new display name
$newTab = $psISE.PowerShellTabs.Add()
$newTab.DisplayName = 'Brand New Tab'
# Switch back to the original tab
$psISE.PowerShellTabs.SelectedPowerShellTab = $oldTab

Consulte también
El objeto PowerShellTab
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
El objeto PowerShellTab
Artículo • 21/03/2023

El objeto PowerShellTab representa un entorno de runtime de Windows PowerShell.

Métodos

Invoke( Script )
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

Ejecuta el script especificado en la pestaña de PowerShell.

7 Nota

Este método solo funciona en otras pestañas de PowerShell, no en la pestaña de


PowerShell desde la que se ejecuta. No devuelve ningún objeto o valor. Si el código
modifica cualquier variable, esos cambios se conservan en la pestaña en la que se
invocó el comando.

Script: System.Management.Automation.ScriptBlock o cadena. El bloque de script para


ejecutar.

PowerShell

# Manually create a second PowerShell tab before running this script.


# Return to the first PowerShell tab and type the following command
$psISE.PowerShellTabs[1].Invoke({dir})

InvokeSynchronous( Script, [usarNuevoÁmbito],


tiempoDeEsperaEnMilisegundos )
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

Ejecuta el script especificado en la pestaña de PowerShell.

7 Nota
Este método solo funciona en otras pestañas de PowerShell, no en la pestaña de
PowerShell desde la que se ejecuta. El bloque de script se ejecuta y cualquier valor
que se devuelve desde el script se devuelve al entorno de ejecución desde el que
se invocó el comando. Si el comando tarda más tiempo en ejecutarse que lo que
especifica el valor de millesecondsTimeout, el comando no se ejecuta
correctamente e inicia una excepción: "La operación ha agotado el tiempo de
espera".

Script: System.Management.Automation.ScriptBlock o cadena. El bloque de script para


ejecutar.

[usarNuevoÁmbito]: booleano opcional cuyo valor predeterminado es $true . Si está


establecido en $true , se crea un ámbito en el que ejecutar el comando. No modifica el
entorno de tiempo de ejecución de la pestaña de PowerShell que se especifica mediante
el comando.

[tiempoDeEsperaEnMilisegundos]: entero opcional cuyo valor predeterminado es 500.


Si el comando no finaliza dentro del tiempo especificado, inicia TimeoutException con
el mensaje "La operación ha agotado el tiempo de espera.".

PowerShell

# Create a new PowerShell tab and then switch back to the first
$psISE.PowerShellTabs.Add()
$psISE.PowerShellTabs.SetSelectedPowerShellTab($psISE.PowerShellTabs[0])

# Invoke a simple command on the other tab, in its own scope


$psISE.PowerShellTabs[1].InvokeSynchronous('$x=1', $false)
# You can switch to the other tab and type '$x' to see that the value is
saved there.

# This example sets a value in the other tab (in a different scope)
# and returns it through the pipeline to this tab to store in $a
$a = $psISE.PowerShellTabs[1].InvokeSynchronous('$z=3;$z')
$a

# This example runs a command that takes longer than the allowed timeout
value
# and measures how long it runs so that you can see the impact
Measure-Command {$psISE.PowerShellTabs[1].InvokeSynchronous('sleep 10',
$false, 5000)}

Propiedades
AddOnsMenu
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el menú Complementos para la pestaña de


PowerShell.

PowerShell

# Clear the Add-ons menu if one exists.


$psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Clear()
# Create an AddOns menu with an accessor.
# Note the use of "_" as opposed to the "&" for mapping to the fast key
letter for the menu item.
$menuAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add('_Process',
{Get-Process}, 'Alt+P')
# Add a nested menu.
$parentAdded = $psISE.CurrentPowerShellTab.AddOnsMenu.SubMenus.Add('Parent',
$null, $null)
$parentAdded.SubMenus.Add('_Dir', {dir}, 'Alt+D')
# Show the Add-ons menu on the current PowerShell tab.
$psISE.CurrentPowerShellTab.AddOnsMenu

CanInvoke
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad booleana de solo lectura que devuelve un valor $true si se puede invocar
un script con el método Invoke( Script ).

PowerShell

# CanInvoke will be false if the PowerShell


# tab is running a script that takes a while, and you
# check its properties from another PowerShell tab. It is
# always false if checked on the current PowerShell tab.
# Manually create a second PowerShell tab before running this script.
# Return to the first tab and type
$secondTab = $psISE.PowerShellTabs[1]
$secondTab.CanInvoke
$secondTab.Invoke({sleep 20})
$secondTab.CanInvoke

ConsolePane
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores. En Windows PowerShell ISE 2.0 esto se llamaba CommandPane.
La propiedad de solo lectura que obtiene el objeto editor del panel de consola.

PowerShell

# Gets the Console Pane editor.


$psISE.CurrentPowerShellTab.ConsolePane

DisplayName
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de lectura y escritura que obtiene o establece el texto que se muestra en


la pestaña de PowerShell. De forma predeterminada, las pestañas se denominan
"PowerShell #", donde # representa un número.

PowerShell

$newTab = $psISE.PowerShellTabs.Add()
# Change the DisplayName of the new PowerShell tab.
$newTab.DisplayName = 'Brand New Tab'

ExpandedScript
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad booleana de lectura y escritura que determina si el panel de scripts se


expande o se oculta.

PowerShell

# Toggle the expanded script property to see its effect.


$psISE.CurrentPowerShellTab.ExpandedScript =
!$psISE.CurrentPowerShellTab.ExpandedScript

Archivos
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene la colección de archivos de scripts que están
abiertos en la pestaña de PowerShell.

PowerShell
$newFile = $psISE.CurrentPowerShellTab.Files.Add()
$newFile.Editor.Text = "a`r`nb"
# Gets the line count
$newFile.Editor.LineCount

Output
Esta característica está presente en Windows PowerShell ISE 2.0, pero se quitó o se
cambió de nombre en versiones posteriores del ISE. En versiones posteriores de
Windows PowerShell ISE, puede usar el objeto ConsolePane con el mismo propósito.

La propiedad de solo lectura que obtiene el panel de salida del editor actual .

PowerShell

# Clears the text in the Output pane.


$psISE.CurrentPowerShellTab.output.clear()

Prompt
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el texto de la petición actual. Nota: El perfil del
usuario puede reemplazar a la función Prompt. Si el resultado es distinto de una cadena
simple, esta propiedad no devuelve nada.

PowerShell

# Gets the current prompt text.


$psISE.CurrentPowerShellTab.Prompt

ShowCommands
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

La propiedad de lectura y escritura que indica si actualmente se muestra el panel de


comandos.

PowerShell

# Gets the current status of the Commands pane and stores it in the $a
variable
$a = $psISE.CurrentPowerShellTab.ShowCommands
# if $a is $false, then turn the Commands pane on by changing the value to
$true
if (!$a) {$psISE.CurrentPowerShellTab.ShowCommands = $true}

StatusText
Se admite en Windows PowerShell ISE 2.0 y versiones posteriores.

La propiedad de solo lectura que obtiene el texto de estado de PowerShellTab.

PowerShell

# Gets the current status text,


$psISE.CurrentPowerShellTab.StatusText

HorizontalAddOnToolsPaneOpened
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

La propiedad de solo lectura que indica si el panel de herramientas de complementos


horizontal está abierto actualmente.

PowerShell

# Gets the current state of the horizontal Add-ons tool pane.


$psISE.CurrentPowerShellTab.HorizontalAddOnToolsPaneOpened

VerticalAddOnToolsPaneOpened
Se admite en Windows PowerShell ISE 3.0 y versiones posteriores y no está presente en
las versiones anteriores.

La propiedad de solo lectura que indica si el panel de herramientas de complementos


vertical está abierto actualmente.

PowerShell

# Turns on the Commands pane


$psISE.CurrentPowerShellTab.ShowCommands = $true
# Gets the current state of the vertical Add-ons tool pane.
$psISE.CurrentPowerShellTab.HorizontalAddOnToolsPaneOpened
Consulte también
El objeto PowerShellTabCollection
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
La jerarquía del modelo de objetos de ISE
Otros objetos de scripting útiles
Artículo • 21/03/2023

Los objetos siguientes proporcionan funcionalidad adicional de scripting de Windows


PowerShell ISE. No forman parte de la jerarquía de $psISE.

Objetos de scripting útiles

$psUnsupportedConsoleApplications
Existen algunas limitaciones sobre cómo Windows PowerShell ISE interactúa con las
aplicaciones de consola. Un comando o un script de automatización que requiere la
intervención de usuario podrían no funcionar de la misma forma que desde la consola
de Windows PowerShell. Puede bloquear la ejecución de estos comandos o scripts en el
panel de comandos de Windows PowerShell ISE. El objeto
$psUnsupportedConsoleApplications mantiene una lista de estos comandos. Si intenta
ejecutar los comandos de esta lista, recibirá un mensaje donde se indica que no son
compatibles. El siguiente script agrega una entrada a la lista.

PowerShell

# List the unsupported commands


$psUnsupportedConsoleApplications

# Add a command to this list


$psUnsupportedConsoleApplications.Add('Mycommand')

# Show the augmented list of commands


$psUnsupportedConsoleApplications

$psLocalHelp
Se trata de un objeto de diccionario que mantiene una asignación contextual entre los
temas de Ayuda y sus vínculos asociados en el archivo de Ayuda HTML compilado local.
Se utiliza para buscar la Ayuda local para un tema determinado. Puede agregar o
eliminar los temas de esta lista. En el ejemplo de código siguiente se muestran algunos
pares clave-valor de ejemplo que se encuentran en $psLocalHelp .

PowerShell
# See the local help map
$psLocalHelp | Format-List

Output

Key : Add-Computer
Value : WindowsPowerShellHelp.chm::/html/093f660c-b8d5-43cf-aa0c-
54e5e54e76f9.htm

Key : Add-Content
Value : WindowsPowerShellHelp.chm::/html/0c836a1b-f389-4e9a-9325-
0f415686d194.htm

El siguiente script agrega una entrada a la lista.

PowerShell

$psLocalHelp.Add("get-myNoun", "c:\MyFolder\MyHelpChm.chm::/html/0198854a-
1298-57ae-aa0c-87b5e5a84712.htm")

$psOnlineHelp
Se trata de un objeto de diccionario que mantiene una asignación contextual entre los
títulos de los temas de Ayuda y sus direcciones URL externas asociadas. Se utiliza para
buscar la Ayuda para un tema determinado en la Web. Puede agregar o eliminar los
temas de esta lista.

PowerShell

$psOnlineHelp | Format-List

Output

Key : Add-Computer
Value : https://go.microsoft.com/fwlink/p/?LinkID=135194

Key : Add-Content
Value : https://go.microsoft.com/fwlink/p/?LinkID=113278

El siguiente script agrega una entrada a la lista.

PowerShell

$psOnlineHelp.Add("get-myNoun", "https://www.mydomain.com/MyNoun.html")
Consulte también
Finalidad del modelo de objetos de scripting de Windows PowerShell ISE
Windows Management Framework
Artículo • 13/09/2023

Windows Management Framework (WMF) proporciona una interfaz de administración


coherente para Windows. WMF proporciona una manera óptima de administrar varias
versiones de cliente de Windows y de Windows Server. Los paquetes de instalador de
WMF contienen actualizaciones para la funcionalidad de administración y están
disponibles para versiones anteriores de Windows.

La instalación de WMF permite agregar o actualizar las características siguientes:

Windows PowerShell
Configuración de estado deseado (DSC) de Windows PowerShell
Windows PowerShell Integrated Script Environment (ISE)
Administración remota de Windows (WinRM)
Instrumental de administración de Windows (WMI)
Windows PowerShell Web Services (Extensión IIS Management OData)
Registro de inventario de software (SIL)
Proveedor de CIM del administrador del servidor

Notas de la versión WMF


Para más información acerca de las diversas mejoras en PowerShell y en otros
componentes de un determinado WMF, consulte los vínculos siguientes para revisar las
notas de la versión:

WMF 5.1
WMF 5.0

Disponibilidad de WMF entre sistemas


operativos Windows
Versión del SO. Fin del WMF 5.1 WMF 5.0 WMF WMF WMF
soporte 4.0 3.0 2.0

Windows Server 2022 2031-10- Se


14 incluye

Windows Server 2019 2029-01- Se


09 incluye
Versión del SO. Fin del WMF 5.1 WMF 5.0 WMF WMF WMF
soporte 4.0 3.0 2.0

Windows Server 2016 2027-01- Se


11 incluye

Windows 11 2025-10- Se
14 incluye

Windows 10 2025-10- Incluido Se incluye


14 en 1607+ (reemplazado
en 1607)

Windows Server 2012 2023-10- Sí Sí Se


R2 10 incluye

Windows 8.1 Fuera de Sí Sí Se


soporte incluye
técnico

Windows Server 2012 2023-10- Sí Sí Sí Se


10 incluye

Windows 8 Fuera de Se
soporte incluye
técnico

Windows Server 2008 Fuera de Sí Sí Sí Sí Se


R2 SP1 soporte incluye
técnico

Windows 7 SP1 Fuera de Sí Sí Sí Sí Se


soporte incluye
técnico

Windows Server 2008 Fuera de Sí Sí


SP2 soporte
técnico

Windows Vista Fuera de Sí


soporte
técnico

Windows Server 2003 Fuera de Sí


soporte
técnico

Windows XP Fuera de Sí Sí
soporte
técnico
Se incluye: las características de la versión especificada de WMF se han enviado en
la versión indicada del cliente de Windows o Windows Server.
Fuera de soporte técnico: estos productos ya no son compatibles con Microsoft.
Tiene que actualizar a una versión compatible. Para obtener más información, vea
la página de la directiva de ciclo de vida de Microsoft .

7 Nota

La versión de WMF que se incluye en un sistema operativo es compatible con la


duración de la compatibilidad con esa versión del sistema operativo. Los
instaladores independientes para WMF 5.0 y versiones anteriores ya no están
disponibles ni son compatibles.

6 Collaborate with us on PowerShell


GitHub
A cross-platform task automation
The source for this content can solution made up of a command-
be found on GitHub, where you line shell and a scripting language.
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Instalación y configuración de WMF 5.1
Artículo • 13/04/2023

) Importante

WMF 5.0 se reemplazó por WMF 5.1. Los usuarios que tengan WMF 5.0 deben
actualizarlo a WMF 5.1 para poder recibir soporte técnico. WMF 5.1 necesita .NET
Framework 4.5.2 (o una versión superior). La instalación se realizará correctamente,
pero se producirá un error en las características clave si .NET 4.5.2 (o una versión
superior) no está instalado.

Descarga e instalación del paquete WMF 5.1


Descargue el paquete WMF 5.1 para el sistema operativo y la arquitectura en la que se
va a instalar en:

Sistema operativo Prerrequisitos Vínculos de paquete

Windows Server 2012 Win8.1AndW2K12R2-KB3191564-x64.msu


R2

Windows Server 2012 W2K12-KB3191565-x64.msu

Windows Server 2008 .NET Framework Win7AndW2K8R2-KB3191566-x64.ZIP


R2 4.5.2

Windows 8.1 x64:Win8.1AndW2K12R2-KB3191564-


x64.msu
x86:Win8.1-KB3191564-x86.msu

Windows 7 SP1 .NET Framework x64:Win7AndW2K8R2-KB3191566-x64.ZIP


4.5.2 x86:Win7-KB3191566-x86.ZIP

Hay que desinstalar la versión preliminar de WMF 5.1 antes de instalar WMF 5.1
RTM.
WMF 5.1 puede instalarse directamente sobre WMF 5.0 o WMF 4.0.
No es necesario instalar WMF 4.0 antes de instalar WMF 5.1 en Windows 7 y
Windows Server 2008 R2.

Instalación de WMF 5.1 para Windows Server


2008 R2 y Windows 7
7 Nota

Las instrucciones de instalación de Windows Server 2008 R2 y Windows 7 han


cambiado y se diferencian de las instrucciones para los otros paquetes. Las
instrucciones de instalación de Windows Server 2012 R2, Windows Server 2012 y
Windows 8.1 se indican a continuación.

Requisitos previos de WMF 5.1 para


Windows Server 2008 R2 SP1 y Windows 7 SP1
La instalación de WMF 5.1 en Windows Server 2008 R2 SP1 o Windows 7 SP1, requiere
lo siguiente:

Debe instalarse el service pack más reciente.


WMF 3.0 no debe instalarse. La instalación de WMF 5.1 en WMF 3.0 provocará la
pérdida de PSModulePath ( $env:PSModulePath ), lo que puede producir errores en
otras aplicaciones. Antes de instalar WMF 5.1, debe desinstalar WMF 3.0 o guardar
PSModulePath y restaurarlo manualmente una vez completada la instalación de
WMF 5.1.
WMF 5.1 requiere al menos .NET Framework 4.5.2 . Puede instalar Microsoft .NET
Framework 4.5.2 mediante las instrucciones que se proporcionan en la ubicación
de descarga.

Instalación de WMF 5.1 para Windows Server 2008 R2 y


Windows 7
1. Desplácese a la carpeta en la que descargó el archivo ZIP.

2. Haga clic con el botón derecho en el archivo ZIP y seleccione Extraer todo.... El
archivo ZIP contiene dos archivos: un archivo MSU y el archivo de script Install-
WMF5.1.ps1 . Después de desempaquetar el archivo ZIP, puede copiar el contenido
en cualquier máquina que ejecuta Windows 7 o Windows Server 2008 R2.

3. Después de extraer el contenido del archivo ZIP, abra PowerShell como


administrador y navegue hasta la carpeta que contiene el contenido del archivo
ZIP.

4. Ejecute el script Install-WMF5.1.ps1 en esa carpeta y siga las instrucciones. Este


script comprobará los requisitos previos en la máquina local e instalará WMF 5.1 si
se cumplen esos requisitos. A continuación, se enumeran los requisitos previos.
Install-WMF5.1.ps1 toma los parámetros siguientes para facilitar la

automatización de la instalación en Windows Server 2008 R2 y Windows 7:

AcceptEula: cuando se incluye este parámetro, el CLUF se acepta


automáticamente y no se muestra.
AllowRestart: este parámetro solo se utiliza si se especifica AcceptEula. Si se
incluye este parámetro y se requiere un reinicio después de instalar WMF 5.1,
el reinicio se realizará sin pedir confirmación, inmediatamente después de
finaliza la instalación.

Dependencia de WinRM
La configuración de estado deseado (DSC) de Windows PowerShell depende de WinRM.
WinRM no está habilitado de forma predeterminada en Windows Server 2008 R2 y
Windows 7. Para habilitar WinRM, ejecute Set-WSManQuickConfig en una sesión de
Windows PowerShell con permisos elevados.

Instalación de WMF 5.1 para Windows Server


2012 R2, Windows 2012 y Windows 8.1

Instalación desde el Explorador de archivos de Windows


1. Desplácese a la carpeta en la que descargó el archivo MSU.
2. Haga doble clic en el archivo MSU para ejecutarlo.

Instalación desde el símbolo del sistema


1. Después de descargar el paquete correcto para la arquitectura del equipo, abra
una ventana del símbolo del sistema con derechos de usuario elevados (Ejecutar
como administrador). En las opciones de instalación de Server Core de Windows
Server 2012 R2, Windows Server 2012 o Windows Server 2008 R2 SP1, el símbolo
del sistema se abre de forma predeterminada con derechos de usuario elevados.

2. Cambie los directorios a la carpeta en la que descargó o copió el paquete de


instalación de WMF 5.1.

3. Ejecute uno de los siguientes comandos:

En los equipos que están ejecutando Windows Server 2012 R2 o Windows 8.1
x64, ejecute Win8.1AndW2K12R2-KB3191564-x64.msu /quiet /norestart .
En los equipos que están ejecutando Windows Server 2012, ejecute W2K12-
KB3191565-x64.msu /quiet /norestart .
En los equipos que están ejecutando Windows 8.1 x86, ejecute Win8.1-
KB3191564-x86.msu /quiet /norestart .

7 Nota

La instalación de WMF 5.1 requiere un reinicio. Si solamente usa la opción


/quiet , el sistema se reiniciará sin ninguna advertencia. Utilice la opción
/norestart para evitar reiniciar el sistema. Sin embargo, no se instalará WMF

5.1 hasta que haya reiniciado el sistema.


Instrucciones de desinstalación
Artículo • 13/04/2023

Uso de la ventana del símbolo del sistema


1. Abra el símbolo del sistema.
2. Ejecute Windows Update Standalone Launcher tal como se muestra a
continuación:

En Windows Server 2012 R2 y Windows 8.1:

PowerShell

wusa /uninstall /kb:3134758

En Windows Server 2012:

PowerShell

wusa /uninstall /kb:3134759

En Windows Server 2008 R2 SP1 y Windows 7 SP1:

PowerShell

wusa /uninstall /kb:3134760

Uso del Panel de control


1. Abra el Panel de control.
2. Abra Programas y, después, Desinstalar un programa.
3. Haga clic en Ver actualizaciones instaladas.
4. Seleccione Windows Management Framework 5.0 en la lista de actualizaciones
instaladas. Corresponde a KB3134758, KB3134759 o KB3134760. Haga clic en
Desinstalar.
Notas de la versión de
Windows Management Framework
(WMF) 5.x
Artículo • 13/04/2023

Cambios en WMF 5.0


PowerShell 5.0 agrega un nuevo flujo de información estructurado
Mejoras en DSC, incluidos cuatro recursos de DSC nuevos:
WindowsFeatureSet
WindowsOptionalFeatureSet
ServiceSet
ProcessSet
Se agregó Just Enough Administration para habilitar la administración basada en
roles a través de la comunicación remota de PowerShell
PowerShell 5.0 extiende el lenguaje para incluir enumeraciones y clases definidas
por el usuario
Se mejoraron las características de depuración de PowerShell ISE y se agregó la
depuración remota
Se agregaron los módulos PowerShellGet y PackageManagement
Se mejoraron las transcripciones y el registro de scripts de PowerShell
Se agregaron cmdlets de sintaxis de mensajes de cifrado
WMF 5.0 incluye el módulo NetworkSwitchManager para Windows
Se agregó el módulo Microsoft.PowerShell.ODataUtils
Se agregó compatibilidad con el Registro de inventario de software (SIL)
Varios cmdlets nuevos o actualizados en respuesta a problemas y solicitudes de
usuarios

Cambios en WMF 5.1


WMF 5.1 incluye los componentes de PowerShell, WMI, WinRM y Registro de inventario
de software (SIL) que se lanzaron con Windows Server 2016. WMF 5.1 puede instalarse
en Windows 7, Windows 8.1, Windows Server 2008 R2, 2012 y 2012 R2 y proporciona
varias mejoras con respecto a WMF 5.0 RTM, incluidos:

Nuevos cmdlets
En las mejoras de PowerShellGet se incluyen la aplicación de módulos firmados y la
instalación de módulos JEA
PackageManagement ha agregado compatibilidad con contenedores,
configuración de CBS, configuración basada en EXE y paquetes de CAB
Mejoras de depuración para las clases DSC y PowerShell
Mejoras de seguridad, incluido el cumplimiento de módulos firmados por
catálogos procedentes del servidor de extracción y al usar cmdlets de
PowerShellGet
Respuestas a varios problemas y varias solicitudes de usuarios

) Importante

Antes de instalar WMF 5.1 en Windows Server 2008 o Windows 7, confirme que
WMF 3.0 no está instalado. Para obtener más información, consulte Requisitos
previos de WMF 5.1 para Windows Server 2008 R2 SP1 y Windows 7 SP1.

Ediciones de PowerShell
A partir de la versión 5.1, PowerShell está disponible en diferentes ediciones que
denotan distintos conjuntos de características y compatibilidad con varias plataformas.

Desktop Edition: basado en .NET Framework y proporciona compatibilidad con


scripts y módulos destinados a las versiones de PowerShell que se ejecutan en las
ediciones de superficie completa de Windows como Server Core y Windows
Desktop.
Core Edition: basado en .NET Core y proporciona compatibilidad con scripts y
módulos destinados a las versiones de PowerShell que se ejecutan en las ediciones
de superficie completa de Windows como Nano Server y Windows IoT.

Más información acerca de las ediciones de PowerShell


Determinación de la edición de ejecución de PowerShell con $PSVersionTable
Filtrado de los resultados de Get-Module mediante CompatiblePSEditions con el
parámetro PSEdition
Impedir la ejecución de scripts, a menos que se ejecuten en una edición
compatible de PowerShell
Declarar la compatibilidad de un módulo con versiones específicas de PowerShell

Caché de análisis de módulo


A partir de WMF 5.1, PowerShell proporciona control sobre el archivo que se utiliza para
almacenar en la caché los datos acerca de un módulo, como los comandos que exporta.

De manera predeterminada, esta caché se almacena en el archivo


${env:LOCALAPPDATA}\Microsoft\Windows\PowerShell\ModuleAnalysisCache . La caché
normalmente se lee en el inicio al buscar un comando y se escribe en un subproceso en
segundo plano después de que se importa un módulo.

Para cambiar la ubicación predeterminada de la memoria caché, establezca la variable


de entorno $env:PSModuleAnalysisCachePath antes de iniciar PowerShell. Los cambios en
esta variable de entorno solo afectarán a los procesos secundarios. El valor debe asignar
un nombre a una ruta de acceso completa (nombre de archivo incluido) en la que
PowerShell tiene permiso para crear y escribir archivos. Para deshabilitar la caché del
archivo, establezca este valor en una ubicación no válida, como por ejemplo:

PowerShell

$env:PSModuleAnalysisCachePath = 'nul'

Esto establece la ruta de acceso en un dispositivo no válido. Si PowerShell no puede


escribir en la ruta de acceso, no se devuelve ningún error, pero se pueden ver informes
del error a través de un seguimiento:

PowerShell

Trace-Command -PSHost -Name Modules -Expression { Import-Module


Microsoft.PowerShell.Management -Force }

Al escribir en la caché, PowerShell buscará si hay módulos que no existen, con el fin de
evitar que la caché sea demasiado grande. A veces no interesa que se realicen estas
comprobaciones, en cuyo caso se pueden desactivar estableciendo:

PowerShell

$env:PSDisableModuleAnalysisCacheCleanup = 1

El establecimiento de esta variable de entorno surtirá efecto de inmediato en el proceso


actual.

Especificación de la versión del módulo


En WMF 5.1, using module se comporta de la misma forma que las restantes
construcciones relacionadas con módulos de PowerShell. Antes no había forma de
especificar una versión concreta del módulo; si había varias versiones, aparecía un error.

En WMF 5.1:

Puede usar el constructor ModuleSpecification (tabla hash).

Esta tabla hash tiene el mismo formato que Get-Module -FullyQualifiedName .

Ejemplo: using module @{ModuleName = 'PSReadLine'; RequiredVersion = '1.1'}

Si hay varias versiones del módulo de multiplicar, PowerShell usa la misma lógica
de resolución que Import-Module y no devuelve ningún error (el mismo
comportamiento que Import-Module y Import-DscResource ).

Mejoras en Pester
En WMF 5.1, la versión de Pester que se incluye con PowerShell se actualizó de 3.3.5 a
3.4.0. Esta actualización permite un mejor comportamiento para Pester en Nano Server.

Para revisar los cambios en Pest, examine el Registro de cambios en el repositorio de


GitHub.
Corrección de errores de WMF 5.1
Artículo • 13/04/2023

Corrección de errores
Se han corregido los siguientes errores importantes en WMF 5.1:

La detección automática de módulos usa PSModulePath


completamente
La detección automática de módulos (carga de módulos automáticamente sin un cmdlet
Import-Module explícito al llamar a un comando) se introdujo en WMF 3. Cuando se
introdujo, PowerShell comprobaba los comandos en $PSHome\Modules antes de usar
$env:PSModulePath .

WMF 5.1 cambia este comportamiento para usar $env:PSModulePath completamente.


Esto permite que un módulo creado por el usuario que define los comandos que
proporciona PowerShell (por ejemplo, Get-ChildItem ) se cargue automáticamente y
reemplace correctamente el comando integrado.

El redireccionamiento de archivos deja de codificar -


Encoding Unicode de forma rígida
En todas las versiones anteriores de PowerShell, era imposible controlar la codificación
de archivos usada por el operador de redireccionamiento de archivos.

A partir de WMF 5.1, se puede cambiar la codificación de archivos del


redireccionamiento mediante el establecimiento de $PSDefaultParameterValues :

PowerShell

$PSDefaultParameterValues["Out-File:Encoding"] = "Ascii"

Se corrigió una regresión en el acceso de los miembros


de System.Reflection.TypeInfo
Una regresión introducida en WMF 5.0 interrumpía el acceso de los miembros de
System.Reflection.RuntimeType , por ejemplo, [int].ImplementedInterfaces . Este error
se ha corregido en WMF 5.1.

Se han corregido algunos problemas con objetos COM


WMF 5.0 introdujo un nuevo enlazador COM para invocar métodos en objetos COM y
acceder a propiedades de objetos COM. Este nuevo enlazador ha mejorado
considerablemente el rendimiento, pero también ha presentado algunos errores que se
han corregido en WMF 5.1.

Las conversiones de argumentos no siempre se realizaban


correctamente

En el ejemplo siguiente:

PowerShell

$obj = New-Object -ComObject WScript.Shell


$obj.SendKeys([char]173)

El método SendKeysespera una cadena, pero PowerShell no ha convertido el carácter en


una cadena, lo que aplaza la conversión a IDispatch::Invoke, que usa
VariantChangeType para realizar la conversión. En este ejemplo, esto provocó el envío
de las claves "1", "7" y "3" en lugar de la clave Volume.Mute que se esperaba.

Los objetos COM enumerables no siempre se controlan


correctamente

PowerShell normalmente enumera la mayoría de los objetos enumerables, pero una


regresión introducida en WMF 5.0 impidió la enumeración de objetos COM que
implementan IEnumerable. Por ejemplo:

PowerShell

function Get-COMDictionary
{
$d = New-Object -ComObject Scripting.Dictionary
$d.Add('a', 2)
$d.Add('b', 2)
return $d
}

$x = Get-COMDictionary
En el ejemplo anterior, WMF 5.0 escribió incorrectamente Scripting.Dictionary en la
canalización, en lugar de enumerar los pares clave-valor.

[ordered] no se permitía en las clases


WMF 5.0 introdujo clases con una validación de los literales de tipo que se usan en las
clases. [ordered] parece un literal de tipo, pero no es un verdadero tipo .NET. WMF 5.0
informaba incorrectamente de un error en [ordered] dentro de una clase:

PowerShell

class CThing
{
[object] foo($i)
{
[ordered]@{ Thing = $i }
}
}

Los temas de ayuda con varias versiones no funcionan


Antes de WMF 5.1, si había varias versiones de un módulo instaladas y todas compartían
un tema de ayuda, por ejemplo, about_PSReadline, help about_PSReadline devolvía
varios temas sin ninguna forma obvia de ver la ayuda real.

WMF 5.1 corrige este problema, para lo que devuelve la ayuda de la versión más
reciente del tema.

Get-Help no proporciona una forma de especificar para qué versión se quiere la ayuda.
Para solucionar este problema, navegue hasta el directorio modules y vea la ayuda
directamente con una herramienta como su editor favorito.

La lectura de powerShell.exe desde STDIN dejó de


funcionar
Los clientes utilizan powershell -command - de las aplicaciones nativas para ejecutar
PowerShell pasando el script a través de STDIN. Desafortunadamente esto se ha
interrumpido debido a otros cambios en el host de consola.

Esto se corrigió para la versión 5.1 en la Actualización de aniversario de Windows 10.


powershell.exe origina un punto máximo en el uso de
CPU en el inicio
PowerShell usa una consulta WMI para comprobar que se ha iniciado a través de la
directiva de grupo para evitar los retrasos en el inicio de sesión. La consulta WMI
termina con la inyección de tzres.mui.dll en todos los procesos del sistema, puesto que
la clase Win32_Process de WMI intenta recuperar la información de la zona horaria
local. Esto produce un gran aumento de la CPU en wmiprvse (el host del proveedor
WMI). La solución consiste en utilizar llamadas a la API de Win32 para obtener la misma
información en lugar de usar WMI.
Cmdlets nuevos y actualizados
Artículo • 13/04/2023

Se agregaron cmdlets nuevos y se actualizaron los cmdlets existentes según los


comentarios de la comunidad.

Cmdlets Archive
Dos cmdlets nuevos, Compress-Archive y Expand-Archive , permiten comprimir y
expandir archivos ZIP.

Para más información, consulte la documentación del módulo


Microsoft.Powershell.Archive.

Cmdlets del catálogo


Se agregaron dos cmdlets nuevos en el módulo Microsoft.PowerShell.Security.

New-FileCatalog
Test-FileCatalog

Estos generan y validan los archivos de catálogo de Windows.

Cmdlets Clipboard
Get-Clipboard y Set-Clipboard facilitan la transferencia de contenido desde y hasta una

sesión de Windows PowerShell. Los cmdlets Clipboard admiten imágenes, archivos de


audio, listas de archivos y texto.

Para más información, consulte:

Get-Clipboard
Set-Clipboard

Cmdlets de sintaxis de mensajes de cifrado


(CMS)
Los cmdlets de sintaxis de mensajes de cifrado admiten el cifrado y descifrado de
contenido mediante el formato estándar IETF para proteger los mensajes de forma
criptográfica según se documenta en RFC5652 .

El estándar de cifrado de CMS implementa la criptografía de clave pública, donde la


clave usada para cifrar contenido (la clave pública) y la clave usada para descifrar
contenido (la clave privada) son independientes.

La clave pública se puede compartir y no se considera información confidencial. Todo el


contenido cifrado con la clave pública solo se puede descifrar con la clave privada. Para
obtener más información, consulte Public-key cryptography (Criptografía mediante
claves públicas).

Para obtener más información, consulte:

Get-CmsMessage
Protect-CmsMessage
Unprotect-CmsMessage

Los certificados requieren un identificador de uso de claves (EKU) único, como "Firma de
código" o "Correo cifrado", para identificarlos como certificados de cifrado de datos en
PowerShell. Para ver certificados de cifrado de documentos en el proveedor de
certificados, puede usar el parámetro dinámico DocumentEncryptionCert de Get-
ChildItem :

PowerShell

Get-ChildItem Cert:\CurrentUser -DocumentEncryptionCert -Recurse

Extraer y analizar objetos estructurados del


contenido de la cadena

ConvertFrom-String
El cmdlet ConvertFrom-String nuevo admite dos modos:

Análisis delimitado básico


Análisis controlado por ejemplos generados automáticamente

De forma predeterminada, el análisis delimitado divide la entrada en el espacio en


blanco y asigna los nombres de propiedad a los grupos resultantes.

El parámetro UpdateTemplate guarda los resultados del algoritmo de aprendizaje en un


comentario en el archivo de plantilla. Esto convierte el proceso de aprendizaje (la fase
más lenta) en un costo puntual. La ejecución de ConvertFrom-String con una plantilla
que contenga el algoritmo de aprendizaje codificado es ahora casi instantánea.

Para más información, consulte ConvertFrom-String.

Convert-String
Convert-String permite proporcionar ejemplos de antes y después sobre cómo quiere
que se vea el texto. El cmdlet da formato al texto de manera automática.

Para más información, consulte Convert-String.

Actualizaciones del objeto FileInfo


La información de la versión de archivo puede ser errónea, especialmente en casos en el
archivo se revisó. WMF 5.0 agrega las nuevas propiedades de script FileVersionRaw y
ProductVersionRaw a los objetos FileInfo. Estas son las propiedades tal como se
muestran para powershell.exe (teniendo en cuenta que $pid es el identificador del
proceso de PowerShell):

PowerShell

Get-Process -Id $pid -FileVersionInfo | Format-List *version*

Output

FileVersionRaw : 10.0.17763.1
ProductVersionRaw : 10.0.17763.1
FileVersion : 10.0.17763.1 (WinBuild.160101.0800)
ProductVersion : 10.0.17763.1

Format-Hex
Format-Hex permite ver datos de texto o binarios en formato hexadecimal.

Para más información, consulte Format-Hex.

Get-ChildItem tiene el parámetro -Depth


Get-ChildItem tiene ahora un parámetro Depth que se usa con Recurse para limitar la

recursión:
Compatibilidad de los módulos para la
declaración de intervalos de versiones (1.*, etc.)
Ahora puede combinar MinimumVersion y MaximumVersion para importar un módulo
dentro de un intervalo específico. Los parámetros también admiten caracteres comodín.

PowerShell

Import-Module psreadline -Verbose -MinimumVersion 1.0 -MaximumVersion 1.2.*

Output

VERBOSE: Loading module from path 'C:\Program


Files\WindowsPowerShell\Modules\psreadline\1.1\psreadline.psd1'.
VERBOSE: Importing cmdlet 'Get-PSReadlineKeyHandler'.
VERBOSE: Importing cmdlet 'Get-PSReadlineOption'.
VERBOSE: Importing cmdlet 'Remove-PSReadlineKeyHandler'.
VERBOSE: Importing cmdlet 'Set-PSReadlineKeyHandler'.
VERBOSE: Importing cmdlet 'Set-PSReadlineOption'.
VERBOSE: Importing function 'PSConsoleHostReadline'.

New-Guid
Hay muchos escenarios donde será necesario un identificador único. El cmdlet New-GUID
proporciona una manera sencilla de crear un GUID.

PowerShell

New-Guid

Output

Guid
----
e19d6ea5-3cc2-4db9-8095-0cdaed5a703d

Parámetro NoNewLine
Out-File , Add-Content y Set-Content ahora tienen un modificador NoNewline que

omite una línea nueva después de la salida. Por ejemplo:

PowerShell
"This is " | Out-File -FilePath Example.txt -NoNewline
"a single " | Add-Content -Path Example.txt -NoNewline
"sentence." | Add-Content -Path Example.txt -NoNewline
Get-Content .\Example.txt

Output

This is a single sentence.

Sin NoNewline especificado, cada fragmento estaría en una línea diferente:

PowerShell

"This is " | Out-File -FilePath Example.txt


"a single " | Add-Content -Path Example.txt
"sentence." | Add-Content -Path Example.txt
Get-Content .\Example.txt

Output

This is
a single
sentence.

Interactuar con los vínculos simbólicos


mediante cmdlets Item mejorados
El cmdlet Item y algunos cmdlets relacionados se extendieron para admitir vínculos
simbólicos.

Archivos de vínculos simbólicos


En este ejemplo, creamos un nuevo archivo de vínculo simbólico llamado
MySymLinkFile.txt en C:\Temp que vincula a $pshome\profile.ps1. Estos ejemplos
producen el mismo resultado.

PowerShell

New-Item -ItemType SymbolicLink -Path C:\Temp -Name MySymLinkFile.txt -Value


$pshome\profile.ps1
New-Item -ItemType SymbolicLink -Path C:\Temp\MySymLinkFile.txt -Value
$pshome\profile.ps1
Directorios de vínculos simbólicos
En este ejemplo, creamos un directorio de vínculo simbólico llamado MySymLinkDir en
C:\Temp que vincula a la carpeta $pshome. Estos ejemplos producen el mismo
resultado.

PowerShell

New-Item -ItemType SymbolicLink -Path C:\Temp -Name MySymLinkDir -Value


$pshome
New-Item -ItemType SymbolicLink -Path C:\Temp\MySymLinkDir -Value $pshome

Vínculos físicos
Las mismas combinaciones de Path y Name permitidas como se describió
anteriormente.

PowerShell

New-Item -ItemType HardLink -Path C:\Temp -Name MyHardLinkFile.txt -Value


$pshome\profile.ps1

Uniones de directorio
Las mismas combinaciones de Path y Name permitidas como se describió
anteriormente.

PowerShell

New-Item -ItemType Junction -Path C:\Temp\MyJunctionDir -Value $pshome

Get-ChildItem
Get-ChildItem ahora muestra una "l" en la propiedad Mode para indicar un directorio o
archivo de vínculo simbólico.

PowerShell

Get-ChildItem C:\Temp | sort LastWriteTime -Descending

Directory: C:\Temp

Mode LastWriteTime Length Name


---- ------------- ------ ----
-a---- 6/13/2014 3:00 PM 16 File.txt
d----- 6/13/2014 3:00 PM Directory
-a---l 6/13/2014 3:21 PM 0 MySymLinkFile.txt
d----l 6/13/2014 3:22 PM MySymLinkDir
-a---l 6/13/2014 3:23 PM 23304 MyHardLinkFile.txt
d----l 6/13/2014 3:24 PM MyJunctionDir

Remove-Item
Quitar los vínculos simbólicos funciona tal como quitar cualquier otro tipo de elemento.

PowerShell

Remove-Item C:\Temp\MySymLinkFile.txt
Remove-Item C:\Temp\MySymLinkDir

Use el parámetro Force para quitar los archivos en el directorio de destino y el vínculo
simbólico.

PowerShell

Remove-Item C:\Temp\MySymLinkDir -Force

New-TemporaryFile
A veces es necesario crear un archivo temporal en los scripts. Ahora puede hacerlo con
el cmdlet New-TemporaryFile :

PowerShell

$tempFile = New-TemporaryFile
$tempFile.FullName

Output

C:\Users\user1\AppData\Local\Temp\tmp375.tmp

Administración de conmutadores de red con


PowerShell
Los cmdlet NetworkSwitch, introducidos en WMF 5.0, permiten aplicar la configuración
de modificador, LAN virtual (VLAN) y básica del puerto del modificador de red de capa 2
a los modificadores de red certificados con el logotipo de Windows Server 2012 R2. Con
estos cmdlets puede hacer lo siguiente:

Configuración global del modificador, como:


Establecer el nombre de host.
Establecer el banner del modificador.
Mantener la configuración.
Habilitar o deshabilitar una característica.

Configuración de VLAN:
Crear o quitar la VLAN.
Habilitar o deshabilitar la VLAN.
Enumerar la VLAN.
Establecer el nombre descriptivo de una VLAN.

Configuración de puerto de la capa 2:


Enumerar los puertos.
Habilitar o deshabilitar los puertos.
Establecer los modos de puerto y sus propiedades.
Agregar o asociar la VLAN al modo de tronco o acceso en el puerto.

Para más información, consulte la documentación de NetworkSwitchManager.

Generar cmdlets de PowerShell basados en un


punto de conexión de OData con ODataUtils
El módulo ODataUtils permite la generación de cmdlets de PowerShell desde los puntos
de conexión de REST que admiten OData. El módulo Microsoft.PowerShell.ODataUtils
incluye estas características:

Canalización de información adicional del punto de conexión del lado servidor al


lado cliente.
Compatibilidad con la paginación del lado cliente.
Filtrado del lado servidor mediante el parámetro -Select.
Compatibilidad con los encabezados de solicitud web.

Los cmdlets de proxy que genera el cmdlet Export-ODataEndPointProxy proporcionan


información adicional del punto de conexión de OData del lado servidor en el flujo de
información.
PowerShell

Import-Module Microsoft.PowerShell.ODataUtils -Force


$generatedProxyModuleDir = Join-Path -Path $env:SystemDrive -ChildPath
'ODataDemoProxy'
$uri =
"http://services.odata.org/V3/(S(fhleiief23wrm5a5nhf542q5))/OData/OData.svc/
"
Export-ODataEndpointProxy -Uri $uri -OutputModule $generatedProxyModuleDir -
Force -AllowUnSecureConnection -Verbose -AllowClobber

En el ejemplo siguiente, recuperamos el producto principal y capturamos la salida en la


variable $infoStream .

Al especificar el parámetro IncludeTotalResponseCount, se obtiene el recuento total de


todos los registros Product disponibles en el servidor.

PowerShell

Import-Module $generatedProxyModuleDir -Force


$product = Get-Product -Top 1 -AllowUnsecureConnection -AllowAdditionalData
-IncludeTotalResponseCount -InformationVariable infoStream
$additionalInfo = $infoStream.GetEnumerator() | % MessageData
$additionalInfo['odata.count']

Puede obtener los registros del servidor en lotes mediante la compatibilidad con la
paginación del lado cliente. Resulta útil cuando se necesita obtener una gran cantidad
de datos del servidor a través de la red.

PowerShell

$skipCount = 0
$batchSize = 3
while($skipCount -le $additionalInfo['odata.count'])
{
Get-Product -AllowUnsecureConnection -AllowAdditionalData -Top $batchSize
-Skip $skipCount
$skipCount += $batchSize
}

Los cmdlets de proxy generados admiten el parámetro Select que se usa como filtro
para recibir solamente las propiedades de registro que el cliente necesita. Este filtrado
se produce en el servidor, lo que disminuye la cantidad de datos que se transfieren a
través de la red.

PowerShell
Get-Product -Top 2 -AllowUnsecureConnection -AllowAdditionalData -Select
Name

El cmdlet Export-ODataEndpointProxy , y los cmdlets de proxy que genera, ahora admiten


el parámetro Headers. El encabezado se puede usar para canalizar la información
adicional que espera el punto de conexión de OData.

En el ejemplo siguiente, una tabla hash que contiene una clave de suscripción se
proporciona al parámetro Headers. Este es un ejemplo típico de los servicios que están
esperando una clave de suscripción para autenticación.

PowerShell

Export-ODataEndpointProxy -Uri $endPointUri -OutputModule


$generatedProxyModuleDir -Force -AllowUnSecureConnection -Verbose -Headers
@{'subscription-key'='XXXX'}
Nuevas características de lenguaje de
PowerShell 5.0
Artículo • 13/04/2023

PowerShell 5.0 agregó la capacidad de definir clases y otros tipos definidos por el
usuario con semántica y sintaxis formal, de manera similar a otros lenguajes de
programación orientados a objetos. El objetivo es permitir a los desarrolladores y
profesionales de TI adoptar PowerShell para una gama más amplia de casos de uso,
simplificar el desarrollo de artefactos de PowerShell (como recursos de DSC) y acelerar
la cobertura de las superficies de administración.

PowerShell 5.0 presenta los siguientes nuevos elementos de lenguaje en PowerShell:

Palabra clave class


La palabra clave class define una nueva clase. Se trata de un tipo verdadero de .NET
Framework. Los miembros de clase son públicos, pero solo en el ámbito del módulo. No
puede hacer referencia al nombre de tipo como una cadena (por ejemplo, New-Object
no funciona) y, en esta versión, no puede usar un literal de tipo (por ejemplo,
[MyClass] ) fuera del archivo de script o módulo en el que se define la clase.

PowerShell

class MyClass
{
...
}

Palabra clave Enum y enumeraciones


Se agregó compatibilidad con la palabra clave enum , que usa el delimitador de nueva
línea. No es posible definir actualmente un enumerador en términos propios. Sin
embargo, puede inicializar una enumeración en términos de otra enumeración, tal como
se muestra en el ejemplo siguiente. Además, el tipo base no se puede especificar,
porque siempre es [int] .

PowerShell

enum Color2
{
Yellow = [Color]::Blue
}

Un valor de enumerador debe ser una constante de tiempo de análisis. No puede


establecerlo en el resultado de un comando invocado.

PowerShell

enum MyEnum
{
Enum1
Enum2
Enum3 = 42
Enum4 = [int]::MaxValue
}

Las enumeraciones admiten operaciones aritméticas, como se muestra en el ejemplo


siguiente.

PowerShell

enum SomeEnum { Max = 42 }


enum OtherEnum { Max = [SomeEnum]::Max + 1 }

Import-DscResource
Import-DscResource ahora es una palabra clave dinámica verdadera. PowerShell analiza

el módulo raíz del módulo especificado y busca las clases que contienen el atributo
DscResource.

ImplementingAssembly
Un campo nuevo, ImplementingAssembly, se agregó a ModuleInfo. Se establece en el
ensamblado dinámico creado para un módulo de script si el script define clases, o en el
ensamblado cargado en el caso de los módulos binarios. No se establece si
ModuleType es Manifest.

La reflexión en el campo ImplementingAssembly descubre los recursos de un módulo.


Esto significa que puede descubrir recursos escritos en PowerShell o en otros lenguajes
administrados.

Información adicional
about_Classes
about_Enum
about_Classes_and_DSC
Mejoras de la consola en WMF 5.1
Artículo • 13/04/2023

Mejoras en la consola de PowerShell


En WMF 5.1, se han realizado los siguientes cambios en powershell.exe para mejorar la
experiencia de la consola:

Compatibilidad con VT100


Windows 10 agregó compatibilidad con secuencias de escape de VT100. PowerShell
ignora ciertas secuencias de escape con formato VT100 al calcular los anchos de tabla.

PowerShell también agregó una nueva API que puede utilizarse al dar formato al código
para determinar si se admite VT100. Por ejemplo:

PowerShell

if ($host.UI.SupportsVirtualTerminal)
{
$esc = [char]0x1b
"A yellow ${esc}[93mhello${esc}[0m"
}
else
{
"A default hello"
}

Esta es un ejemplo completo que se puede utilizar para resaltar las coincidencias de
Select-String . Guarde el ejemplo en un archivo denominado MatchInfo.format.ps1xml

y para usarlo, en su perfil o en cualquier otro lugar, ejecute Update-FormatData -Prepend


MatchInfo.format.ps1xml .

Tenga en cuenta que las secuencias de escape de VT100 solo se admiten a partir de la
Actualización de aniversario de Windows 10. No se admiten en sistemas anteriores.

Compatibilidad con el modo VI en PSReadline


PSReadline agrega compatibilidad con el modo VI. Para utilizar el modo VI, ejecute
Set-PSReadlineOption -EditMode Vi .
Stdin redirigido con entrada interactiva
En versiones anteriores, a partir de PowerShell con powershell -File - se requería
cuando se redirigía stdin y deseaba especificar los comandos de forma interactiva.

Con WMF 5.1 ya no es necesaria esta opción, que es difícil de detectar. Puede iniciar
PowerShell sin ninguna opción.

Tenga en cuenta que PSReadline no admite stdin redirigido y la experiencia de edición


de línea de comandos integrada con stdin redirigido es extremadamente limitada, por
ejemplo, las teclas de dirección no funcionan. Una futura versión de PSReadline debería
solucionar este problema.
Mejoras en la depuración de scripts de
PowerShell
Artículo • 13/04/2023

PowerShell 5.0 incluye varias mejoras que perfeccionan la experiencia de depuración.

Interrumpir todos
La consola de PowerShell y PowerShell ISE permiten ahora el acceso al depurador para
ejecutar scripts. Está opción está disponible para sesiones locales y remotas.

En la consola, presione Ctrl + Interrumpir .

En el ISE, presione Ctrl + B o use el comando de menú Depurar -> Interrumpir todos.

Depuración remota y edición remota de


archivos en PowerShell ISE
PowerShell ISE permite ahora abrir y editar archivos en una sesión remota mediante la
ejecución del comando PSEdit. Por ejemplo, puede abrir un archivo para editarlo desde
la línea de comandos en una sesión remota de la siguiente manera:

PowerShell

[RemoteComputer1]: PS C:\> PSEdit C:\DebugDemoScripts\Test-GetMutex.ps1

Además, ahora puede editarlo y guardar los cambios en un archivo remoto que se abrirá
automáticamente en PowerShell ISE cuando se alcance un punto de interrupción. Ahora,
puede depurar un archivo de script que se ejecute en un equipo remoto, editar el
archivo para corregir un error y, después, volver a ejecutar el script modificado.

Depuración de scripts avanzada


Existen nuevas características de depuración avanzadas que permiten conectarse a
cualquier proceso del equipo local que tenga PowerShell cargado, así como depurar
espacios de ejecución arbitrarios en ese proceso.

Depuración del espacio de ejecución


Los nuevos cmdlets agregados permiten enumerar los espacios de ejecución actuales en
un proceso y conectar la consola de PowerShell o el depurador de PowerShell ISE a ese
espacio de ejecución para la depuración de scripts:

Get-Runspace
Debug-Runspace
Enable-RunspaceDebug
Disable-RunspaceDebug
Get-RunspaceDebug

Conectarse al proceso que hospeda PowerShell


Ahora puede establecer la conexión con cualquier proceso del equipo que tenga
PowerShell cargado. Para ello, ingrese en una sesión interactiva con el proceso de host.
Para más información, consulte:

Enter-PSHostProcess
Exit-PSHostProcess
Seguimiento y registro de scripts
Artículo • 13/04/2023

Mientras que PowerShell ya tiene la opción de Directiva de grupo


LogPipelineExecutionDetails para registrar la invocación de cmdlets, el lenguaje de
scripting de PowerShell tiene muchas características que quizás quiera registrar y
auditar. La nueva característica de seguimiento detallado de scripts ofrece el
seguimiento detallado y el análisis de la actividad de los scripts de PowerShell en un
sistema. Después de habilitar el seguimiento detallado de scripts, PowerShell registra
todos los bloques de script en el registro de eventos ETW, Microsoft-Windows-
PowerShell/Operational. Si un bloque de script crea otro bloque de script, por ejemplo,
al llamar a Invoke-Expression , también se registrará el bloque de script al que se invocó.

El registro se habilita mediante la opción de Directiva de grupo Activar el registro de


bloque de script de PowerShell en Plantillas administrativas ->Componentes de
Windows ->Windows PowerShell.

Los eventos son:

Canal Operativos

Nivel Verbose

Código de operación Crear

Tarea CommandStart

Palabra clave Espacio de ejecución

EventId Engine_ScriptBlockCompiled (0x1008 = 4104)

Message Crear texto de Scriptblock (%1 de %2):


%3
Id. de ScriptBlock: %4

El texto insertado en el mensaje es la extensión del bloque de script compilado. El


identificador es un GUID que se conserva durante la vida del bloque de script.

Cuando se habilita el registro detallado, la característica escribe los marcadores de inicio


y fin:

Canal Operativos

Nivel Verbose
Canal Operativos

Código de operación Abrir / Cerrar

Tarea CommandStart / CommandStop

Palabra clave Espacio de ejecución

EventId ScriptBlock_Invoke_Start_Detail (0x1009 = 4105) /


ScriptBlock_Invoke_Complete_Detail (0x100A = 4106)

Mensaje Invocación iniciada / completada del id. de bloque de script: %1


Id. de espacio de ejecución: %2

El identificador es el GUID que representa el bloque de script (que puede estar


correlacionado con Id. de evento 0x1008) y el identificador de espacio de ejecución
representa el espacio de ejecución en el que se ejecutó este bloque de script.

Los signos de porcentaje del mensaje de invocación representan las propiedades de


ETW estructuradas. Mientras se reemplazan por los valores reales en el texto del
mensaje, una manera más segura de acceder a ellos es recuperar el mensaje con el
cmdlet Get-WinEvent y, luego, usara la matriz Properties del mensaje.

Este es un ejemplo de cómo esta funcionalidad puede ayudarle a descubrir un intento


malicioso para cifrar y ofuscar un script:

PowerShell

## Malware
function SuperDecrypt
{
param($script)
$bytes = [Convert]::FromBase64String($script)

## XOR "encryption"
$xorKey = 0x42
for($counter = 0; $counter -lt $bytes.Length; $counter++)
{
$bytes[$counter] = $bytes[$counter] -bxor $xorKey
}
[System.Text.Encoding]::Unicode.GetString($bytes)
}

$decrypted = SuperDecrypt "FUIwQitCNkInQm9CCkItQjFCNkJiQmVCEkI1QixCJkJlQg=="


Invoke-Expression $decrypted

Si se ejecuta, generará las entradas de registro siguientes:

Output
Compiling Scriptblock text (1 of 1):
function SuperDecrypt
{
param($script)
$bytes = [Convert]::FromBase64String($script)
## XOR "encryption"
$xorKey = 0x42
for($counter = 0; $counter -lt $bytes.Length; $counter++)
{
$bytes[$counter] = $bytes[$counter] -bxor $xorKey
}
[System.Text.Encoding]::Unicode.GetString($bytes)

}
ScriptBlock ID: ad8ae740-1f33-42aa-8dfc-1314411877e3

Compiling Scriptblock text (1 of 1):


$decrypted = SuperDecrypt "FUIwQitCNkInQm9CCkItQjFCNkJiQmVCEkI1QixCJkJlQg=="
ScriptBlock ID: ba11c155-d34c-4004-88e3-6502ecb50f52

Compiling Scriptblock text (1 of 1):


Invoke-Expression $decrypted
ScriptBlock ID: 856c01ca-85d7-4989-b47f-e6a09ee4eeb3

Compiling Scriptblock text (1 of 1):


Write-Host 'Pwnd'
ScriptBlock ID: 5e618414-4e77-48e3-8f65-9a863f54b4c8

Si la longitud del bloque de script supera la capacidad de un solo evento, PowerShell


divide el script en varias partes. A continuación, se muestra código de ejemplo para
volver a combinar un script a partir de sus mensajes de registro:

PowerShell

$created = Get-WinEvent -FilterHashtable @{ ProviderName="Microsoft-Windows-


PowerShell"; Id = 4104 } |
Where-Object { $_.<...> }
$sortedScripts = $created | sort { $_.Properties[0].Value }
$mergedScript = -join ($sortedScripts | % { $_.Properties[2].Value })

Al igual que con todos los sistemas de registro que tienen un búfer de retención
limitado, una forma de atacar esta infraestructura es inundar el registro de eventos
falsos para ocultar las pruebas anteriores. Para protegerse de este ataque, asegúrese de
tener configurado algún tipo de colección de registros de eventos, como Reenvío de
eventos de Windows. Para obtener más información, consulte Uso de Azure Monitor
para su integración con herramientas SIEM .
Mejoras en la configuración de estado
deseado (DSC) en WMF 5.1
Artículo • 13/04/2023

Mejoras en los recursos de la clase DSC


En WMF 5.1, hemos corregido los siguientes problemas conocidos:

Get-DscConfiguration puede devolver valores vacíos (NULL) o errores si la función


Get() de un recurso de DSC basado en clases devuelve un tipo complejo o de tabla
hash.
Get-DscConfiguration devuelve un error si se usa la credencial RunAs en la
configuración de DSC.
Un recurso basado en clases no se puede usar en una configuración compuesta.
Start-DscConfiguration se bloquea si el recurso basado en clases tiene una
propiedad de un tipo propio.
Los recursos basados en clases no se pueden utilizar como recursos exclusivos.

Mejoras en la depuración de recursos de DSC


En WMF 5.0, el depurador de PowerShell no se detenía directamente en el método de
recursos basados en clases (Get/Set/Test). En WMF 5.1, el depurador se detiene en el
método de recursos basados en clases de la misma manera que con los métodos de
recursos basados en MOF.

El cliente de extracción de DSC es compatible


con TLS 1.1 y TLS 1.2
Anteriormente, el cliente de extracción de DSC solo era compatible con SSL3.0 y TLS1.0
a través de conexiones HTTPS. Cuando se le obligaba a usar protocolos más seguros, el
cliente de extracción dejaba de funcionar. En WMF 5.1, el cliente de extracción de DSC
ya no es compatible con SSL 3.0 y, en cambio, ya es compatible con los protocolos TLS
1.1 y TLS 1.2 que son más seguros.

Registro de servidor de extracción mejorado


En las versiones anteriores de WMF, si se realizaban solicitudes de informes y registros
concurrentes al servidor de extracción de DSC mientras se usaba la base de datos
ESENT, LCM no podía registrarlas ni informar al respecto. En esos casos, los registros de
eventos en el servidor de extracción tienen el error "El nombre de instancia ya está en
uso". Esto se debe a que se usa un patrón incorrecto para acceder a la base de datos
ESENT en un escenario multiproceso. En WMF 5.1, este problema se ha corregido. Los
informes o registros simultáneos (que implican la base de datos ESENT) funcionan
correctamente en WMF 5.1. Este problema solo concierne a la base de datos ESENT, no
se aplica a la base de datos OLEDB.

Habilitación del registro circular en la instancia


de base de datos ESENT
En versiones anteriores de DSC-PullServer, los archivos de registro de la base de datos
ESENT llenaban el espacio en disco del servidor de extracción, porque la instancia de la
base de datos se creó sin el registro circular. En esta versión, tiene la opción de controlar
el comportamiento del registro circular de la instancia mediante el archivo web.config
del servidor de extracción. De forma predeterminada, CircularLogging se establece en
TRUE.

XML

<appSettings>
<add key="dbprovider" value="ESENT" />
<add key="dbconnectionstr" value="C:\Program
Files\WindowsPowerShell\DscService\Devices.edb" />
<add key="CheckpointDepthMaxKB" value="512" />
<add key="UseCircularESENTLogs" value="TRUE" />
</appSettings>

Compatibilidad de WOW64 con la palabra


clave Configuration
La palabra clave Configuration se admite ahora en WOW64 en un equipo de 64 bits.
Esto significa que una configuración de DSC puede definirse y compilarse en un proceso
de 32 bits como Windows PowerShell ISE (x 86) ejecutándose en un equipo de 64 bits.

Convención de nomenclatura de configuración


parcial de extracción
En la versión anterior, la convención de nomenclatura de una configuración parcial
consistía en que el nombre de archivo MOF en el servidor o servicio de extracción debía
coincidir con el nombre de configuración parcial especificado en la configuración del
administrador de configuración local, que a su vez debe coincidir con el nombre de
configuración insertado en el archivo MOF.

Vea las instantáneas siguientes:

Opciones de configuración local que definen una configuración parcial que puede
recibir un nodo.

Definición de configuración parcial de ejemplo.

PowerShell

Configuration PartialOne
{
Node('localhost')
{
File test
{
DestinationPath = "$env:TEMP\partialconfigexample.txt"
Contents = 'Partial Config Example'
}
}
}
PartialOne

"ConfigurationName" insertado en el archivo MOF generado.


FileName en el repositorio de configuración de extracción

El nombre del servicio Automatización de Azure generó archivos MOF como


<ConfigurationName>.<NodeName>.mof . Por tanto, la configuración siguiente se

compila como PartialOne.localhost.mof.

Esto hizo imposible extraer una de las configuraciones parciales del servicio
Automatización de Azure.

PowerShell

Configuration PartialOne
{
Node('localhost')
{
File test
{
DestinationPath = "$env:TEMP\partialconfigexample.txt"
Contents = 'Partial Config Example'
}
}
}
PartialOne
En WMF 5.1, la configuración parcial del servidor o servicio de extracción se puede
denominar <ConfigurationName>.<NodeName>.mof . Además, si una máquina extrae
una sola configuración del servidor o servicio de extracción, el archivo de
configuración del repositorio de configuración del servidor de extracción puede
tener cualquier nombre de archivo. Esta flexibilidad de nomenclatura le permite
administrar los nodos parcialmente mediante el servicio Azure Automation, donde
cierta configuración del nodo proviene del DSC de Azure Automation y con una
configuración parcial que administra de forma local.

La metaconfiguración siguiente configura un nodo que se debe administrar tanto


localmente como mediante el servicio Azure Automation.

PowerShell

[DscLocalConfigurationManager()]
Configuration RegistrationMetaConfig
{
Settings
{
RefreshFrequencyMins = 30
RefreshMode = "PULL"
}

ConfigurationRepositoryWeb web
{
ServerURL = $endPoint
RegistrationKey = $registrationKey
ConfigurationNames = $configurationName
}

# Partial configuration managed by Azure Automation service.


PartialConfiguration PartialConfigurationManagedByAzureAutomation
{
ConfigurationSource = "[ConfigurationRepositoryWeb]Web"
}

# This partial configuration is managed locally.


PartialConfiguration OnPremisesConfig
{
RefreshMode = "PUSH"
ExclusiveResources = @("Script")
}

RegistrationMetaConfig
Set-DscLocalConfigurationManager -Path .\RegistrationMetaConfig -
Verbose
Uso de PsDscRunAsCredential con recursos
compuestos de DSC
Hemos agregado compatibilidad para usar PsDscRunAsCredential con recursos
compuestos de DSC.

Ahora puede especificar el valor de PsDscRunAsCredential al usar recursos compuestos


dentro de las configuraciones. Si se especifica así, todos los recursos se ejecutarán
dentro de un recurso compuesto como un usuario RunAs. Si el recurso compuesto llama
a otro recurso compuesto, todos esos recursos se ejecutarán también como usuario
RunAs. Las credenciales de RunAs se propagan a todos los niveles de la jerarquía del
recurso compuesto. Si cualquier recurso de un recurso compuesto especifica su propio
valor para PsDscRunAsCredential, aparece un error de combinación durante la
compilación de la configuración.

En este ejemplo se muestra el uso con el recurso compuesto WindowsFeatureSet que se


incluye en el módulo PSDesiredStateConfiguration.

PowerShell

Configuration InstallWindowsFeature
{
Import-DscResource -ModuleName PSDesiredStateConfiguration

Node $AllNodes.NodeName
{
WindowsFeatureSet features
{
Name = @("Telnet-Client","SNMP-Service")
Ensure = "Present"
IncludeAllSubFeature = $true
PsDscRunAsCredential = Get-Credential
}
}
}

$configData = @{
AllNodes = @(
@{
NodeName = 'localhost'
PSDscAllowDomainUser = $true
CertificateFile = 'C:\publicKeys\targetNode.cer'
Thumbprint = '7ee7f09d-4be0-41aa-a47f-96b9e3bdec25'
}
)
}

InstallWindowsFeature -ConfigurationData $configData


Permitir recursos duplicados idénticos en una
configuración
DSC no permite ni administra las definiciones de recursos en conflicto dentro de una
configuración. En lugar de intentar resolver el conflicto, simplemente no funciona. Dado
que la reutilización de la configuración se usa más en los recursos compuestos, etc., se
producirán conflictos más a menudo. Cuando las definiciones de recursos en conflicto
son idénticas, DSC debe ser inteligente y permitirlo. En esta versión, se admite tener
varias instancias de recursos con definiciones idénticas:

PowerShell

Configuration IIS_FrontEnd
{
WindowsFeature FE_IIS #Identical resource
{
Ensure = 'Present'
Name = 'Web-Server'
}

WindowsFeature FTP
{
Ensure = 'Present'
Name = 'Web-FTP-Server'
}
}

Configuration IIS_Worker
{
WindowsFeature Worker_IIS #Identical resource
{
Ensure = 'Present'
Name = 'Web-Server'
}

WindowsFeature ASP
{
Ensure = 'Present'
Name = 'Web-ASP-Net45'
}
}

Configuration WebApplication
{
IIS_Frontend Web {}

IIS_Worker ASP {}
}
En versiones anteriores, el resultado sería un error de compilación debido a un conflicto
entre las instancias de WindowsFeature FE_IIS y WindowsFeature Worker_IIS al intentar
comprobar la instalación del rol "Servidor web". Observe que todas las propiedades que
se están configurando son idénticas en estas dos configuraciones. Puesto que todas las
propiedades de estos dos recursos son idénticas, el resultado será una compilación
correcta.

Si cualquiera de las propiedades difiere entre los dos recursos, no se considerarán


idénticas y se producirá un error de compilación.

Validaciones de firmas de configuraciones y


módulos de DSC
En DSC, las configuraciones y los módulos se distribuyen a los equipos administrados
desde el servidor de extracción. Si el servidor de extracción está en peligro, un atacante
puede modificar las configuraciones y los módulos en el servidor de extracción y
distribuirlo a todos los nodos administrados.

En WMF 5.1, DSC admite la validación de las firmas digitales en los archivos del catálogo
y de configuración (.MOF). Esta característica evita que los nodos ejecuten archivos de
módulos o de configuración que no están firmados por un firmante de confianza o que
se han alterado después de que los haya firmado un firmante de confianza.

Cómo firmar un módulo y una configuración


Archivos de configuración (.MOF): el cmdlet de PowerShell existente Set-
AuthenticodeSignature se amplía para admitir la firma de archivos MOF.
Módulos: la firma de módulos se realiza mediante la firma del catálogo de
módulos correspondiente mediante los siguientes pasos:

1. Creación de un archivo de catálogo: un archivo de catálogo contiene una


colección de algoritmos hash criptográficos o huellas digitales. Cada huella
digital corresponde a un archivo que se incluye en el módulo. Se ha
agregado un nuevo cmdlet, New-FileCatalog, para que los usuarios puedan
crear un archivo de catálogo para su módulo.
2. Firma del archivo de catálogo: use el cmdlet Set-AuthenticodeSignature para
firmar el archivo de catálogo.
3. Coloque el archivo de catálogo dentro de la carpeta del módulo. Por
convención, el archivo de catálogo del módulo debe colocarse en la carpeta
del módulo y debe tener el mismo nombre que este.
Configuración de LocalConfigurationManager para
habilitar las validaciones de las firmas

Extracción
En un nodo, LocalConfigurationManager realiza la validación de las firmas de módulos y
las configuraciones en función de su configuración actual. De forma predeterminada, la
validación de firmas está deshabilitada. La validación de firmas se puede habilitar
agregando un bloque "SignatureValidation" a la definición de metaconfiguración del
nodo, tal como se muestra aquí:

PowerShell

[DSCLocalConfigurationManager()]
Configuration EnableSignatureValidation
{
Settings
{
RefreshMode = 'PULL'
}

ConfigurationRepositoryWeb pullserver{
ConfigurationNames = 'sql'
ServerURL =
'http://localhost:8080/PSDSCPullServer/PSDSCPullServer.svc'
AllowUnsecureConnection = $true
RegistrationKey = 'd6750ff1-d8dd-49f7-8caf-7471ea9793fc' # Replace
this with correct registration key.
}
SignatureValidation validations{
# If the TrustedStorePath property is provided then LCM will use the
custom path. Otherwise, the LCM will use default trusted store path
(Cert:\LocalMachine\DSCStore) to find the signing certificate.
TrustedStorePath = 'Cert:\LocalMachine\DSCStore'
SignedItemType = 'Configuration','Module' # This is a list
of DSC artifacts, for which LCM need to verify their digital signature
before executing them on the node.
}

}
EnableSignatureValidation
Set-DscLocalConfigurationManager -Path .\EnableSignatureValidation -Verbose

El establecimiento de la metaconfiguración anterior en un nodo habilita la validación de


firmas de los módulos y las configuraciones descargados. LocalConfigurationManager
lleva a cabo los pasos siguientes para comprobar las firmas digitales.
1. Compruebe que la firma de un archivo de configuración (. MOF) es válida con el
cmdlet Get-AuthenticodeSignature .
2. Compruebe que la entidad de certificación que autorizó al firmante es de
confianza.
3. Descargue las dependencias de los módulos o recursos de la configuración en una
ubicación temporal.
4. Compruebe la firma del catálogo incluida dentro del módulo.

Busque un archivo <moduleName>.cat y compruebe su firma con Get-


AuthenticodeSignature .
Compruebe que la entidad de certificación que autenticó al firmante es de
confianza.
Compruebe que el contenido de los módulos no se ha alterado, para lo que
debe usar el cmdlet nuevo Test-FileCatalog .

5. Install-Module a $env:ProgramFiles\WindowsPowerShell\Modules\
6. Configuración de proceso

7 Nota

La validación de la firma en el catálogo de módulo y la configuración solo se


realizan la primera vez que se aplica la configuración al sistema o cuando el
módulo se descarga e instala. Las ejecuciones de coherencia no validan la firma de
Current.mof ni sus dependencias de módulo. Si se ha producido un error en
cualquier etapa de la comprobación, por ejemplo, si la configuración extraída del
servidor de extracción no tiene firma, el procesamiento de la configuración termina
con el error que se muestra más adelante y se eliminan todos los archivos
temporales.
De forma similar, la extracción de un módulo cuyo catálogo no esté firmado provoca el
siguiente error:

Inserción

Una configuración entregada mediante inserción puede alterarse en su origen antes de


que se entregue al nodo. El administrador de configuración local lleva a cabo pasos de
validación de firmas similares para las configuraciones insertadas o publicadas. A
continuación, se muestra un ejemplo completo de validación de firma para la inserción.

Habilite la validación de firma en el nodo.

PowerShell
[DSCLocalConfigurationManager()]
Configuration EnableSignatureValidation
{
Settings
{
RefreshMode = 'PUSH'
}
SignatureValidation validations{
TrustedStorePath = 'Cert:\LocalMachine\DSCStore'
SignedItemType = 'Configuration','Module'
}

}
EnableSignatureValidation
Set-DscLocalConfigurationManager -Path .\EnableSignatureValidation -
Verbose

Cree un archivo de configuración de ejemplo.

PowerShell

# Sample configuration
Configuration Test
{

File foo
{
DestinationPath = "$env:TEMP\signingTest.txt"
Contents = "ABC"
}
}
Test

Intente insertar el archivo de configuración sin firmar en el nodo.

PowerShell

Start-DscConfiguration -Path .\Test -Wait -Verbose -Force

Firme el archivo configuración mediante el certificado de firma de código.


Intente insertar el archivo MOF firmado.
Mejoras del motor de PowerShell
Artículo • 13/04/2023

En WMF 5.1, se han implementado las siguientes mejoras al motor central de


PowerShell:

Rendimiento
El rendimiento ha mejorado en algunas áreas importantes:

Inicio
La canalización a cmdlets como ForEach-Object y Where-Object es
aproximadamente un 50 % más rápida

Algunas mejoras del ejemplo (los resultados pueden variar en función del hardware):

Escenario Tiempo de 5.0 Tiempo de 5.1


(ms) (ms)

powershell -command "echo 1" 900 250

Primera ejecución de PowerShell: powershell -command 30000 13000


"Unknown-Command"

Caché de análisis de comandos integrada: powershell - 7000 520


command "Unknown-Command"

1..1000000 | % { } 1400 750

7 Nota

Un cambio relacionado con el inicio puede afectar a algunos escenarios no


compatibles. PowerShell ya no lee los archivos $pshome\*.ps1xml : estos archivos se
han convertido en C# para evitar la sobrecarga de archivos y de la CPU que supone
procesar los archivos XML. Los archivos aún existen para proporcionar
compatibilidad con V2 en paralelo, por lo que si se cambia el contenido de los
archivos, esto no tendrá ningún efecto en V5, solo en V2. Tenga en cuenta que el
cambio del contenido de estos archivos nunca ha sido un escenario compatible.

Otro cambio visible es la forma en que PowerShell almacena en caché tanto comandos
exportados como otra información de los módulos instalados en un sistema. Antes, la
memoria caché se almacenaba en el directorio
$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\CommandAnalysis . En WMF 5.1, la

memoria caché es un único archivo


$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\ModuleAnalysisCache . Para obtener

más información, vea Caché de análisis de módulo.


Flujo de información
Artículo • 13/04/2023

PowerShell 5.0 agrega un nuevo flujo de información estructurado para transmitir datos
estructurados entre un script y su host. Write-Host también se actualizó para emitir su
salida en el flujo de información, donde ahora se puede capturar o silenciar. El nuevo
cmdlet Write-Information usado con los parámetros comunes InformationVariable y
InformationAction permiten más flexibilidad y funcionalidad.

La función siguiente usa cmdlets que aprovechan el nuevo flujo de información.

PowerShell

function OutputGusher {
[CmdletBinding()]
param()
Write-Host -ForegroundColor Green 'Preparing to give you output!'
Write-Host '============================='
Write-Host 'I ' -ForegroundColor White -NoNewline
Write-Host '<3 ' -ForegroundColor Red -NoNewline
Write-Host 'Output' -ForegroundColor White
Write-Host '============================='

$p = Get-Process -id $pid


$p

Write-Information $p -Tag Process


Write-Information 'Some spammy logging information' -Tag LogLow
Write-Information 'Some important logging information' -Tag LogHigh

Write-Host
Write-Host -ForegroundColor Green 'SCRIPT COMPLETE!!'
}

En los ejemplos se muestran los resultados de la ejecución de esta función.

PowerShell

$r = OutputGusher

Output

Preparing to give you output!


=============================
I <3 Output
=============================
SCRIPT COMPLETE!!

La variable $r ha capturado la información del proceso en la variable de script $p .

PowerShell

$r.Id
4008

A diferencia del cmdlet Write-Host , usar el parámetro InformationVariable de Write-


Information le permite capturar la salida en una variable. Con la etiqueta, puede crear

canales independientes para el mensaje enviado al flujo de información.

PowerShell

$r = OutputGusher -InformationVariable iv
$ivOutput = $iv | Group-Object -AsHash { $_.Tags[0] } -AsString
$ivOutput

Output

Preparing to give you output!


=============================
I <3 Output
=============================
SCRIPT COMPLETE!!

Name Value
---- -----
LogLow {Some spammy logging information}
LogHigh {Some important logging information}
Process {System.Diagnostics.Process (powershell)}
PSHOST {Preparing to give you output!,
=============================, I , <3 ...}

Cuando envía un mensaje al flujo de información con una etiqueta, ese mensaje no se
muestra en la aplicación host, pero se puede recuperar con el nombre de la etiqueta.
Por ejemplo:

PowerShell

$iv | where Tags -eq 'LogHigh'

Output
Some important logging information
Mejoras de Just Enough Administration
(JEA)
Artículo • 13/04/2023

Just Enough Administration es una nueva característica de WMF 5.0 que permite la
administración basada en roles a través de la comunicación remota de PowerShell.
Amplía la infraestructura existente de punto de conexión restringida existente. Para
hacerlo, permite que usuarios no administradores ejecuten comandos específicos,
scripts y ejecutables como administrador. Esto permite reducir el número de
administradores totales en su entorno y mejorar la seguridad.

Copia restringida de archivos a o desde puntos


de conexión JEA
Ahora puede copiar remotamente archivos a o desde un punto de conexión JEA sin
tener que preocuparse por si el usuario que se conecta puede copiar cualquier otro
archivo del sistema. Esto se puede realizar si configura el archivo PSSC para que monte
una unidad de usuario para los usuarios que se conectan. La unidad de usuario es un
PSDrive nuevo único para cada usuario que se conecta y que se mantiene conectado
entre sesiones. Cuando se usa Copy-Item para copiar archivos a o desde una sesión JEA,
se restringe para que solo permita el acceso a la unidad de usuario. Si intenta copiar
archivos a cualquier otro PSDrive, se producirá un error.

Para configurar la unidad de usuario en el archivo de configuración de la sesión JEA, use


los siguientes campos nuevos:

PowerShell

MountUserDrive = $true
UserDriveMaximumSize = 10485760 # 10 MB

La carpeta de respaldo de la unidad del usuario se creará en


$env:LOCALAPPDATA\Microsoft\Windows\PowerShell\DriveRoots\ . Para cada usuario que se
conecta al punto de conexión, se crea una carpeta con el nombre
$env:USERDOMAIN_$env:USERNAME .

Para usar la unidad de usuario y copiar archivos a o desde un punto de conexión JEA
configurado para exponer la unidad de usuario, use los parámetros -ToSession y -
FromSession en Copy-Item .
PowerShell

# Connect to the JEA endpoint


$jeasession = New-PSSession -ComputerName 'srv01' -ConfigurationName
'UserDemo'

# Copy a file in the local folder to the remote machine.


# Note: you cannot specify the file name or subfolder on the remote machine.
# You must exactly type "User:"
Copy-Item -Path .\SampleFile.txt -Destination User: -ToSession $jeasession

# Copy the file back from the remote machine to your local machine
Copy-Item -Path User:\SampleFile.txt -Destination . -FromSession $jeasession

Después, puede escribir funciones personalizadas para procesar los datos almacenados
en la unidad de usuario y ponerlas a disposición de los usuarios en el archivo de
funcionalidad de roles.

Compatibilidad con las cuentas de servicio


administradas de grupo
En algunos casos, puede que una tarea que tenga que realizar un usuario en una sesión
JEA necesite acceso a recursos más allá de la máquina local. Cuando una sesión JEA está
configurada para usar una cuenta virtual, cualquier intento de tener acceso a esos
recursos parecerá que proviene de la identidad de la máquina local, y no de la cuenta
virtual ni del usuario conectado. En TP5, hemos habilitado la compatibilidad para
ejecutar JEA en el contexto de una cuenta de servicio administrada de grupo, lo que
facilita el acceso a recursos de red mediante una identidad de dominio.

Para configurar una sesión JEA para que se ejecute en una cuenta de gMSA, use la
siguiente clave nueva en el archivo PSSC:

PowerShell

# Provide the name of your gMSA account here (don't include a trailing $)
# The local machine must be privileged to use this gMSA in Active Directory
GroupManagedServiceAccount = 'myGMSAforJEA'

# You cannot configure a JEA endpoint to use both a gMSA and virtual account
# You can leave the RunAsVirtualAccount field commented out or explicitly
set it to false
RunAsVirtualAccount = $false

7 Nota
Las cuentas de servicio administradas de grupo no permiten el ámbito limitado o
de aislamiento de las cuentas virtuales. Cada usuario que se conecta compartirá la
misma identidad de gMSA, que puede tener permisos en toda la empresa. Tenga
mucho cuidado al seleccionar la opción de usar una gMSA; siempre son preferibles
las cuentas virtuales que están limitadas a la máquina local cuando sea posible.

Directivas de acceso condicional


JEA es ideal para limitar lo que alguien puede hacer cuando está conectado a un sistema
para administrarlo, pero ¿qué sucede si también quiere limitar el momento en que
alguien puede usar JEA? Hemos agregado opciones de configuración en los archivos de
configuración de sesión (.pssc) para permitirle especificar grupos de seguridad a los que
debe pertenecer un usuario para establecer una sesión JEA. Esto resulta especialmente
útil si tiene un sistema Just In Time (JIT) en su entorno y quiere que sus usuarios eleven
los privilegios antes de acceder a un punto de conexión JEA con privilegios elevados.

El nuevo campo RequiredGroups en el archivo PSSC le permite especificar la lógica para


determinar si un usuario puede conectarse a JEA. Consiste en especificar una tabla hash
(opcionalmente anidada) que use las claves "And" y "Or" para construir las reglas. Estos
son algunos ejemplos sobre cómo usar este campo:

PowerShell

# Example 1: Connecting users must belong to a security group called


"elevated-jea"
RequiredGroups = @{ And = 'elevated-jea' }

# Example 2: Connecting users must have signed on with 2 factor


authentication or a smart card
# The 2 factor authentication group name is "2FA-logon" and the smart card
group name is "smartcard-logon"
RequiredGroups = @{ Or = '2FA-logon', 'smartcard-logon' }

# Example 3: Connecting users must elevate into "elevated-jea" with their


JIT system and have logged on with 2FA or a smart card
RequiredGroups = @{ And = 'elevated-jea', @{ Or = '2FA-logon', 'smartcard-
logon' }}

Solucionado: las cuentas virtuales ahora son


compatibles con Windows Server 2008 R2
En WMF 5.1, ahora puede usar cuentas virtuales en Windows Server 2008 R2, lo que
permite configuraciones coherentes y paridad de funcionalidades en Windows Server
2008 R2 - 2016. Las cuentas virtuales siguen sin admitirse al usar JEA en Windows 7.
Mejoras en la administración de
paquetes en WMF 5.1
Artículo • 13/04/2023

Estas son las correcciones realizadas en WMF 5.1:

Alias de versión
Escenario: si tiene las versiones 1.0 y 2.0 de un paquete (P1) instaladas en el sistema y
quiere desinstalar la versión 1.0, ejecutaría Uninstall-Package -Name P1 -Version 1.0 y
esperaría que se desinstalara la versión 1.0 después de ejecutar el cmdlet. Sin embargo,
el resultado es que se desinstala la versión 2.0.

Esto se debe a que el parámetro -Version es un alias del parámetro -MinimumVersion .


Cuando PackageManagement busca un paquete cualificado con la versión mínima 1.0,
devuelve la versión más reciente. Este comportamiento es el esperable en los casos
normales, ya que el resultado que se suele desear es que se busque la versión más
reciente. En cambio, no se debe aplicar al caso Uninstall-Package .

Solución: el alias -Version se ha quitado completamente en PackageManagement


(también conocido como OneGet) y PowerShellGet.

Varios mensajes para arrancar el proveedor de


NuGet
Escenario: cuando ejecuta Find-Module o Install-Module u otros cmdlets de
PackageManagement en un equipo por primera vez, PackageManagement intenta
arrancar el proveedor de NuGet, ya que el proveedor de PowerShellGet también usa el
proveedor de NuGet para descargar los módulos de PowerShell. Luego,
PackageManagement pide permiso al usuario para instalar el proveedor de NuGet. Una
vez que el usuario selecciona "yes" en el arranque, se instalará la versión más reciente
del proveedor de NuGet.

En cambio, en algunos casos, si tiene una versión anterior del proveedor de NuGet
instalada en el equipo, a veces se carga primero la versión anterior de NuGet en la
sesión de PowerShell (esa es la condición de carrera en PackageManagement). En
cambio, PowerShellGet requiere la versión posterior del proveedor de NuGet para
funcionar, por lo que PowerShellGet solicita a PackageManagement que vuelva a
arrancar el proveedor de NuGet. Esto genera varios mensajes para arrancar el proveedor
de NuGet.

Solución: en WMF 5.1, PackageManagement carga la versión más reciente del


proveedor de NuGet para evitar varios mensajes de arranque del proveedor de NuGet.

Otra posible solución es la eliminación manual de la versión anterior del proveedor de


NuGet (NuGet-Anycpu.exe) desde
$env:ProgramFiles\PackageManagement\ProviderAssemblies
$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies

Compatibilidad de PackageManagement en
equipos con solo acceso a la intranet
Escenario: en el escenario empresarial, los usuarios trabajan en un entorno en el que no
hay acceso a Internet, solo a la intranet. PackageManagement no admitía este caso en
WMF 5.0.

Escenario: en WMF 5.0, PackageManagement no era compatible con equipos que solo
tuvieran acceso a la intranet (pero no a Internet).

Solución: en WMF 5.1, puede seguir estos pasos para que los equipos de la intranet
usen PackageManagement:

1. Descargue el proveedor de NuGet desde otro equipo con conexión a Internet


mediante Install-PackageProvider -Name NuGet .

2. Busque el proveedor de NuGet en


$env:ProgramFiles\PackageManagement\ProviderAssemblies\nuget o
$env:LOCALAPPDATA\PackageManagement\ProviderAssemblies\nuget .

3. Copie los archivos binarios a una carpeta o ubicación de recurso compartido de


red a la que pueda tener acceso el equipo de la intranet y, luego, instale el
proveedor de NuGet con Install-PackageProvider -Name NuGet -Source <Path to
folder> .

Mejoras del registro de eventos


Al instalar paquetes, se cambia el estado del equipo. En WMF 5.1, ahora
PackageManagement registra eventos en el registro de eventos de Windows para las
actividades de Install-Package , Uninstall-Package y Save-Package . El registro de
eventos es el mismo que para PowerShell; es decir, Microsoft-Windows-PowerShell,
Operational .

Compatibilidad con la autenticación básica


En WMF 5.1, PackageManagement admite la búsqueda e instalación de paquetes de un
repositorio que requiera autenticación básica. Puede proporcionar las credenciales para
los cmdlets Find-Package y Install-Package . Por ejemplo:

PowerShell

Find-Package -Source <SourceWithCredential> -Credential (Get-Credential)

Compatibilidad para usar PackageManagement


detrás de un proxy
En WMF 5.1, ahora PackageManagement toma nuevos parámetros de proxy -
ProxyCredential y -Proxy . Mediante estos parámetros, es posible especificar la

dirección URL y las credenciales del proxy en los cmdlets de PackageManagement. De


forma predeterminada, se utiliza la configuración del proxy del sistema. Por ejemplo:

PowerShell

Find-Package -Source https://www.nuget.org/api/v2/ -Proxy


http://www.myproxyserver.com -ProxyCredential (Get-Credential)
Registro de inventario de software (SIL)
Artículo • 13/04/2023

) Importante

Al instalar WMF 5.x en un servidor de Windows Server 2012 R2 que ya ejecuta SIL,
es necesario ejecutar el cmdlet Start-SilLogging después de la instalación de WMF,
ya que el proceso de instalación detendrá por error la característica Registro de
inventario de software.

La característica Registro de inventario de software ayuda a reducir los costos operativos


derivados de la obtención de información precisa sobre el software de Microsoft
instalado de forma local en un servidor y, en especial, en numerosos servidores en un
entorno de TI (suponiendo que esté instalado y se ejecute en dicho entorno). Siempre
que haya uno configurado, puede reenviar estos datos a un servidor de agregación y
recopilar los datos de registro en un mismo lugar mediante un proceso automático y
uniforme.

Aunque también se pueden registrar datos de inventario de software con una consulta
directa a cada equipo, la característica Registro de inventario de software puede,
mediante una arquitectura de reenvío (a través de la red) que se inicia en cada servidor,
superar los retos de detección de servidores típicos en muchos escenarios relativos al
inventario y a la administración de activos de software. Registro de inventario de
software usa SSL para proteger los datos que se reenvían a través de HTTPS a un
servidor de agregación. Almacenar los datos en un mismo lugar facilita su análisis y
manipulación, así como compartirlos cuando sea necesario.

Estos datos no se envían a Microsoft como parte de la funcionalidad de la característica.


Solo el propietario con licencia del software del servidor y los administradores pueden
hacer uso de los datos y de la funcionalidad del registro de inventario de software.

Para más información y documentación sobre los cmdlets de Registro de inventario de


software, consulte Administrar el Registro de inventario de software en
Windows Server 2012 R2.
Estado de compatibilidad de producto
Artículo • 13/04/2023

Compatible
Los sistemas que ejecutan las siguientes aplicaciones de servidor pueden ejecutar
Windows Management Framework 5.1:

Microsoft SharePoint Server 2013


Skype Empresarial Server 2015
Microsoft Lync Server 2013
System Center 2012 Configuration Manager

7 Nota

La compatibilidad de Skype Empresarial Server 2015 con WMF 5.1 se ha probado


únicamente con Windows Server 2012 R2.

No probado
Los sistemas que ejecutan las siguientes aplicaciones de servidor no se han probado
con Windows Management Framework 5.1:

Microsoft SharePoint Server 2010


System Center 2012 Virtual Machine Manager

No compatible
Los sistemas que ejecutan las siguientes aplicaciones de servidor no deberían ejecutar
Windows Management Framework 5.1:

Microsoft Exchange Server 2013


Microsoft Exchange Server 2010 SP3
Microsoft Lync Server 2010
System Center 2012 R2 Service Management Automation
Problemas conocidos de WMF 5.0
Artículo • 13/04/2023

Los accesos directos de PowerShell se


interrumpen cuando se usan por primera vez
Resolución: realice una de las acciones siguientes.

1. Haga clic con el botón derecho en el acceso directo de PowerShell. Seleccione


"Windows PowerShell" para iniciar en modo sin privilegios elevados.
2. Haga clic con el botón derecho en el acceso directo de PowerShell. Haga clic en
"Windows PowerShell" y seleccione "Ejecutar como administrador" para iniciar en
modo con privilegios elevados.

Después de llevar a cabo cualquiera de las acciones anteriores, los accesos directos de
PowerShell funcionarán. Estas acciones deben realizarse una sola vez.

Los módulos de PowerShell y los recursos de


DSC notifican errores sobre ExecutionPolicy en
Windows 7
En Windows 7, el uso de módulos de PowerShell y recursos de DSC puede provocar la
notificación de errores sobre ExecutionPolicy.

Resolución: establezca ExecutionPolicy en RemoteSigned. Para ello, ejecute el siguiente


comando en una sesión de PowerShell con privilegios elevados (Ejecutar como
administrador):

PowerShell

Set-ExecutionPolicy RemoteSigned

La conexión a un punto de conexión de


Exchange remoto antiguo causa un bloqueo
El punto de conexión de Exchange le redirige a un nuevo punto de conexión. Hay un
error en la lógica de redirección que causa un bloqueo.
Resolución: realice la conexión directamente al nuevo punto de conexión.

La característica Registro de inventario de


software se detiene erróneamente después de
la instalación de WMF 5.0 en Windows Server
2012 R2
Al instalar WMF 5.0 en un sistema Windows Server 2012 R2 que ya ejecuta SIL, la
característica Registro de inventario de software de detiene por error después de la
instalación.

Resolución: ejecute el cmdlet Start-SilLogging una vez después de la instalación de


WMF, ya que el proceso de instalación detendrá por error la característica Registro de
inventario de software.

Get-ChildItem no funciona si -LiteralPath y –


Recurse se usan juntos.
Si un nombre de directorio contiene un carácter comodín no válido, Get-ChildItem no
producirá los resultados esperados si -LiteralPath y -Recurse se usan juntos.

Resolución: no es lo ideal, pero la solución actual es implementar la recursividad en el


script en lugar de depender del cmdlet.

Se produce un error de Sysprep después de la


instalación de WMF 5.0
Hay dos soluciones alternativas para este problema según la versión de Windows Server
que se ejecute.

Resolución:

Para sistemas que ejecutan Windows Server 2008 R2

1. Abra PowerShell como administrador.

2. Ejecute el siguiente comando.

PowerShell
Set-SilLogging -TargetUri https://BlankTarget -
CertificateThumbprint 0123456789

3. Ejecute el comando y omita el error, tal como se espera.

PowerShell

Publish-SilData

4. Elimine los archivos del directorio \Windows\System32\Logfiles\SIL\.

PowerShell

Remove-Item -Recurse $env:SystemRoot\System32\Logfiles\SIL\

5. Instale todas las actualizaciones disponibles de Windows importantes y


comience a utilizar Sysyprep con normalidad.

Para sistemas que ejecutan Windows Server 2012

1. Después de instalar WMF 5.0 en el servidor para la preparación del sistema


con Sysprep, inicie sesión como administrador.

2. Copie Generize.xml desde el directorio


\Windows\System32\Sysprep\ActionFiles\ a una ubicación fuera del directorio
de Windows, por ejemplo, C:\ .

3. Abra la copia de Generalize.xml con el Bloc de notas.

4. Busque y quite el texto siguiente; hay que eliminar una instancia de cada caso
(se encuentran casi al final del documento).

XML

<sysprepOrder order="0x3200"></sysprepOrder>
<sysprepOrder order="0x3300"></sysprepOrder>

5. Guarde la copia modificada de Generalize.xml y cierre el archivo.

6. Abra una ventana del símbolo del sistema como administrador.

7. Ejecute el siguiente comando para adquirir la titularidad del archivo


Generalize.xml en la carpeta system32:
PowerShell

Takeown /f C:\Windows\System32\Sysprep\ActionFiles\Generalize.xml

8. Ejecute el siguiente comando para establecer los permisos adecuados en el


archivo:

PowerShell

Cacls C:\Windows\System32\ Sysprep\ActionFiles\Generalize.xml /G


`<AdministratorUserName>`:F

Responda de manera afirmativa cuando se le solicite confirmación.


Tenga en cuenta que <AdministratorUserName> se debe reemplazar por el
nombre de usuario administrador en el equipo. Por ejemplo,
"Administrador".

9. Copie el archivo modificado que ha guardado en el directorio Sysprep; para


ello, use el comando siguiente:

PowerShell

xcopy C:\Generalize.xml
C:\Windows\System32\Sysprep\ActionFiles\Generalize.xml

Responda de manera afirmativa para sobrescribir (tenga en cuenta que si


no aparece ningún mensaje para sobrescribir, debe comprobar la ruta de
acceso especificada).
Se supone que la copia modificada de Generalize.xml se ha copiado en C:\.

10. Generalize.xml se ha actualizado con la solución alternativa. Ejecute Sysprep


con la opción de generalizar habilitada.
Problemas conocidos de WMF 5.1
Artículo • 13/04/2023

Inicio del acceso directo de PowerShell como


administrador
Al instalar WMF, si intenta iniciar PowerShell como administrador desde el acceso
directo, puede obtener el mensaje "Error no especificado". Vuelva a abrir el acceso
directo como no administrador y este ya funcionará incluso como administrador.

Pester
En esta versión, hay dos problemas que deben tenerse en cuenta cuando se utilice
Pester en Nano Server:

La realización de pruebas en el propio Pester puede provocar errores debido a las


diferencias entre FULL CLR y CORE CLR. En concreto, el método Validate no está
disponible en el tipo XmlDocument. Se sabe que seis pruebas que intentan validar
el esquema de los registros de salida de NUnit generan un error.
Una prueba de cobertura de código genera un error porque el recurso de DSC
WindowsFeature no existe en Nano Server. Sin embargo, estos errores suelen ser
poco preocupantes y pueden ignorarse.

Validación de operaciones
Se produce un error de Update-Help para el módulo
Microsoft.PowerShell.Operation.Validation porque el URI de ayuda no funciona.

DSC después de desinstalar WMF


La desinstalación de WMF no elimina los documentos MOF de DSC desde la
carpeta de configuración. DSC no funcionará correctamente si los documentos
MOF contienen propiedades más recientes que no están disponibles en los
sistemas más antiguos. En este caso, ejecute el siguiente script desde la consola de
PowerShell con privilegios elevados para limpiar los estados de DSC.

PowerShell
$PreviousDSCStates = @("$env:windir\system32\configuration\*.mof",
"$env:windir\system32\configuration\*.mof.checksum",
"$env:windir\system32\configuration\PartialConfiguration\*.mof",

"$env:windir\system32\configuration\PartialConfiguration\*.mof.checksum
"
)
$PreviousDSCStates | Remove-Item -ErrorAction SilentlyContinue -Verbose

Cuentas virtuales de JEA


Los puntos de conexión de JEA y las configuraciones de sesión configuradas para usar
las cuentas virtuales de WMF 5.0 no se configurará para utilizar una cuenta virtual
después de actualizar a WMF 5.1. Esto significa que los comandos que se ejecutan en
sesiones de JEA se ejecutarán bajo la identidad del usuario que se conecta en lugar de
una cuenta de administrador temporal, impidiendo posiblemente que el usuario ejecute
comandos que requieren privilegios elevados. Para restaurar las cuentas virtuales, debe
anular el registro y volver a registrar las configuraciones de sesión que utilizan las
cuentas virtuales.

PowerShell

# Find the JEA endpoint by its name


$jea = Get-PSSessionConfiguration -Name MyJeaEndpoint

# Copy the cached PSSC file so it can be re-registered


$pssc = Copy-Item $jea.ConfigFilePath $env:temp -PassThru

# Unregister the current PSSC


Unregister-PSSessionConfiguration -Name $jea.Name

# Re-register the PSSC


Register-PSSessionConfiguration -Name $jea.Name -Path $pssc.FullName -Force

# Ensure the access policies remain the same


Set-PSSessionConfiguration -Name $newjea.Name -SecurityDescriptorSddl
$jea.SecurityDescriptorSddl
Problemas y limitaciones conocidos de
la configuración de estado deseado
(DSC)
Artículo • 13/04/2023

Cambio de última hora: los certificados usados


para cifrar o descifrar contraseñas en
configuraciones de DSC no funcionan después
de instalar WMF 5.0 RTM
En las versiones WMF 4.0 y WMF 5.0 Preview, DSC no permitía que las contraseñas de la
configuración tuvieran más de 121 caracteres de longitud. DSC obligaba a usar
contraseñas cortas, aunque se deseasen contraseñas largas y seguras. Este cambio de
última hora permite que las contraseñas tengan una longitud arbitraria en la
configuración de DSC.

Resolución: vuelva a crear el certificado mediante el cifrado de datos o el cifrado de


clave, así como con el uso mejorado de claves de cifrado de documentos
(1.3.6.1.4.1.311.80.1). Para más información, consulte Protect-CmsMessage.

Los cmdlets de DSC puede producir un error


después de instalar WMF 5.0 RTM
Start-DscConfiguration y otros cmdlets de DSC pueden generar el siguiente error
después de instalar WMF 5.0 RTM:

Output

LCM failed to retrieve the property PendingJobStep from the object of class
dscInternalCache .
+ CategoryInfo : ObjectNotFound: (root/Microsoft/...gurationManager:String)
[], CimException
+ FullyQualifiedErrorId : MI RESULT 6
+ PSComputerName : localhost

Resolución: elimine DSCEngineCache.mof. Para ello, ejecute el siguiente comando en


una sesión de PowerShell con privilegios elevados (Ejecutar como administrador):
PowerShell

Remove-Item -Path $env:SystemRoot\system32\Configuration\DSCEngineCache.mof

Es posible que los Cmdlets de DSC no


funcionen si WMF 5.0 RTM se instala encima de
WMF 5.0 Production Preview
Resolución: ejecute el siguiente comando en una sesión de PowerShell con privilegios
elevados (Ejecutar como administrador):

PowerShell

mofcomp $env:windir\system32\wbem\DscCoreConfProv.mof

LCM puede entrar en un estado inestable al


usar Get-DscConfiguration en DebugMode
Si LCM está en DebugMode, al presionar CTRL+C para detener el procesamiento de
Get-DscConfiguration puede causar que LCM entre en un estado inestable que impida

funcionar a la mayoría de los cmdlets de DSC.

Resolución: No presione CTRL+C mientras se depura el cmdlet Get-DscConfiguration .

Stop-DscConfiguration puede no responder en


DebugMode
Si LCM está en DebugMode, es posible que Stop-DscConfiguration no responde
mientras se intenta detener una operación iniciada por Get-DscConfiguration

Resolución: Finalice la depuración de la operación iniciada por Get-DscConfiguration


como se describe en Depuración de recursos de DSC.

No se muestran mensajes de error detallados


en DebugMode
Si LCM está en DebugMode, no se muestra ningún mensaje de error detallado de
recursos de DSC.

Resolución: deshabilite DebugMode para ver mensajes detallados del recurso

Las operaciones Invoke-DscResource no se


pueden recuperar mediante el cmdlet Get-
DscConfigurationStatus
Después de usar el cmdlet Invoke-DscResource para invocar directamente los métodos
de cualquier recurso, los registros de dicha operación no se pueden recuperar a través
de Get-DscConfigurationStatus .

Resolución: Ninguno.

Get-DscConfigurationStatus devuelve
operaciones de ciclo de extracción como de
tipo Consistency
Cuando un nodo se establece en modo de actualización de extracción, para cada
operación de extracción realizada, el cmdlet Get-DscConfigurationStatus indica el tipo
de operación como Consistency en lugar de Initial

Resolución: Ninguno.

El cmdlet Invoke-DscResource no devuelve los


mensajes en el orden en que se producen
El cmdlet Invoke-DscResource no devuelve los mensajes detallados, de advertencia ni de
error en el orden en que los producen LCM o el recurso de DSC.

Resolución: Ninguno.

Los recursos de DSC no se pueden depurar


fácilmente cuando se usan con Invoke-
DscResource
Cuando LCM se ejecuta en modo de depuración, el cmdlet Invoke-DscResource no
brinda información sobre el espacio de ejecución al cual conectarse para la depuración.
Para más información, consulte Depuración de recursos de DSC.

Resolución: Descubra el espacio de ejecución y conéctese a él mediante los cmdlets


Get-PSHostProcessInfo , Enter-PSHostProcess , Get-Runspace y Debug-Runspace para

depurar el recurso de DSC.

PowerShell

# Find all the processes hosting PowerShell


Get-PSHostProcessInfo

ProcessName ProcessId AppDomainName


----------- --------- -------------
powershell 3932 DefaultAppDomain
powershell_ise 2304 DefaultAppDomain
WmiPrvSE 3396 DscPsPluginWkr_AppDomain

# Enter the process that is hosting DSC engine (WMI process with
DscPsPluginWkr_Appdomain)
Enter-PSHostProcess -Id 3396 -AppDomainName DscPsPluginWkr_AppDomain

# Find all the available rusnspaces in that process


Get-Runspace

Id Name ComputerName Type State Availability


-- ---- ------------ ---- ----- ------------
2 Runspace2 localhost Local Opened InBreakpoint
5 RemoteHost localhost Local Opened Busy

# Debug the runspace that is in **InBreakpoint** availability state


Debug-Runspace -Id 2

Varios documentos de configuración parcial


para el mismo nodo no pueden tener nombres
de recurso idénticos
Para varias configuraciones parciales implementadas en un mismo nodo, los nombres
idénticos de recursos causan un error en tiempo de ejecución.

Resolución: use nombres diferentes para la mismos recursos en distintas


configuraciones parciales.
Start-DscConfiguration –UseExisting no
funciona con -Credential
Si se usa Start-DscConfiguration con el parámetro UseExisting, se omite el parámetro
Credential. DSC usa la identidad de proceso predeterminada para continuar la
operación. Esto provoca un error cuando se necesita una credencial distinta para
continuar en el nodo remoto.

Resolución: use una sesión CIM para las operaciones remotas de DSC:

PowerShell

$session = New-CimSession -ComputerName $node -Credential $credential


Start-DscConfiguration -UseExisting -CimSession $session

Direcciones IPv6 como nombres de nodo en


configuraciones de DSC
No se admiten direcciones IPv6 como nombres de nodo en los scripts de configuración
de DSC en esta versión.

Resolución: Ninguno.

Depuración de recursos de DSC Class-Based


En esta versión no se admite la depuración de los recursos de DSC basado en clases.

Resolución: Ninguno.

Las variables y las funciones que se definen en


el ámbito de $script en el recurso basado en
clases de DSC no se conservan en varias
llamadas a un recurso de DSC
Varias llamadas consecutivas a Start-DSCConfiguration producirán un error si la
configuración usa cualquier recurso basado en clases que tenga variables o funciones
definidas en el ámbito de $script .
Resolución: defina todas las variables y funciones de la propia clase de recurso de DSC.
No usar funciones o variables de ámbito $script .

Depuración de recursos de DSC cuando un


recurso usa PSDscRunAsCredential
La depuración de recursos de DSC cuando un recurso usa la propiedad
PSDscRunAsCredential en la configuración no se admite en esta versión.

Resolución: Ninguno.

PsDscRunAsCredential no se admite para los


recursos compuestos de DSC
Resolución: use la propiedad Credential si está disponible. ServiceSet y
WindowsFeatureSet de ejemplo

Get-DscResource -Syntax no refleja


PsDscRunAsCredential correctamente
El parámetro Syntax no refleja correctamente la propiedad PsDscRunAsCredential
cuando el recurso la marca como obligatoria o no la admite.

Resolución: Ninguno. Sin embargo, la configuración de creación en ISE refleja los


metadatos correctos acerca de la propiedad PsDscRunAsCredential al usar IntelliSense.

WindowsOptionalFeature no está disponible en


Windows 7
El recurso de DSC WindowsOptionalFeature no está disponible en Windows 7. Este
recurso requiere el módulo DISM, así como los cmdlets DISM que están disponibles a
partir de Windows 8 y versiones más recientes del sistema operativo Windows.

En el caso de los recursos de DSC basados en


clases, puede que Import-DscResource -
ModuleVersion no funcione según lo previsto
Si el nodo de compilación tiene varias versiones de un módulo de recursos de DSC
basados en clases, Import-DscResource -ModuleVersion no podrá seleccionar la versión
especificada y genera el siguiente error de compilación.

Output

ImportClassResourcesFromModule : Exception calling


"ImportClassResourcesFromModule" with "3" argument(s):
"Keyword 'MyTestResource' already defined in the configuration."
At
C:\Windows\system32\WindowsPowerShell\v1.0\Modules\PSDesiredStateConfigurati
on\PSDesiredStateConfiguration.psm1:2035 char:35
+ ... rcesFound = ImportClassResourcesFromModule -Module $mod -Resources $r
...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:)
[ImportClassResourcesFromModule], MethodInvocationException
+ FullyQualifiedErrorId :
PSInvalidOperationException,ImportClassResourcesFromModule

Resolución: importe la versión necesaria mediante la defición del objeto


ModuleSpecification al parámetro ModuleName con la clave RequiredVersion
especificada como sigue:

PowerShell

Import-DscResource -ModuleName
@{ModuleName='MyModuleName';RequiredVersion='1.2'}

Algunos recursos de DSC, como el recurso de


registro, pueden comenzar a tardar mucho
tiempo en procesar la solicitud.
Solución 1: cree una tarea de programación que limpie periódicamente la siguiente
carpeta.

PowerShell

$env:windir\system32\config\systemprofile\AppData\Local\Microsoft\Windows\Po
werShell\CommandAnalysis

Solución 2: cambie la configuración de DSC para limpiar la carpeta CommandAnalysis al


final de la configuración.
PowerShell

Configuration $configName
{

# User Data
Registry SetRegisteredOwner
{
Ensure = 'Present'
Force = $True
Key = $Node.RegisteredKey
ValueName = $Node.RegisteredOwnerValue
ValueType = 'String'
ValueData = $Node.RegisteredOwnerData
}
#
# Script to delete the config
#
script DeleteCommandAnalysisCache
{
DependsOn = "[Registry]SetRegisteredOwner"
getscript = "@{}"
testscript = 'Remove-Item -Path
$env:windir\system32\config\systemprofile\AppData\Local\Microsoft\Windows\Po
werShell\CommandAnalysis -Force -Recurse -ErrorAction SilentlyContinue -
ErrorVariable ev | out-null;$true'
setscript = '$true'
}
}
Iniciar Windows PowerShell
Artículo • 08/05/2023

Windows PowerShell es una .DLL de motor de scripting que se inserta en varios hosts.
Los hosts más comunes que iniciará son la línea de comandos interactiva
powershell.exe y el entorno de scripting interactivo powershell_ise.exe .

Para iniciar Windows PowerShell en Windows Server 2012 R2, Windows 8.1,
Windows Server 2012 y Windows 8, vea Navegación y tareas de administración
comunes en Windows.

PowerShell ha cambiado el nombre del archivo


binario.
PowerShell versión 6 y posteriores utilizan .NET Core. Las versiones compatibles están
disponibles en Windows, macOS y Linux.

A partir de PowerShell 6, el nombre del archivo binario de PowerShell cambió a


pwsh.exe para Windows y a pwsh para macOS y Linux. Puede iniciar las versiones

preliminares de PowerShell mediante pwsh-preview . Para más información, consulte


Acerca de pwsh.

Para acceder a la documentación de la instalación y la referencia de cmdlets de


PowerShell 7, use los vínculos siguientes:

Documento Link

Referencia de cmdlets Explorador de módulos de PowerShell

Instalación de Windows Instalación de PowerShell en Windows

Instalación de macOS Instalación de PowerShell en macOS

Instalación de Linux Instalación de PowerShell en Linux

Para ver el contenido de otras versiones de PowerShell, vea Cómo usar la


documentación de PowerShell.

Iniciar Windows PowerShell en versiones


anteriores de Windows
En esta sección se explica cómo iniciar Windows PowerShell y el Entorno de scripting
integrado (ISE) de Windows PowerShell en Windows 7, Windows Server 2008 R2 y
Windows Server 2008. También se explica cómo habilitar la característica opcional para
Windows PowerShell ISE de Windows PowerShell 2.0 en Windows Server 2008 R2 y
Windows Server 2008.

Use cualquiera de los métodos siguientes para iniciar la versión instalada de Windows
PowerShell 3.0 o Windows PowerShell 4.0, según corresponda.

Desde el menú Inicio


Haga clic en Inicio, escriba ISE y, después, haga clic en Windows PowerShell.
Desde el menú Inicio, haga clic en Inicio, Todos los programas, Accesorios, la
carpeta Windows PowerShell y, luego, en Windows PowerShell.

En el símbolo del sistema


En el shell de comandos de Windows, Windows PowerShell o Windows PowerShell ISE,
para iniciar Windows PowerShell, escriba PowerShell .

También puede usar los parámetros del programa powershell.exe para personalizar la
sesión. Para obtener más información, consulte Ayuda de línea de comandos de
PowerShell.exe.

Con privilegios administrativos (Ejecutar como


administrador)
Haga clic en Inicio, escriba PowerShell, haga clic con el botón derecho en Windows
PowerShell y, después, haga clic en Ejecutar como administrador.

Iniciar Windows PowerShell ISE en versiones


anteriores de Windows
Use cualquiera de los métodos siguientes para iniciar Windows PowerShell ISE.

Desde el menú Inicio


Haga clic en Inicio, escriba ISE y, después, haga clic en Windows PowerShell ISE.
Desde el menú Inicio, haga clic en Inicio, Todos los programas, Accesorios, la
carpeta Windows PowerShell y, luego, en Windows PowerShell ISE.
En el símbolo del sistema
En el shell de comandos de Windows, Windows PowerShell o Windows PowerShell ISE,
para iniciar Windows PowerShell, escriba PowerShell_ISE . En Windows PowerShell,
puede usar el alias ise .

Con privilegios administrativos (Ejecutar como


administrador)
Haga clic en Inicio, escriba ISE, haga clic con el botón derecho en Windows PowerShell
ISE y, después, haga clic en Ejecutar como administrador.

Habilitar Windows PowerShell ISE en versiones


anteriores de Windows
En Windows PowerShell 4.0 y Windows PowerShell 3.0, Windows PowerShell ISE está
habilitado de forma predeterminada en todas las versiones de Windows. Si aún no está
habilitado, Windows Management Framework 4.0 o Windows Management
Framework 3.0 lo habilitan.

En Windows PowerShell 2.0, Windows PowerShell ISE está habilitado de forma


predeterminada en Windows 7. Sin embargo, en Windows Server 2008 R2 y
Windows Server 2008, es una característica opcional.

Para habilitar Windows PowerShell ISE de Windows PowerShell 2.0 en Windows Server
2008 R2 o Windows Server 2008, use el procedimiento siguiente.

Habilitar el Entorno de scripting integrado (ISE) de


Windows PowerShell
1. Inicie el Administrador del servidor.
2. Haz clic en Características y, a continuación, en Agregar características.
3. En Seleccionar características, haga clic en Entorno de scripting integrado (ISE) de
Windows PowerShell.

Iniciar la versión de 32 bits de Windows


PowerShell
Al instalar Windows PowerShell en un equipo de 64 bits, Windows PowerShell (x86) , se
instala una versión de 32 bits de Windows PowerShell además de la versión de 64 bits.
Al ejecutar Windows PowerShell, la versión de 64 bits se ejecuta de forma
predeterminada.

Sin embargo, en ocasiones, deberá ejecutar Windows PowerShell (x86) , como cuando
usa un módulo que requiere la versión de 32 bits o cuando se conecta de forma remota
a un equipo de 32 bits.

Para iniciar una versión de 32 bits de Windows PowerShell, use uno de los
procedimientos siguientes.

En Windows Server 2012 R2


En la pantalla Inicio, escriba Windows PowerShell (x86). Haga clic en el icono
Windows PowerShell x86.
En Administrador del servidor, desde el menú Herramientas, seleccione Windows
PowerShell (x86).
En el escritorio, mueva el cursor a la esquina superior derecha, haga clic en Buscar,
escriba PowerShell x86 y, a continuación, haga clic en Windows PowerShell (x86) .
Mediante la línea de comandos, escriba:
%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe

En Windows 8.1
En la pantalla Inicio, escriba Windows PowerShell (x86). Haga clic en el icono
Windows PowerShell x86.
Si ejecuta Herramientas de administración remota del servidor para
Windows 8.1, también puede abrir Windows PowerShell x86 desde el menú
Herramientas del Administrador del servidor. Seleccione Windows PowerShell
(x86).
En el escritorio, mueva el cursor a la esquina superior derecha, haga clic en Buscar,
escriba PowerShell x86 y, a continuación, haga clic en Windows PowerShell (x86) .
Mediante la línea de comandos, escriba:
%SystemRoot%\SysWOW64\WindowsPowerShell\v1.0\powershell.exe
Uso del motor de Windows PowerShell
2.0
Artículo • 21/03/2023

Windows PowerShell está diseñado para ser compatible con versiones anteriores. Los
cmdlets, proveedores, complementos, módulos y scripts escritos para Windows
PowerShell 2.0 se ejecutan sin cambios en versiones posteriores de Windows
PowerShell. Sin embargo, en Microsoft .NET Framework 4 se cambió la directiva de
activación en tiempo de ejecución. Los programas host de Windows PowerShell escritos
para Windows PowerShell 2.0 y compilados con Common Language Runtime (CLR) 2.0
no se pueden ejecutar sin modificaciones en las nuevas versiones de Windows
PowerShell compiladas con CLR 4.0 (o posterior).

El motor de Windows PowerShell 2.0 está destinado a usarse solo cuando un programa
host o un script existente no se puede ejecutar porque es incompatible con Windows
PowerShell 5.1. Algunos ejemplos de ello son las versiones anteriores de Exchange o los
módulos de SQL Server. Estos casos deben ser infrecuentes.

Muchos programas que requieren el motor de Windows PowerShell 2.0 lo inician


automáticamente. Estas instrucciones se incluyen para las situaciones excepcionales en
que necesite iniciar el motor de forma manual.

Problemas de desuso y seguridad


Windows PowerShell 2.0 quedó en desuso en agosto de 2017. Para obtener más
información, consulte el anuncio en el blog de PowerShell.

En Windows PowerShell 2.0 faltan una cantidad significativa de las características de


protección y seguridad agregadas en las versiones 3, 4 y 5. Recomendamos
encarecidamente que los usuarios no usen esa versión si es posible. Para obtener más
información, consulte Comparación de la seguridad de Shell y del lenguaje de
scripting y PowerShell ♥ el Equipo Azul .

Instalar y habilitar los programas requeridos


Antes de iniciar el motor de Windows PowerShell 2.0, habilite el motor de Windows
PowerShell 2.0 y Microsoft .NET Framework 3.5 con Service Pack 1. Para obtener
instrucciones, consulte Instalación de Windows PowerShell.
Los sistemas con Windows Management Framework 3.0 o posterior instalado tienen
todos los componentes necesarios. No es necesario realizar ninguna otra configuración.
Para obtener información acerca de cómo instalar Windows Management Framework,
consulte Instalación y configuración de WMF.

Iniciar el motor de Windows PowerShell 2.0


Al iniciar Windows PowerShell, se inicia la versión más reciente de forma
predeterminada. Para iniciar Windows PowerShell con el motor de Windows PowerShell
2.0, use el parámetro Version de PowerShell.exe . Puede ejecutar el comando en
cualquier símbolo del sistema, incluidos Windows PowerShell y Cmd.exe.

PowerShell.exe -Version 2

Iniciar una sesión remota con el motor de


Windows PowerShell 2.0
Para ejecutar el motor de Windows PowerShell 2.0 en una sesión remota, cree una
configuración de sesión (también conocida como punto de conexión) en el equipo
remoto que carga el motor de Windows PowerShell 2.0. La configuración de sesión se
guarda en el equipo remoto y puede usarla cualquier usuario autorizado para crear
sesiones que usen el motor de Windows PowerShell 2.0.

Se trata de una tarea avanzada que suele realizarla un administrador del sistema.

El siguiente procedimiento usa el parámetro PSVersion del cmdlet Register-


PSSessionConfiguration para crear una configuración de sesión que use el motor de
Windows PowerShell 2.0. También puede usar el parámetro PowerShellVersion del
cmdlet New-PSSessionConfigurationFile para crear un archivo de configuración de
sesión para una sesión que cargue el motor de Windows PowerShell 2.0 y el parámetro
PSVersion del cmdlet Set-PSSessionConfiguration para cambiar una configuración de
sesión para que use el motor de Windows PowerShell 2.0.

Para obtener más información sobre los archivos de configuración de sesión, consulte
about_Session_Configuration_Files. Para obtener información sobre las configuraciones
de sesión, incluida la configuración y la seguridad, consulte
about_Session_Configurations.
Iniciar una sesión de Windows PowerShell 2.0
1. Para crear una configuración de sesión que requiera el motor de Windows
PowerShell 2.0, use el parámetro PSVersion del cmdlet Register-
PSSessionConfiguration con un valor de 2.0 . Ejecute este comando en el equipo

en el "lado servidor" o en el extremo receptor de la conexión.

El siguiente comando de ejemplo crea la configuración de sesión PS2 en el equipo


Server01. Para ejecutar este comando, inicie Windows PowerShell con la opción
Ejecutar como administrador.

PowerShell

Register-PSSessionConfiguration -Name PS2 -PSVersion 2.0

2. Para crear una sesión en el equipo Server01 que use la configuración de sesión
PS2, use el parámetro ConfigurationName de los cmdlets que crean una sesión
remota, como el cmdlet `New-PSSession.

Cuando se inicia una sesión que usa la configuración de sesión, el motor de


Windows PowerShell 2.0 se carga automáticamente en la sesión.

El comando siguiente inicia una sesión en el equipo Server01 que usa la


configuración de sesión PS2. El comando guarda la sesión en la variable $s .

PowerShell

$s = New-PSSession -ComputerName Server01 -ConfigurationName PS2

Iniciar un trabajo en segundo plano con el


motor de Windows PowerShell 2.0
Para iniciar un trabajo en segundo plano con el motor de Windows PowerShell 2.0, use
el parámetro PSVersion del cmdlet Start-Job.

El comando siguiente inicia un trabajo en segundo plano con el motor de Windows


PowerShell 2.0.

PowerShell

Start-Job {Get-Process} -PSVersion 2.0


Para obtener más información sobre los trabajos en segundo plano, vea about_Jobs.
Información general sobre Desired State
Configuration (DSC) de PowerShell
Artículo • 13/04/2023

DSC es una plataforma de administración de PowerShell que le permite administrar su


infraestructura de desarrollo y TI con configuración como código.

Hay tres versiones de DSC disponibles:

DSC 1.1 es la versión heredada de DSC que se envió originalmente en Windows


PowerShell 5.1.

DSC 2.0 es la versión de DSC que se incluye en PowerShell 7.

Con la versión PowerShell 7.2, el módulo PSDesiredStateConfiguration ya no se


incluye en el paquete de PowerShell. Separar DSC en su propio módulo nos
permite invertir y desarrollar DSC independientemente de PowerShell y reducir el
tamaño del paquete de PowerShell. Los usuarios de DSC disfrutarán de la ventaja
de actualizar DSC sin necesidad de actualizar PowerShell, lo que acelera el tiempo
de implementación de las nuevas características de DSC. Los usuarios que quieran
seguir usando DSC v2 pueden descargar PSDesiredStateConfiguration 2.0.5 desde
la Galería de PowerShell.

DSC 3.0 es la nueva versión de DSC. Esta versión es una versión preliminar que
todavía se está desarrollando. Los usuarios que trabajan con entornos no Windows
pueden esperar características multiplataforma en DSC 3.0. DSC 3.0 es la versión
que admite la característica de configuración de máquina de Azure Automanage.

La documentación de DSC se ha movido a una nueva ubicación para que podamos


administrar la información específica de la versión de DSC independiente de las
versiones de PowerShell.

Consulte la nueva documentación en Desired State Configuration 2.0.


Galería de PowerShell
Artículo • 17/04/2023

La Galería de PowerShell es el repositorio central del contenido de PowerShell. En ella,


encontrará scripts de PowerShell, módulos que contienen cmdlets de PowerShell y los
recursos de Desired State Configuration (DSC). Algunos de estos paquetes los crea
Microsoft y otros los crea la comunidad de PowerShell.

El módulo PowerShellGet contiene cmdlets para detectar, instalar, actualizar y publicar


paquetes de PowerShell desde la Galería de PowerShell. Estos paquetes pueden
contener artefactos como módulos, recursos de DSC, funcionalidades de rol y scripts.
Asegúrese de tener instalada la versión más reciente de PowerShellGet.

La documentación de PowerShellGet y la Galería de PowerShell se ha movido a una


nueva ubicación para que podamos administrar la información específica de la versión
independiente de las versiones de PowerShell.

Consulte la nueva documentación de PowerShellGet y la Galería de PowerShell.


Actualización de la comunidad
Una lista de recursos y un resumen de los nuevos artículos y las contribuciones de la
comunidad.

Novedades de Docs

h NOVEDADES

Actualizaciones de 2022

Actualizaciones de 2021

Actualizaciones de 2020

Salón de la fama de los colaboradores

Recursos de aprendizaje

オ LEARN

Conceptos básicos sobre PowerShell

Seminarios web de Deep Dive

Módulos de aprendizaje de PowerShell

q VIDEO

Vídeos de Microsoft Virtual Academy

Jason Helmick's: The Show

Canal de PSConfEU

Canal de PowerShell.org

Recursos de la comunidad

e INFORMACIÓN GENERAL

Soporte técnico de la comunidad


a DESCARGAR

Arte digital
Obtención de ayuda de la comunidad
Artículo • 01/03/2022

La comunidad de PowerShell es un grupo de usuarios dinámico y activo. Este artículo


puede ayudarle a ponerse en contacto con otro miembro de la comunidad.

La comunidad de PowerShell puede presentar problemas, errores o solicitudes de


características en nuestro repositorio de GitHub . Si tiene alguna pregunta, puede
encontrar ayuda en otros miembros de la comunidad en uno de estos foros públicos:

Grupos de usuarios
PowerShell Tech Community
Comunidad de DSC
PowerShell.org
StackOverFlow
r/PowerShell subreddit
Grupo de usuarios virtuales de PowerShell; puede unirse a través de:
Slack
Discord

Para información sobre nuestra directiva de soporte técnico, consulte el ciclo de vida de
soporte técnico de PowerShell.
Salón de la fama de los colaboradores
de la comunidad
Artículo • 02/06/2022

La comunidad de PowerShell es un grupo vibrante y colaborativo. Agradecemos


enormemente toda la ayuda y apoyo que nos brinda la comunidad. Obtenga
información sobre cómo puede contribuir leyendo la Guía del colaborador.

A finales de mayo de 2022, estos usuarios GitHub son los principales colaboradores de
Community All-Time.

Solicitudes de incorporación de cambios


combinadas
Las solicitudes de incorporación de cambios nos ayudan a corregir esas incidencias y
mejoran la documentación para todos.

Solicitudes 2015 2016 2017 2018 2019 2020 2021 2022 Total
combinadas de general
solicitudes de
incorporación de
cambios

Comunidad 3 194 446 464 318 161 100 36 1722

matt9ucci 157 80 30 1 6 274

nschonni 14 138 10 162

kiazhi 25 79 12 116

alexandair 57 7 26 2 1 93

doctordns 5 32 20 7 9 5 78

sethvs 1 43 20 1 5 70

yecril71pl 21 3 24

Dan1el42 20 20

NReilingh 2 13 3 18

it-praktyk 16 1 17
Solicitudes 2015 2016 2017 2018 2019 2020 2021 2022 Total
combinadas de general
solicitudes de
incorporación de
cambios

vors 15 1 16

markekraus 11 5 16

kvprasoon 2 1 7 2 2 2 16

purdo17 13 13

skycommand 1 3 3 6 13

k-takai 5 1 7 13

PlagueHO 10 1 11

exchange12rocks 7 3 1 11

Incidencias de GitHub abiertas


Las incidencias de GitHub nos ayudan a identificar errores e intervalos en nuestra
documentación.

Problemas 2015 2016 2017 2018 2019 2020 2021 2022 Total
abiertos general

Comunidad 3 54 95 212 566 562 368 85 1945

mklement0 19 60 56 61 28 224

iSazonov 1 4 10 8 4 27

jszabo98 2 15 6 1 24

juvtib 15 7 22

doctordns 5 3 5 7 1 21

vexx32 3 11 1 15

KirkMunro 7 7 1 15

alexandair 9 4 2 15

clamb123 14 14
Problemas 2015 2016 2017 2018 2019 2020 2021 2022 Total
abiertos general

trollyanov 11 11

rkeithhill 1 2 2 2 3 1 11

JustinGrote 1 3 6 1 11

UberKluger 1 7 2 10

vors 1 6 2 1 10
What's new in PowerShell Docs for 2023
Article • 10/02/2023

This article lists notable changes made to docs each month and celebrates the
contributions from the community.

Help us make the documentation better for you. Read the Contributor's Guide to learn
how to get started.

2023-Sep
New content

How to create a feedback provider

Updated Content

Updated What's new in PowerShell 7.4 for PowerShell 7.4-preview.6


Documented the changes to search scope in How to use the documentation
Updated What's new in Crescendo 1.1 for the GA release
Updated the setup scripts for supported Linux distributions
Updated DSC v3 content for the alpha.3 release

Quality improvement project contributions

@ehmiiz contributed 5 PRs to update 35 files

New Learn platform features

Deployed the new feedback experience at that bottom of each page

Top Community Contributors


GitHub stats

52 PRs merged (9 from Community)


24 issues opened (22 from Community)
24 issues closed (23 Community issues closed)

The following people contributed to PowerShell docs this month by submitting pull
requests or filing issues. Thank you!
GitHub Id PRs merged Issues opened

ehmiiz 5 5

bubbletroubles 1

JamesDBartlett3 1

not-not-kevin 1

skycommand 1

jsilverm 3

mklement0 2

2023-Aug
New content

66 New articles for DSC v3 (alpha)

See Microsoft Desired State Configuration v3 overview to get started with the new
documentation

Updated Content

Crescendo 1.1-RC1 release updates


What's new in Crescendo 1.1

New PSResourceGet beta24 content updates


See Supported repository configurations

Lots updates for the PowerShell 7.4-preview.5 release


What's New in PowerShell 7.4 (preview)
New features for 10 cmdlets

Updated support status and installation notes for Raspberry Pi


Community support for PowerShell on Linux - PowerShell

Top Community Contributors


GitHub stats

29 PRs merged (3 from Community)


16 issues opened (12 from Community)
21 issues closed (17 Community issues closed)

The following people contributed to PowerShell docs this month by submitting pull
requests or filing issues. Thank you!

GitHub Id PRs merged Issues opened

ehmiiz 1 1

crisman 1

deadlydog 1

JamesDBartlett3 1

2023-Jul
Updated content

7.4-preview.4 release notes


Add publish information to Supported repository configurations
Updated the release notes shipped with Get-WhatsNew
Fixed invalid ///-comments in SDK API reference
Updated the man page that ships in PowerShell for Linux and macOS

Top Community Contributors


GitHub stats

31 PRs merged (10 from Community)


21 issues opened (17 from Community)
17 issues closed (13 Community issues closed)

The following people contributed to PowerShell docs this month by submitting pull
requests or filing issues. Thank you!

GitHub Id PRs merged Issues opened

crisman 2 3

TSanzo-BLE 2

MilekJakub 1

Atman-Shastri 1
GitHub Id PRs merged Issues opened

BraveJhawk 1

coolhome 1

johndward01 1

lor3k 1

2023-Jun
New Azure Cloud Shell content

Using Cloud Shell in an Azure virtual network


Deploy Azure Cloud Shell in a VNET with quickstart templates

New PowerShellGet v3 content

Supported repository configurations


Cmdlet reference for Microsoft.PowerShell.PSResourceGet
Cmdlet reference for the PowerShellGet compatibility module

Lot of updates for the PowerShell 7.4-preview.4 release

What's New in PowerShell 7.4 (preview)


Using Experimental Features in PowerShell
New features for 12 cmdlets

Quality Project contributions

@XXLMandalorian013 contributed 3 PRs to update 2 files in the


MicrosoftDocs/windows-docs-powershell repository

Top Community Contributors


GitHub stats

59 PRs merged (15 from Community)


44 issues opened (30 from Community)
47 issues closed (31 Community issues closed)

The following people contributed to PowerShell docs this month by submitting pull
requests or filing issues. Thank you!
GitHub Id PRs merged Issues opened

thegraffix 4

crisman 4 3

RAJU2529 1

dstreefkerk 1

vontompers 1

mubed 1

Frederisk 1

khaffner 1

noamper 1

aksarben 4

2023-May
New content

New cmdlet in 7.4 - Get-SecureRandom


Using Windows Defender Application Control

Updated content

How to use the PowerShell documentation


Added descriptions for various navigation elements on the site
Added information about how to use the new Download PDF feature
Exploring the Windows PowerShell ISE
Added screenshots for the ISE user interface elements
Update documentation for Add-Member
Corrected some parameter values
Improved the description and added examples for the SecondValue parameter

Quality Project contributions

@robderickson contributed 1 PR to update 10 files in the MicrosoftDocs/windows-


docs-powershell repository

Top Community Contributors


GitHub stats

38 PRs merged (7 from Community)


24 issues opened (18 from Community)
20 issues closed (17 Community issues closed)

The following people contributed to PowerShell docs this month by submitting pull
requests or filing issues. Thank you!

GitHub Id PRs merged Issues opened

rwp0 1

pronichkin 1

Ooggle 1

mavaddat 1

IanKemp 1

mcdonaldjc 1

Brizio 1

dotnvo 1

r0bfr 1

mklement0 3

aksarben 2

crisman 2

2023-April
New content

Handling errors in Crescendo


Transforming arguments in Crescendo

Updated content

Updated release notes for PowerShell 7.4-preview.3


Migrated the PowerShell Gallery and PowerShellGet docs to new location to enable
version selectors for PowerShellGet
PowerShell Summit 2023 - Hack-a-Doc event

We hosted a Hack-a-Doc event on April 27th. Special thanks to the following 19


people. They contributed 62 PRs to update 204 files in the
MicrosoftDocs/windows-powershell-docs repository.

GitHub Id name Count of PRs Count of file

RobBiddle Robert Biddle 28 48

pbossman Phil Bossman 1 27

ThomasNieto Thomas Nieto 1 24

kevinCefalu Kevin Cefalu 1 24

robderickson Rob Derickson 4 17

Snozzberries Michael Soule 13 16

Spoonsk Joseph Gast 1 12

thedavecarroll Dave Carroll 1 11

raynbowbrite Vanda Paladino 2 7

majst32 Melissa Januszko 1 6

XXLMandalorian013 Drew McClellan 1 4

ThePoShWolf Anthony Howell 1 1

mdowst Matthew Dowst 1 1

thepowerstring 1 1

KevinMarquette Kevin Marquette 1 1

53883 1 1

zockan Michael Svegmar 1 1

lanwench Paula Kingsley 1 1

stevenjudd Steven Judd 1 1

Grand Total 62 204

Top Community Contributors


GitHub stats
23 PRs merged (2 from Community)
16 issues opened (14 from Community)
17 issues closed (15 Community issues closed)

The following people contributed to PowerShell docs this month by submitting pull
requests or filing issues. Thank you!

GitHub Id PRs merged Issues opened

NLZ 1

Jonathan-Quilter 1

2023-March
New content

Create a class-based DSC Resource for Machine Configuration


Using PSReadLine key handlers

Updated content

Release notes for PowerShell 7.4-preview.2

Quality project updates from the community

One of our top contributors @ehmiiz blogged about contributing to Docs


How to Learn Git, Markdown and PowerShell by Contributing to the PowerShell-
Docs Repository

Top Community Contributors


GitHub stats

60 PRs merged (13 from Community)


44 issues opened (31 from Community)
50 issues closed (36 Community issues closed)

The following people have contributed to PowerShell docs by submitting pull requests
or filing issues. Thank you!

GitHub Id PRs merged Issues opened

skycommand 2
GitHub Id PRs merged Issues opened

martincostello 1

iRon7 1 4

chrullrich 1

FlintyLemming 1

ehmiiz 1

vvavrychuk 1

bb-froggy 1

BenjamimCS 1

kirillkrylov 1

bergmeister 1

lizy14 1

CarloToso 5

MartinGC94 2

rgl 2

2023-February
New Content

Preventing script injection attacks (Thanks @PaulHigin )

Content updates

Major update to about_PowerShell_Config


Update to about_Logging_Non-Windows for macOS instructions
Major update to Class-based DSC Resources and other related articles for DSC v2

Quality project updates from the community

Added alias information to 4 cmdlet articles (Thanks @ehmiiz !)

Top Community Contributors


GitHub stats
35 PRs merged (8 from Community)
20 issues opened (14 from Community)
17 issues closed (10 Community issues closed)

The following people have contributed to PowerShell docs by submitting pull requests
or filing issues. Thank you!

GitHub Id PRs merged Issues opened

joshua-russell 4 1

1NF053C 1

doctordns 1

Hrxn 1

KyleMit 1

VertigoRay 1

ehmiiz 1

ArmaanMcleod 2

mklement0 2

2023-January
New Content

What's new in PowerShell 7.4 (preview)


about_Data_Files

Content updates

Updated docs for 7.4-preview.1 release


Major update to about_Language_Modes
Major update to about_Logging_Non-Windows

Quality project updates from the community

Added alias information to 40 cmdlet articles (Thanks @ehmiiz !)


Added alias information to 52 cmdlet articles (Thanks @szabolevo !)

Top Community Contributors


GitHub stats

71 PRs merged (21 from Community)


53 issues opened (33 from Community)
62 issues closed (40 Community issues closed)

The following people have contributed to PowerShell docs by submitting pull requests
or filing issues. Thank you!

GitHub Id PRs merged Issues opened

ehmiiz 5 5

szabolevo 5 7

anderjef 2

turbedi 1

desk7 1

cobrabr 1

ZYinMD 1

tompazourek 1

kenyon 1

cjvandyk 1

JTBrinkmann 1

mklement0 4

CarloToso 3

KyleMit 2

iRon7 2

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our  Provide product feedback
contributor guide.
Novedades de PowerShell Docs para
2022
Artículo • 02/06/2022

En este artículo se muestran algunos de los cambios importantes en los documentos


durante este mes anterior y se celebran las contribuciones de la comunidad.

Ayúdenos a mejorar para usted la documentación. Lea la Guía del colaborador para
obtener información sobre cómo empezar.

Mayo de 2022
Contenido nuevo

Creación de una configuración de Crescendo mediante los cmdlets de Crescendo


Información general de los módulos SecretManagement y SecretStore
Comenzar con el módulo SecretStore
Descripción del módulo SecretManagement
Administración de un almacén de SecretStore

Actualizaciones de contenido

Se ha cambiado el nombre de la staging rama a . main


Se ha actualizado la tabla de contenido para facilitar la detección.
Se ha movido el ciclo de vida de soporte técnico al nivel superior
Guía de colaborador movido al nivel superior
Notas de la versión 7.3-preview.4
Limpieza de formato masivo para muchos documentos
contenido de PowerShell-Docs: 272 archivos
Administración de secretos: 17 archivos
Se ha actualizado el ARCHIVO LÉAME de PSScriptAnalyzer y los documentos
eliminados que se migraron a docs.microsoft.com
Se ha quitado CentOS y Fedora de la documentación; ya no se admite
Contenido retirado 7.1: ya no se admite
Contraer notas de la versión en un artículo de diferencias
Eliminar o mover contenido al repositorio de archivo

Principales colaboradores de la comunidad


Estadísticas de GitHub
53 SOLICITUDES combinadas (12 de Community)
38 problemas abiertos (21 de Community)
39 problemas cerrados (26 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

tommymaynard 5

naveensrinivasan 2

rikurauhala 1

joshua6point0 1

rhorber 1

Raton-Laveur 1

StephenRoille 1

krlinus 2

Abril de 2022
Contenido nuevo

No hay contenido nuevo este mes

Actualizaciones de contenido

Reescrito de las instrucciones de instalación de PowerShellGet


Artículo independiente creado para instalar PowerShellGet en sistemas de
Windows antiguos

Otros proyectos

PowerShell + DevOps Summit 25-28


Presentación sobre cómo contribuir a Docs
Demostración de Lightning sobre los completadores de argumentos
Entrevista para el podcast de PowerShell

Principales colaboradores de la comunidad


Estadísticas de GitHub

24 SOLICITUDES combinadas (3 de Community)


22 problemas abiertos (17 de Community)
21 problemas cerrados (15 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

Hrxn 1

kevinholtkamp 1

MikeyBronowski 1

tommymaynard 4

Marzo de 2022
Contenido nuevo

Nuevos documentos de PowerShell


about_Member Access_Enumeration
about_Module_Manifests
Creación de un predictor de línea de comandos
Actualizaciones de módulos de utilidad
Nuevos documentos para la versión de Crescendo
Instalación de Crescendo
Elección de una herramienta de línea de comandos
Decidir qué características ampliar
Creación de un cmdlet de Crescendo
Generación y prueba de un módulo crescendo
Tenemos planes para al menos dos documentos más
Traslado de un artículo de PlatyPS desde documentos de PowerShell a la
documentación de PlatyPS
Artículo sobre PlatyPS movido
Se ha migrado más documentación de PSScriptAnalyzer desde el repositorio de
código fuente.
Uso de PSScriptAnalyzer
Reglas y recomendaciones
Creación de reglas personalizadas

Actualizaciones de contenido

Limpieza masiva de vínculos relacionados en temas de About_


Se han agregado plantillas de solicitud de incorporación de cambios y problemas a
todos los repositorios de documentos.
Actualizaciones del contenido de la versión preliminar 7.3
Nuevas finalizaciones de pestañas
Compatibilidad con opciones de SSH en cmdlets de comunicación remota
Nueva característica experimental PSAMSIMethodInvocationLogging

Otros proyectos

Se ha creado un cmdlet Get-WhatsNew de prototipo basado en el borrador de


RFC .
Consulte la RFC y proporcione comentarios.

Nuevo miembro del equipo

Bienvenido a Mikey Lombardi al equipo de documentación

Principales colaboradores de la comunidad


Estadísticas de GitHub

49 SOLICITUDES combinadas (8 de Community)


26 problemas abiertos (14 de Community)
33 problemas cerrados (18 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

AspenForester 1

codaamok 1

DianaKuzmenko 1

MikeyBronowski 1

poshdude 1
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

robcmo 1

sertdfyguhi 1

stampycode 1

Febrero de 2022
Contenido nuevo

about_Calling_Generic_Methods

Actualizaciones de contenido

Ponerse al día sobre problemas


Actualizaciones del contenido de la versión preliminar 7.3

Principales colaboradores de la comunidad


Estadísticas de GitHub

22 SOLICITUDES combinadas (3 de Community)


24 problemas abiertos (19 de Community)
18 problemas cerrados (16 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

sethvs 2

guilhermgonzaga 1

Enero de 2022
Contenido nuevo

No hay contenido nuevo. Estamos en un sistema de escritura para PowerShell.


Estuve fuera de la oficina durante la mitad de diciembre para vacaciones y la mitad
de enero para la COVID.

Actualizaciones de contenido

Ponerse al día sobre problemas


Actualizaciones del contenido de la versión preliminar 7.3

Principales colaboradores de la comunidad


Estadísticas de GitHub

51 SOLICITUDES combinadas (10 de Community)


29 problemas abiertos (26 de Community)
46 problemas cerrados (39 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

sethvs 3

UberKluger 1

MiguelDomingues 1

reZach 1

Hertz-Hu 1

julian-hansen 1

Hrxn 1

peteraritchie 1
Novedades de la documentación de
PowerShell para 2021
Artículo • 09/03/2022

En este artículo se muestran algunos de los cambios importantes en los documentos


durante este mes anterior y se celebran las contribuciones de la comunidad.

Ayúdenos a mejorar para usted la documentación. Lea la Guía del colaborador para
obtener información sobre cómo empezar.

2021-Diciembre
Contenido nuevo

Se ha agregado PowerShell 7.3-preview.1 [contenido de versión preliminar]


Nuevo contenido de DSC 3.0
Introducción al Desired State Configuration PowerShell
Administración de la configuración mediante DSC de PowerShell
Configuraciones DSC
Recursos de DSC

Actualizaciones de contenido

Se Desired State Configuration contenido al nuevo conjunto de documentos y


repositorio
DSC se está desarrollando ahora fuera del producto de PowerShell.
El traslado permite un mejor control de versiones de la documentación de DSC.

Principales colaboradores de la comunidad


Estadísticas de GitHub

24 PR combinados (4 de Community)
30 incidencias abiertas (26 desde Community)
12 problemas cerrados (7 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

dAu6jARL 1

yharsh ara 1

a-sync 1

indesgángg 1

2021-noviembre
Contenido nuevo

about_Built-in_Functions

Actualizaciones de contenido

Actualizaciones de documentación general de PowerShell 7.2


Actualización GitHub problemas y plantillas de solicitud de solicitud de acceso:
prueba piloto de los nuevos formularios basados en YAML para problemas
Referencia actualizada de Crescendo para la versión preliminar 4

Principales colaboradores de la comunidad


Estadísticas de GitHub

48 PR combinados (13 de Community)


31 incidencias abiertas (24 desde Community)
34 problemas cerrados (28 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

matt9ucci 4

yecril71pl 3

rklabrk 1

lukejjh 1
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

Oechiomisión 1

bergmeister 1

Hrxn 1

jehamham 1

2021-octubre
Contenido nuevo

Documentación de PSScriptAnalyzer
Información general
Documentación de reglas

Actualizaciones de contenido

Muchas actualizaciones generales editoriales y de actualización en 450 archivos


Actualizaciones de documentación de PowerShell 7.2-rc.1

Principales colaboradores de la comunidad


Estadísticas de GitHub

49 PR combinados (12 de Community)


33 incidencias abiertas (30 desde Community)
33 problemas cerrados (32 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

doctordns 4

diecknet 1

Kagre 1

KexyBiscuit 1
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

JohnRoos 1

Zhu-Panda 1

philanderson888 1

BlackFalcons 1

milauyahiya 1

mklement0 2

2021-septiembre
Contenido nuevo

Documentación del SDK


Validación de un argumento mediante un script
Declaración de atributo ValidateScript
Learning contenido
Características de seguridad de PowerShell

Actualizaciones de contenido

Instalar documentación: se ha reescrito por completo la documentación de


instalación. Ahora hay un artículo independiente para cada sistema operativo
compatible.
Instalación en Windows
Instalación en macOS
Instalación en Linux
Alpine
CentOS
Debian
Fedora
Raspberry Pi OS
Red Hat Enterprise Linux
Ubuntu
Métodos de instalación alternativos
SDK con soporte de la comunidad
Documentación de soporte técnico
Uso de PowerShell en Docker
Compatibilidad con procesadores Arm
Preguntas más frecuentes sobre Microsoft Update para PowerShell
Ciclo de vida de soporte técnico de PowerShell
Se ha reformateado y actualizado la documentación de las reglas de
PSScriptAnalyzer. El próximo mes tenemos previsto publicar estos documentos en
docs.microsoft.com.
Documentación de reglas sobre GitHub
Muchas actualizaciones editoriales generales en 4500 archivos
Actualizaciones de documentación de PowerShell 7.2-preview.10

Principales colaboradores de la comunidad


Estadísticas de GitHub

68 PR combinados (6 desde Community)


32 incidencias abiertas (29 desde Community)
49 problemas cerrados (41 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

RaghuRocks3 1

Zhu-Panda 1

Paradójor 1

juvtib 1

przmv 1

mklement0 2

Agosto de 2021
Contenido nuevo

about_ANSI_Terminals
about_PSCustomObject

Actualizaciones de contenido
Actualizaciones de documentación de PowerShell 7.2-preview.9

Principales colaboradores de la comunidad


Estadísticas de GitHub

66 PR combinados (14 desde Community)


42 incidencias abiertas (30 desde Community)
53 problemas cerrados (38 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

AvrumMenuman 1

benmccallum 1

bitdeft 2

BraINstinct0 1

diddledani 1

doctordns 1

cional 1

homotechsual 1

gregó-tjd 1

juvtib 1

yak 1

y 1

ryandasilva2992 1

sethvs 1

yernuts 1

2021-julio
Contenido nuevo
about_Functions_Argument_Completion
about_Tab_Expansion

Actualizaciones de contenido

about_Functions_Advanced_Parameters : actualizaciones principales y vínculos a


nuevos artículos
Actualizaciones de documentación de PowerShell 7.2-preview.8

Principales colaboradores de la comunidad


Estadísticas de GitHub

51 PR combinados (9 desde Community)


56 incidencias abiertas (50 desde Community)
59 problemas cerrados (52 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

ithithithith 2

juvtib 2

SetTrend 1

Rob-S 1

xtqqczze 1

akashdabhi03 1

mcmcmc 1

clamb123 13

mklement0 2

ykahnPerl 2

2021-junio
Contenido nuevo
about_Intrinsic_Members
about_Booleans

Actualizaciones de contenido

Se han about_remote_faq al nuevo formato Yaml y se han movido a la tabla de


contenido conceptual
Se ha movido PSDesiredStateConfiguration fuera de los documentos de la
versión 7.2 y a PowerShell-Docs-Modules.
DSC se está quitando de PowerShell para convertirse en un módulo opcional
que se carga desde el Galería de PowerShell
El plan a largo plazo es mover toda la documentación de DSC fuera PowerShell-
Docs a un nuevo repositorio para el contenido de DSC.
Vuelva a crear completamente las notas de la versión de PowerShell para resumir
el estado actual, lo que facilita a los usuarios encontrar la información sin tener
que leer cada nota de versión.
Diferencias entre Windows PowerShell 5.1 y PowerShell (core) 7.x
Diferencias de PowerShell en plataformas diferentes de Windows
Actualizaciones de documentación de PowerShell 7.2-preview.7

Principales colaboradores de la comunidad


Estadísticas de GitHub

43 PR combinados (1 desde Community)


36 incidencias abiertas (32 desde Community)
49 problemas cerrados (41 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

ithithithith 1

frenchiveruti 2

retin-automutatio 2

ringerc 2

yyanov 2

UberKluger 2
2021-Mayo
Contenido nuevo

Se han migrado dos artículos del contenido Windows Server al conjunto de


documentos de PowerShell.
Consideraciones de rendimiento de scripting de PowerShell
Consideraciones sobre la creación de módulos de PowerShell
Se ha agregado la especificación del lenguaje PowerShell 3.0
El documento de especificación está disponible en el Centro de descarga de
Microsoft como Microsoft Word documento .
Contenido actualizado para la versión PowerShell 7.2-Preview6
Ejemplos movidos en el nodo Learn de la tabla de contenido

Principales colaboradores de la comunidad


Estadísticas de GitHub

53 PR combinados (6 de Community)
37 incidencias abiertas (35 desde Community)
39 problemas cerrados (36 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

kvprasoon 2

jErprog 1

aamami 1

BetaLyte 1

TheNCuber 1

yyanov 6

Tarjei-stavanger 3

aungminko93750 3

SetTrend 2

cdichter 2
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

reuvygroovy 2

2021-abril
Contenido nuevo

Contenido de Learn publicado Escriba su primer código de PowerShell.


Documentos actualizados para PowerShell 7.2-preview.5
Metadatos actualizados en ~3300 artículos en la documentación Windows módulo
de actualización
Preparación para la Windows Server 2022 y corrección de la ayuda actualizable
Esto sigue siendo un trabajo en curso

Principales colaboradores de la comunidad


Estadísticas de GitHub

45 PR combinados (5 de Community)
42 incidencias abiertas (33 desde Community)
55 problemas cerrados (32 Community problemas cerrados)

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

ealmonte32 1

hana hana 1
hanajacobson

MarcChasse 1

Melvin-Abraham 1

robertkruk 1

MikeMM70 2

2021-marzo
Contenido nuevo

Trabajar para simplificar y expandir el contenido de información general


Se ha agregado ¿Qué es un comando de PowerShell?
Inicio de una nueva serie de tutoriales: Bits de PowerShell
Descripción de PowerShell
Contenido de ayuda para módulos de la utilidad de PowerShell
Microsoft.PowerShell.Crescendo
Microsoft.PowerShell.SecretManagement
Microsoft.PowerShell.SecretStore
PlatyPS
PSScriptAnalyzer
Trabajar con el equipo de Windows para actualizar la ayuda para los módulos
Windows administración
Se ha agregado contenido para Windows Server 2019 y Windows Server 2022
(versión preliminar)
Seguir trabajando para mejorar la ayuda actualizable para estos módulos
Actualizaciones de documentación de PowerShell 7.2-preview

Principales colaboradores de la comunidad


Estadísticas de GitHub

42 PR combinados (5 de Community)
63 incidencias abiertas (42 desde Community)
47 problemas cerrados

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

bl-ue 1

brianary 1

Lx 1

matt9ucci 1

ick 1

mklement0 10
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

juvtib 6

BoJackem23 2

2021-febrero de 2021
Contenido nuevo

Actualizaciones de documentación de PowerShell 7.2-preview

Principales colaboradores de la comunidad


Estadísticas de GitHub

40 PR combinados (12 de Community)


40 incidencias abiertas (30 desde Community)
35 problemas cerrados

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

bbodenmiller 1

brianary 1

exchange12rocks 1

IvenVención 1

ypinhive 1

jdoubleu 1

LogicalToolkit 1

matt9ucci 1

mihir-ajmera 1

revolter 1

secretGeek 1
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

springcomp 1

Ayanmullick 2

2021-Enero
Contenido nuevo

Actualizaciones de documentación de PowerShell 7.2-preview

Principales colaboradores de la comunidad


Estadísticas de GitHub

44 PR combinados (14 de Community)


46 incidencias abiertas (38 desde Community)
35 problemas cerrados

Las siguientes personas han contribuido a la documentación de PowerShell enviando


solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

Andmatrosov 4

revolter 2

cconrad 1

Hrxn 1

kilasuit 1

NN--- 1

snickler 1

yan 1

kbrown 1

brianary 2

mklement0 2
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

plastikfan 2
Novedades de PowerShell Docs para
2020
Artículo • 05/05/2022

En este artículo se muestran algunos de los cambios importantes en los documentos


durante este mes anterior y se celebran las contribuciones de la comunidad.

Ayúdenos a mejorar para usted la documentación. Lea la Guía del colaborador para
obtener información sobre cómo empezar.

Diciembre de 2020
Guía de colaborador actualizada
documentó el &preserve_view=true parámetro de consulta para hipervínculos
sintaxis de referencia cruzada documentada para hipervínculos
información agregada sobre la localización

Estadísticas de GitHub
44 SOLICITUDES combinadas (11 de Community)
50 problemas abiertos (43 de Community)
50 problemas cerrados

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

doctordns 3 2

chadbaldwin 1

dawedawe 1

dumpvn 1

kvprasoon 1

lbearl 1

petershen0307 1
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

skycommand 1

springcomp 1

Cwilson-dataselfcom 5

bobbybatatina 2

Noviembre de 2020
Versión de disponibilidad general de PowerShell 7.1
Novedades de PowerShell 7.1
Documentos de 7.1 convertidos al estado de la versión
Se han agregado documentos 7.2 (versión preliminar)
Documentos retirados de la versión 6 para archivar el repositorio

Publicaciones de blog
¡Tienes ayuda!
Actualización de la ayuda para el módulo PSReadLine

Mantenimiento de la documentación
Se han actualizado 137 artículos para quitar referencias de MSDN y TechNet
Se han actualizado 171 artículos para indicar la compatibilidad de solo Windows
Se han actualizado 38 artículos para abordar las advertencias y sugerencias de
compilación.
Se ha agregado inclusión a 24 artículos de DSC
Reescritura principal de los artículos trabajos de PowerShell
about_Jobs
about_Remote_Jobs
about_Thread_Jobs

Estadísticas de GitHub
50 SOLICITUDES combinadas (8 de Community)
55 problemas abiertos (45 de Community)
51 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

AlanFlorance 1

gilbertbw 1

ianwalkeruk 1

JeremyTBradshaw 1

matt9ucci 1

Rob-S 1

ShaydeNofziger 1

skycommand 1

juvtib 8

iRon7 2

l-ip 2

stephenrgentry 2

Vixb1122 2

Octubre de 2020
Artículos nuevos
Acerca de la codificación de caracteres
Acerca de los flujos de salid
Uso de Visual Studio Code para depurar cmdlets compilados (gracias a
@fsackur)
Compatibilidad para agregar credenciales a funciones de PowerShell (gracias a
@joshduffney)

Mantenimiento de la documentación
Actualizaciones para el contenido de 7.1-rc
Se actualizaron todas las descripciones de artículos para mejorar la optimización
del motor de búsqueda (SEO).

Estadísticas de GitHub
61 solicitudes de incorporación de cambios combinadas (7 de la comunidad)
49 incidencias abiertas (42 de la comunidad)
61 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

doctordns 1

escape208 1

nickdevore 1

fsackur 1

Duffney 1

skycommand 1

yecril71pl 1

mklement0 3

Abdullah0820 2

Septiembre de 2020
Mantenimiento de la documentación
Actualizaciones para el contenido de la versión preliminar 7.1

Presentación de la comunidad
Cómo contribuir a la documentación de RTPUG:
https://www.youtube.com/watch?v=0_DEB61YOMc

Estadísticas de GitHub
41 solicitudes de incorporación de cambios combinadas (9 de la comunidad)
52 incidencias abiertas (47 de la comunidad)
51 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

doctordns 1

fatherjack 1

goforgold 1

jonathanweinberg 1

kvprasoon 1

skycommand 1

springcomp 1

themichaelbender 1

toddryan 1

mklement0 13

setpeetrike 2

Agosto de 2020
Nueva documentación de PowerShell
Propiedades calculadas
Escritura de Progress en varios subprocesos con Foreach Parallel

Mantenimiento de la documentación
Actualizaciones para el contenido de la versión preliminar 7.1

Estadísticas de GitHub
69 solicitudes de incorporación de cambios combinadas (26 de la comunidad)
68 incidencias abiertas (49 de la comunidad)
58 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

sethvs 10 2

yecril71pl 10

mklement0 1 7

springcomp 1 2

SquirrelAssassin 2

thorstenbutz 2

aetos382 1

crumdev 1

joshSi 1

kmoad 1

Julio de 2020
Nueva documentación de PowerShell
Se han restablecido siete artículos de la documentación anterior de ETS.
Se ha agregado un artículo sobre la creación de ayuda actualizable mediante
PlatyPS.

Mantenimiento de la documentación
Actualizaciones para el contenido de la versión preliminar 7.1
Actualización del encabezado de página: se han simplificado las opciones del
menú y se ha agregado un botón de descarga.
Se han corregido varios problemas de Update-Help .
Ahora se descarga la ayuda de los módulos PSDesiredStateConfiguration y
ThreadJob.
Se ha publicado ayuda actualizable para PowerShell 7.1 (versión preliminar).
La ayuda actualizable para PowerShell 5.1 ahora incluye temas relativos a
Acerca de.

Estadísticas de GitHub
99 solicitudes de incorporación de cambios combinadas (29 de la comunidad)
51 incidencias abiertas (44 de la comunidad)
71 incidencias cerradas
Principales colaboradores de la comunidad
Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

yecril71pl 10 3

sethvs 10

springcomp 3 2

txtor 2 1

baardhermansen 1

skycommand 1

srjennings 1

xtqqczze 1

mklement0 3

Allexxann 2

sharpninja 2

XuHeng1021 2

Junio de 2020
Nueva documentación de PowerShell
Se ha publicado contenido nuevo de Conceptos básicos sobre PowerShell
aportado por Mike F. Robbins.
Se han agregado dos entradas de blog recientes de Rob Holt a los documentos
de Scripting y desarrollo.
Elección del paquete NuGet de PowerShell adecuado para un proyecto de
.NET
Resolución de conflictos con las dependencias de ensamblado de los
módulos de PowerShell

Mantenimiento de la documentación
Contenido anterior archivado en https://aka.ms/PSLegacyDocs
Contenido del SDK de acceso web de PowerShell
Contenido del SDK de flujos de trabajo de PowerShell
Actualizaciones para el contenido de la versión preliminar 7.1

Estadísticas de GitHub
83 solicitudes de incorporación de cambios combinadas (15 de la comunidad)
68 incidencias abiertas (52 de la comunidad)
74 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

doctordns 3

gabrielmccoll 2

adrianhale 1

aisbergde 1

beatcracker 1

bergmeister 1

DarioArzaba 1

gforceg 1

jpomfret 1

Karl-WE 1

signalwarrant 1

skycommand 1

tkhadimullin 1

johnkberry 2

juvtib 2

mklement0 2

Sagatboy33 4
Mayo de 2020
Nueva documentación de PowerShell
Se ha creado una nueva sección Deep dives que incluye contenido del
colaborador de la comunidad Kevin Marquette
Todo lo que le interesa sobre las matrices
Todo lo que le interesa sobre las tablas hash
Todo lo que le interesa sobre PSCustomObject
Todo lo que le interesa sobre la sustitución de cadenas
Todo lo que le interesa sobre las expresiones if/then/else
Todo lo que le interesa sobre los modificadores
Todo lo que le interesa sobre las excepciones
Todo lo que le interesa sobre $null
Todo lo que le interesa sobre ShouldProcess
Cómo crear un módulo binario de biblioteca estándar
Se publicó la referencia de la API de .NET de PowerShell 7.0
Update-Help -Force para PowerShell 5.1 ahora descarga el contenido
actualizado para los módulos principales de PowerShell

Mantenimiento de la documentación
Reorganización significativa de la tabla de contenido
Nuevo contenido en la sección Aprendizaje de PowerShell
Contenido de Windows PowerShell 5.1 recopilado en una ubicación
Contenido anterior archivado en https://aka.ms/PSLegacyDocs
Acceso web a PowerShell
Guía de flujos de trabajo de PowerShell
Actualizaciones para el contenido de la versión preliminar 7.1

Estadísticas de GitHub
81 solicitudes de incorporación de cambios combinadas (21 de la comunidad)
61 incidencias abiertas (53 de la comunidad)
64 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

nschonni 10
Identificador de Solicitudes de incorporación de cambios Incidencias
GitHub combinadas abiertas

xtqqczze 2 1

kilasuit 1 1

davidseibel 1

doctordns 1

jhoffmann271 1

KevinMarquette 1

klitztuch 1

markojorge 1

perjahn 1

schuelermine 1

jsilverm 7

mklement0 5

cam1170 2

JustinGrote 2

peetrike 2

Abril de 2020
Nuevos documentos
Documentación de PowerShell
Uso de las características experimentales
acerca de_about_PSModulePath
Artículos de wiki
Pros y contras de Invoke-Expression
Se pueden asignar valores a las variables como parte de una expresión (con
limitaciones)

Mantenimiento de la documentación
Ahora las actualizaciones se publican en docs.microsoft.com con una
programación diaria
lunes-viernes a las 15 h, hora de Redmond (UTC-8).
Hemos reestructurado el contenido de la comunidad.
Hemos realizado muchas limpiezas editoriales.
Hemos actualizado la guía para colaboradores.
Hemos aclarado algunas reglas de formato.
Hemos incluido nueva información sobre el formato de tabla.

Estadísticas de GitHub
74 solicitudes de incorporación de cambios combinadas (8 de la comunidad)
79 incidencias abiertas (71 de la comunidad)
102 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Identificador de Solicitudes de incorporación de cambios Incidencias


GitHub combinadas abiertas

ScSurber 1 1

alexandair 1

bmkaiser 1

hyoshioka0128 1

jpomfret 1

raydixon 1

signalwarrant 1

mklement0 8

reinierk 3

scabon 2

Abdullah0820 2

awooga 2

Damag3d 2

Fiasco123 2

Jasonthurston 2
Marzo de 2020
Nuevos documentos
Páginas de la comunidad de la documentación de PowerShell
Página de recursos de la comunidad
Página de Novedades de PowerShell Docs (esta página)
Infografía de PowerShell agregada a la página de arte digital
Guía para colaboradores de PowerShell
Nuevo contenido de PowerShell
Migración de Windows PowerShell 5.1 a PowerShell 7
Lista de compatibilidad del módulo de PowerShell 7
Uso de PowerShell en Docker
Nuevo contenido de la wiki
PowerShell evita excepciones para las claves no existentes de los tipos que
implementan IDictionary TKey y TValue.
El tratamiento de PowerShell de los espacios de nombres no distingue
mayúsculas de minúsculas, pero no las modifica.

Mantenimiento de la documentación
Limpieza masiva de vínculos rotos
Limpieza de problemas antiguos y duplicados

Estadísticas de GitHub
100 PR combinadas (14 de la comunidad)
68 incidencias abiertas (56 de la comunidad)
109 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

k-takai: 7 PR
mklement0: 5 incidencias
juvtib: 4 incidencias
iSazonov: 3 incidencias
doctordns: 2 incidencias
mdorantesm: 2 incidencias
qt3m45su0najc7:2 incidencias

Febrero de 2020
Nuevos documentos
about_Parameter_Sets
Historial de versiones de módulos y cmdlets
Actualizaciones de documentación de PowerShell 7
Actualizaciones para solucionar incidencias
Se ejecutó PlatyPS para comprobar la información de parámetros para todos los
cmdlets y versiones
Estadísticas de GitHub
52 PR combinadas (9 de la comunidad)
49 incidencias abiertas (42 de la comunidad)
55 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Maamue: 2 PR
doctordns: 2 PR
mklement0: 4 incidencias
he852100: 3 incidencias
VectorBCO: 2 incidencias
metablaster: 2 incidencias

Enero de 2020
Nuevos documentos
about_Windows_PowerShell_Compatibility
Actualizaciones de documentación de PowerShell 7
Actualizaciones para solucionar incidencias
Estadísticas de GitHub
58 PR combinadas (7 de la comunidad)
57 incidencias abiertas (43 de la comunidad)
70 incidencias cerradas

Principales colaboradores de la comunidad


Las siguientes personas han contribuido a la documentación de PowerShell enviando
solicitudes de incorporación de cambios o rellenando incidencias. Gracias.

Makovec: 3 PR
mklement0: 9 incidencias
mvadu: 2 incidencias
razos: 2 incidencias
VLoub: 2 incidencias
doctordns: 2 incidencias
Arte digital de PowerShell
Artículo • 05/05/2022

Las leyendas son ciertas. El eficaz shell que garantiza el paso seguro a la nube. Pero,
¿cómo?

Disfrute de la ilustración digital vinculada a continuación. Muestre a sus compañeros


que se le han confiado los pergaminos de mónada.

Infografía de PowerShell
Infografía de PowerShell

Cómic
Cómic de héroes de PowerShell (alta resolución)
Cómic de héroes de PowerShell (resolución de impresión)
Cómic de héroes de PowerShell (resolución web)

Fondo de pantalla
Papel tapiz de cómic de héroes de PowerShell (resolución 4k)
Papel tapiz rosa de héroes de PowerShell (resolución 4k)
Papel tapiz blanco de héroes de PowerShell (resolución 4k)

Póster
Póster de héroes de PowerShell

Héroe de PowerShell
Imagen de héroes de PowerShell

Directrices para arte digital y logotipos de Microsoft


PowerShell
Como norma general, no pueden usarse logotipos ni ilustraciones de Microsoft sin
permiso por parte de terceros. A continuación se indican las circunstancias limitadas en
las que pueden usarse logotipos e ilustraciones de Microsoft por parte de terceros.

Con fines no comerciales (documentación o en un sitio web) que hacen referencia


a su conexión con Microsoft PowerShell.

Todo uso no incluido en estas directrices, tal como determina Microsoft, está
estrictamente prohibido. No use logotipos ni ilustraciones de Microsoft PowerShell en
productos, empaquetado de productos u otros servicios de negocio para los que se
requiere una licencia formal.

Microsoft se reserva el derecho según su exclusivo criterio a finalizar o modificar el


permiso para mostrar el logotipo o la ilustración, y puede solicitar a terceros la
modificación o eliminación de cualquier uso del logotipo o la ilustración que, a criterio
exclusivo de Microsoft, no cumpla estas directrices o pueda, de otro modo, perjudicar
los derechos de Microsoft sobre el logotipo.
Uso de Visual Studio Code para el
desarrollo de PowerShell
Artículo • 13/04/2023

Visual Studio Code (VS Code) es un editor de scripts multiplataforma de Microsoft.


Junto con la extensión de PowerShell , proporciona una experiencia de edición de
scripts enriquecida e interactiva que facilita la escritura de scripts confiables de
PowerShell. Visual Studio Code con la extensión de PowerShell es el editor
recomendado para escribir scripts de PowerShell.

Admite las siguientes versiones de PowerShell:

PowerShell 7.2 y versiones posteriores (Windows, macOS y Linux)


Windows PowerShell 5.1 (solo Windows) con .NET Framework 4.8

7 Nota

Visual Studio Code no es lo mismo que Visual Studio .

Introducción
Antes de empezar, asegúrese de que PowerShell existe en el sistema. Para cargas de
trabajo modernas de Windows, macOS y Linux, consulte los siguientes vínculos:

Instalación de PowerShell en Linux


Instalación de PowerShell en macOS
Instalación de PowerShell en Windows

Para las cargas de trabajo de Windows PowerShell tradicionales, vea Instalación de


Windows PowerShell.

) Importante

Windows PowerShell ISE sigue estando disponible para Windows. Sin embargo, ya
no se incluye en el desarrollo activo de características. El ISE solo funciona con
PowerShell 5.1 y versiones anteriores. Como un componente de Windows, sigue
siendo compatible oficialmente con las correcciones de servicios de seguridad y
alta prioridad. No está previsto quitar el ISE de Windows.
Instalación de VS Code y la extensión de
PowerShell
1. Instale Visual Studio Code. Para más información, consulte la información general
que se describe en Configuración de Visual Studio Code .

Hay instrucciones de instalación para cada plataforma:

Ejecución de Visual Studio Code en Windows


Ejecución de Visual Studio Code en macOS
Ejecución de Visual Studio Code en Linux

2. Instale la extensión de PowerShell.


a. Inicie la aplicación VS Code; para ello, escriba code en una consola, o code-
insiders si ha instalado Visual Studio Code Insiders.
b. Inicie Quick Open en Windows o Linux; para ello, presione Ctrl + P . En macOS,
presione Cmd + P .
c. En Quick Open, escriba ext install powershell y presione Entrar.
d. Se abre la vista Extensiones en la barra lateral. Seleccione la extensión de
PowerShell de Microsoft.
e. Haga clic en el botón Instalar en la extensión de PowerShell de Microsoft.
f. Después de la instalación, si ve que el botón Instalar cambia a Recargar, haga
clic en Recargar.
g. Una vez que VS Code se haya vuelto a cargar, estará listo para editar.

Por ejemplo, para crear un archivo, haga clic en Archivo > Nuevo. Para guardarlo, haga
clic en Archivo > Guardar y proporcione un nombre de archivo, por ejemplo,
HelloWorld.ps1 . Para cerrar el archivo, haga clic en la X junto al nombre de archivo. Para
salir de VS Code, haga clic en Archivo > Salir.

Instalación de la extensión de PowerShell en sistemas


restringidos
Algunos sistemas están configurados para requerir la validación de todas las firmas de
código. Puede que aparezca el siguiente mensaje de error:

Language server startup failed.


Este problema puede producirse cuando la directiva de ejecución de PowerShell está
establecida en la directiva de grupo de Windows. Para aprobar manualmente los
servicios del editor de PowerShell y la extensión de PowerShell para VS Code, abra un
símbolo del sistema de PowerShell y ejecute el siguiente comando:

PowerShell

Import-Module $HOME\.vscode\extensions\ms-
vscode.powershell*\modules\PowerShellEditorServices\PowerShellEditorServices
.psd1

Se le preguntará si desea ejecutar software de este editor que no es de confianza.


Escriba A para ejecutar el archivo. Luego abra VS Code y verifique que la extensión de
PowerShell funciona correctamente. Si sigue teniendo problemas para empezar,
háznoslo saber en un problema de GitHub .

Elección de una versión de PowerShell para usarla con la


extensión
Con la instalación de PowerShell en paralelo con Windows PowerShell, ahora es posible
usar una versión específica de PowerShell con la extensión de PowerShell. Esta
característica examina algunas rutas de acceso conocidas en distintos sistemas
operativos para detectar las instalaciones de PowerShell.

Use estos pasos para elegir la versión:

1. Abra la paleta de comandos en Windows o Linux con Ctrl + Mayús + P . En macOS,


use Cmd + Mayús + P .
2. Busque Sesión.
3. Haga clic en PowerShell: Show Session Menu (PowerShell: Mostrar menú de
sesión).
4. En la lista, elija la versión de PowerShell que quiere usar.

O PowerShell pode não ser inicialmente mostrado no menu de sessão caso você o tenha
instalado em um local atípico. Para extender el menú de la sesión, agregue sus propias
rutas de acceso personalizadas tal como se describe a continuación.

También puede acceder al menú de la sesión de PowerShell desde el icono de {} de la


esquina inferior derecha de la barra de estado. Al pasar el cursor sobre este icono o
seleccionarlo, se muestra un acceso directo al menú de la sesión y un pequeño icono de
anclaje. Si selecciona el icono de anclaje, el número de versión se agrega a la barra de
estado. El número de versión es un acceso directo al menú de sesión que requiere
menos clics.

7 Nota

Anclar el número de versión replica el comportamiento de la extensión en


versiones de VS Code anteriores a la 1.65. La versión 1.65 de VS Code cambió las
API que usa la extensión de PowerShell y normalizó la barra de estado para las
extensiones de lenguaje.

Valores de configuración para Visual Studio


Code
En primer lugar, si no se está familiarizado con la forma de cambiar la configuración en
VS Code, se recomienda leer la documentación sobre la configuración de
Visual Studio Code .

Después de leer la documentación, puede agregar opciones de configuración en


settings.json .

JSON

{
"editor.renderWhitespace": "all",
"editor.renderControlCharacters": true,
"files.trimTrailingWhitespace": true,
"files.encoding": "utf8bom",
"files.autoGuessEncoding": true
}

Si no desea que esta configuración afecte a todos los tipos de archivos, VS Code
también permite configuraciones por lenguaje. Cree un ajuste específico del lenguaje
colocando los ajustes en un campo [<language-name>] . Por ejemplo:

JSON

{
"[powershell]": {
"files.encoding": "utf8bom",
"files.autoGuessEncoding": true
}
}
 Sugerencia

Para obtener más información sobre la codificación de archivo en VS Code,


consulte Descripción de la codificación de archivo. Vea también Cómo replicar la
experiencia de ISE en Visual Studio Code para obtener otras sugerencias sobre
cómo configurar VS Code para la edición de PowerShell.

Adición de rutas de acceso propias de PowerShell al


menú de sesión
Puede agregar otras rutas de acceso ejecutables de PowerShell al menú de sesión
mediante la configuración de Visual Studio Code :
powershell.powerShellAdditionalExePaths .

Puede hacerlo mediante la GUI:

1. En la paleta de comandos, busque y seleccione Abrir configuración de usuario. O


bien, use el método abreviado de teclado en Windows o Linux Ctrl + , . En
macOS, use Cmd + , .
2. En el editor de configuración, busque Rutas de acceso adicionales de Exe de
PowerShell.
3. Haga clic en Add Item (Agregar elemento).
4. Para la clave (en Elemento), proporcione su nombre para esta instalación adicional
de PowerShell.
5. Para el valor (en Valor), proporcione la ruta de acceso absoluta al propio
ejecutable.

Puede añadir tantas rutas adicionales como quiera. Los elementos agregados aparecen
en el menú de sesión con la clave especificada como nombre.

Como alternativa, puede agregar pares clave-valor al objeto


powershell.powerShellAdditionalExePaths en settings.json :

JSON

{
"powershell.powerShellAdditionalExePaths": {
"Downloaded PowerShell":
"C:/Users/username/Downloads/PowerShell/pwsh.exe",
"Built PowerShell":
"C:/Users/username/src/PowerShell/src/powershell-win-
core/bin/Debug/net6.0/win7-x64/publish/pwsh.exe"
},
}
7 Nota

Antes de la versión 2022.5.0 de la extensión, esta configuración era una lista de


objetos con las claves exePath necesarias y versionName . Se introdujo un cambio
importante para admitir la configuración a través de la GUI. Si ha configurado
previamente esta configuración, conviértela en el nuevo formato. El valor
especificado para versionName ahora es la clave y el valor especificado para
exePath ahora es el valor. Para ello, puede restablecer el valor y usar la interfaz
Configuración.

Para configurar la versión predeterminada de PowerShell, establezca el valor


powershell.powerShellDefaultVersion en el texto que se muestra en el menú de la

sesión (el texto utilizado para la clave):

JSON

{
"powershell.powerShellAdditionalExePaths": {
"Downloaded PowerShell":
"C:/Users/username/Downloads/PowerShell/pwsh.exe",
},
"powershell.powerShellDefaultVersion": "Downloaded PowerShell",
}

Después de configurar este valor, reinicie VS Code, o para volver a cargar la ventana
actual de VS Code desde la paleta de comandos, escriba Developer: Reload Window .

Si abre el menú de la sesión, ahora verá sus instalaciones adicionales de PowerShell.

 Sugerencia

Si compila PowerShell a partir del código fuente, se trata de una excelente forma de
probar la compilación local de PowerShell.

Depuración con Visual Studio Code

Depuración fuera del área de trabajo


En VS Code 1.9 (o versiones posteriores), puede depurar scripts de PowerShell sin tener
que abrir la carpeta que los contiene.

1. Abra el archivo de script de PowerShell con Archivo > Abrir archivo….


2. Establezca un punto de interrupción: seleccione una línea y, a continuación,
presione F9 .
3. Presione F5 para iniciar la depuración.

Verá que aparece el panel de acciones de depuración, que le permite iniciar el


depurador, realizar la depuración paso a paso, reanudarla y detenerla.

Depuración del área de trabajo


La depuración del área de trabajo hace referencia a la depuración en el contexto de una
carpeta que se ha abierto desde el menú Archivo mediante Abrir carpeta... Suele
tratarse de la carpeta del proyecto de PowerShell o la raíz del repositorio de Git. La
depuración del área de trabajo no se limita a depurar el archivo abierto actualmente,
sino que permite definir diversas configuraciones de depuración.

Siga los pasos siguientes para crear un archivo de configuración de depuración:

1. Abra la vista Depurar en Windows o Linux con Ctrl + Mayús + D . En macOS,


presione Cmd + Mayús + D .

2. Haga clic en el vínculo crear un archivo launch.json.

3. En el mensaje Seleccionar entorno, seleccione PowerShell.

4. Elija el tipo de depuración que desea usar:

Iniciar el archivo actual: iniciar y depurar el archivo en la ventana del editor


actualmente activa
Iniciar script: iniciar y depurar el archivo o comando especificado
Sesión interactiva: depurar los comandos ejecutados desde la consola
integrada
Adjuntar: adjuntar el depurador a un proceso de host de PowerShell en
ejecución

VS Code crea un directorio y un archivo .vscode\launch.json en la raíz de la carpeta del


área de trabajo para almacenar la configuración de depuración. Si los archivos están en
un repositorio de Git, lo normal es que le interese confirmar el archivo launch.json . El
contenido del archivo launch.json es el siguiente:

JSON
{
"version": "0.2.0",
"configurations": [
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Launch (current file)",
"script": "${file}",
"args": [],
"cwd": "${file}"
},
{
"type": "PowerShell",
"request": "attach",
"name": "PowerShell Attach to Host Process",
"processId": "${command.PickPSHostProcess}",
"runspaceId": 1
},
{
"type": "PowerShell",
"request": "launch",
"name": "PowerShell Interactive Session",
"cwd": "${workspaceRoot}"
}
]
}

Este archivo representa los escenarios de depuración comunes. Cuando abra este
archivo en el editor, verá un botón Agregar configuración… . Puede hacer clic en este
botón para agregar más configuraciones de depuración de PowerShell. Una
configuración muy útil que conviene agregar es PowerShell: Iniciar Script. Con esta
configuración, puede especificar un archivo que contenga argumentos opcionales que
se usarán cada vez que se presione F5 , con independencia del archivo que esté activo
en el editor.

Una vez establecida la configuración de depuración, puede seleccionar qué


configuración quiere usar durante una sesión de depuración. Seleccione una
configuración de la lista desplegable de configuraciones de depuración en la barra de
herramientas de la vista Depurar.

Solución de problemas de la extensión de


PowerShell
Si experimenta algún problema al usar VS Code para el desarrollo de scripts de
PowerShell, vea la guía de solución de problemas en GitHub.
Recursos útiles
Algunos vídeos y entradas de blog pueden servirle de ayuda para empezar a usar la
extensión de PowerShell para VS Code:

Vídeos
Uso de Visual Studio Code como editor de PowerShell predeterminado
Visual Studio Code: profundizar en la depuración de los scripts de PowerShell

Publicaciones de blog
Extensión de PowerShell
Escritura y depuración de scripts de PowerShell en Visual Studio Code
Instrucciones de depuración de Visual Studio Code
Depuración de PowerShell en Visual Studio Code
Introducción al desarrollo de PowerShell en Visual Studio Code
Características de edición de Visual Studio Code para el desarrollo de PowerShell,
parte 1
Características de edición de Visual Studio Code para el desarrollo de PowerShell,
parte 2
Depuración de scripts de PowerShell en Visual Studio Code, parte 1
Depuración de scripts de PowerShell en Visual Studio Code, parte 2

Código fuente del proyecto de extensión de


PowerShell
Encontrará en GitHub el código fuente de la extensión de PowerShell.

Si está interesado en contribuir, las solicitudes de incorporación de cambios resultan


muy apreciadas. Siga los pasos de la documentación para desarrolladores en GitHub
para comenzar.
Cómo replicar la experiencia de ISE en
Visual Studio Code
Artículo • 14/07/2023

Si bien la extensión de PowerShell para VS Code no busca una paridad de características


completa con el ISE de PowerShell, existen características para hacer que la experiencia
de VS Code sea más natural para los usuarios de ISE.

El objetivo de este documento es confeccionar un listado con las opciones que puede
configurar en VS Code para que la experiencia del usuario sea un poco más familiar en
comparación con el ISE.

Modo ISE

7 Nota

Esta característica está disponible en la extensión en versión preliminar de


PowerShell desde la versión 2019.12.0, así como en la extensión de PowerShell
desde la versión 2020.3.0.

La forma más sencilla de replicar la experiencia de ISE en Visual Studio Code es activar el
modo ISE. Para ello, abra la paleta de comandos ( F1 O Ctrl + Mayús + P , o bien Cmd +
Mayús + P en macOS) y escriba "modo ISE". Seleccione en la lista "PowerShell: Habilitar
modo ISE".

Este comando aplica automáticamente la configuración que se describe a continuación.


El resultado tiene el siguiente aspecto:
Opciones de configuración del modo ISE
El modo ISE realiza los cambios siguientes en la configuración de VS Code.

Enlaces de teclado

Función Enlace de ISE Enlace de VS Code

Depurador de interrupción Ctrl + B F6

Ejecutar línea actual/texto resaltado F8 F8

Lista de fragmentos de código disponibles Ctrl + J Ctrl + Alt + J

7 Nota

En VS Code también puede configurar sus propios enlaces de teclado.

Interfaz de usuario de tipo ISE simplificada

Si quiere simplificar la interfaz de usuario de Visual Studio Code para que se


asemeje más a la interfaz de usuario del ISE, aplique estas dos configuraciones:

JSON

"workbench.activityBar.visible": false,
"debug.openDebug": "neverOpen",

Esta configuración oculta las secciones "Barra de actividades" y "Barra lateral de


depuración" que se muestran dentro del cuadro rojo siguiente:

El resultado final tiene el siguiente aspecto:


Finalización con tabulación

Para habilitar una finalización con tabulación más similar a ISE, agregue este
parámetro:

JSON

"editor.tabCompletion": "on",

Sin foco en la consola al ejecutar

Para mantener el foco en el editor cuando se ejecuta con F8 :

JSON

"powershell.integratedConsole.focusConsoleOnExecute": false

El valor predeterminado es true con fines de accesibilidad.


No iniciar la consola integrada en el inicio

Para detener la consola integrada en el inicio, configure:

JSON

"powershell.integratedConsole.showOnStartup": false

7 Nota

El proceso de PowerShell en segundo plano sigue iniciándose para


proporcionar IntelliSense, análisis de scripts, navegación de símbolos, etc.,
pero la consola no se mostrará.

Suponer que los archivos son de PowerShell de manera predeterminada

Para tener archivos nuevos/sin título, regístrelos como de PowerShell de forma


predeterminada:

JSON

"files.defaultLanguage": "powershell",

Combinación de colores

Hay una serie de temas de ISE disponibles para VS Code para que el editor se
parezca mucho más a ISE.

En la Paleta de comandos, escriba theme para obtener Preferences: Color Theme y


presione Entrar . En la lista desplegable, seleccione PowerShell ISE .

Puede establecer en este tema en la configuración con:

JSON

"workbench.colorTheme": "PowerShell ISE",

Explorador de comandos de PowerShell

Gracias al trabajo de @corbob , la extensión de PowerShell tiene un incipiente


explorador de comandos propio.

En la Paleta de comandos, escriba PowerShell Command Explorer y presione Entrar .


Abrir en el ISE

Si desea abrir un archivo en Windows PowerShell ISE de todos modos, abra la


Paleta de comandos, busque "abrir en ISE" y, a continuación, seleccione
PowerShell: Abrir el archivo actual en PowerShell ISE.

Otros recursos
4sysops tiene un excelente artículo sobre la configuración de VS Code para que
sea más parecido al ISE.
Mike F Robbins tiene una excelente publicación sobre la configuración de VS
Code.

Sugerencias de VS Code
Paleta de comandos

La paleta de comandos es una forma cómoda de ejecutar comandos en VS Code.


Abra la paleta de comandos con F1 O Ctrl + Mayús + P O Cmd + Mayús + P en
macOS.

Para más información, vea la documentación sobre VS Code .

Ocultar el panel Consola de depuración

La extensión de PowerShell usa la interfaz de depuración integrada de VS Code


para permitir la depuración de scripts y módulos de PowerShell. Sin embargo, la
extensión no usa el panel Consola de depuración. Para ocultar la Consola de
depuración, haga clic con el botón derecho en Consola de depuración y
seleccione Ocultar "Consola de depuración".
Para obtener más información sobre cómo depurar PowerShell con Visual Studio
Code, consulte Uso de VS Code.

Más opciones de configuración


Si conoce más formas de hacer que VS Code resulte más familiar para los usuarios de
ISE, haga su aportación a este documento. Si busca una configuración de
compatibilidad pero no encuentra la manera de habilitarla, abra una incidencia y
pregunte.

Siempre estamos encantados de aceptar solicitudes de incorporación de cambios y


aportaciones.
Uso de Visual Studio Code para la
edición y la depuración de forma
remota
Artículo • 13/04/2023

Aquellos usuarios que están familiarizados con el ISE pueden recordar que era posible
ejecutar psedit file.ps1 desde la consola integrada para abrir archivos, locales o
remotos, directamente en el ISE.

Esta característica también está disponible en la extensión de PowerShell para VSCode.


Esta guía muestra cómo hacerlo.

Prerequisites
En esta guía se da por supuesto que tiene lo siguiente:

un recurso remoto (p. ej.: una máquina virtual, un contenedor) al que tiene acceso.
PowerShell ejecutándose en él y en el equipo host
VSCode y la extensión de PowerShell para VSCode

Esta característica funciona en PowerShell y Windows PowerShell.

Esta característica también funciona al conectarse a un equipo remoto a través de


WinRM, PowerShell Direct o SSH. Si desea usar SSH, pero está usando Windows,
consulte la versión Win32 de SSH .

) Importante

Los comandos Open-EditorFile y psedit solo funcionan en la consola integrada


de PowerShell que la extensión de PowerShell crea para VSCode.

Ejemplos de uso
Estos ejemplos muestran la depuración y la edición remotas desde un equipo MacBook
Pro a una máquina virtual Ubuntu que se ejecuta en Azure. El proceso es idéntico en
Windows.

Edición de archivo local con Open-EditorFile


Con la extensión de PowerShell para VSCode iniciada y la consola integrada de
PowerShell abierta, podemos escribir Open-EditorFile foo.ps1 o psedit foo.ps1 para
abrir el archivo foo.ps1 local directamente en el editor.

7 Nota

El archivo foo.ps1 ya debería existir.

Desde ahí, podemos hacer lo siguiente:

Agregar puntos de interrupción en el medianil.


Presionar F5 para depurar el script de PowerShell.
Durante la depuración, puede interactuar con la consola de depuración y consultar las
variables en el ámbito de la izquierda y todas las demás herramientas de depuración
estándar.

Edición de archivo remoto con Open-EditorFile


Ahora veamos la edición y la depuración de un archivo remoto. Los pasos son
prácticamente los mismos, solo hay una cosa que debemos hacer primero: escribir
nuestra sesión de PowerShell en el servidor remoto.

Hay un cmdlet para hacerlo. Se llama Enter-PSSession .

En resumen:

Enter-PSSession -ComputerName foo inicia una sesión a través de WinRM


Enter-PSSession -ContainerId foo y Enter-PSSession -VmId foo inician una sesión

a través de PowerShell Direct


Enter-PSSession -HostName foo inicia una sesión a través de SSH

Para más información, consulte la documentación para Enter-PSSession.

Como vamos a conectarnos de forma remota a una máquina virtual de Ubuntu en


Azure, usamos SSH.

En primer lugar, ejecute Enter-PSSession en la consola integrada. Se conecta a la sesión


remota cuando [<hostname>] aparece a la izquierda del símbolo del sistema.
Ahora podemos completar los mismos pasos que llevaríamos a cabo si estuviésemos
editando un script local.

1. Ejecute Open-EditorFile test.ps1 o psedit test.ps1 para abrir el archivo


test.ps1 remoto.
2. Editar el archivo/establecer los puntos de interrupción
3. Iniciar la depuración (F5) del archivo remoto

Si tiene algún problema, puede abrir los problemas que hay en el repositorio de
GitHub .
Descripción de la codificación de
archivo en VS Code y PowerShell
Artículo • 13/04/2023

Al usar VS Code para crear y editar scripts de PowerShell es importante que los archivos
se guarden con el formato de codificación de caracteres correcto.

¿Qué es la codificación de archivo y por qué es


importante?
VS Code administra la interfaz entre una entrada manual de cadenas de caracteres en
un búfer y la lectura/escritura de bloques de bytes en el sistema de archivos. Cuando VS
Code guarda un archivo, usa una codificación de texto para decidir en qué bytes se
convierte cada carácter. Para obtener más información, vea Acerca de la codificación de
caracteres.

De forma similar, cuando PowerShell ejecuta un script debe convertir los bytes de un
archivo a caracteres para reconstruir el archivo en un programa de PowerShell. Dado
que VS Code escribe el archivo y PowerShell lee el archivo, deben usar el mismo sistema
de codificación. Este proceso de análisis de un script de PowerShell es: bytes -
>caracteres ->tokens ->árbol de sintaxis abstracta ->ejecución.

VS Code y PowerShell se instalan con una configuración de codificación predeterminada


sensible. Sin embargo, la codificación predeterminada usada por PowerShell ha
cambiado con la publicación de PowerShell 6. Para garantizar que no tiene problemas
con el uso de PowerShell o la extensión de PowerShell en VS Code, debe configurar sus
opciones de VS Code y PowerShell correctamente.

Causas comunes de problemas de codificación


Se producen problemas de codificación cuando la codificación de VS Code o el archivo
de script no coincide con la codificación esperada de PowerShell. No hay ninguna forma
de que PowerShell determine automáticamente la codificación del archivo.

Es más probable tener problemas de codificación cuando se usan caracteres que no


están en el juego de caracteres ASCII de 7 bits . Por ejemplo:

Caracteres que no son letras extendidos, como guion largo ( — ), espacio de no


separación ( ) o comilla doble izquierda ( " )
Caracteres latinos acentuados ( É , ü )
Caracteres no latinos; por ejemplo, cirílico ( Д , Ц )
Caracteres de CJK ( 本 , 화 , が )

Algunas causas comunes de problemas de codificación son las siguientes:

Las codificaciones de VS Code y PowerShell no han cambiado respecto a sus


valores predeterminados. Para PowerShell 5.1 y versiones posteriores, el valor
predeterminado de codificación es diferente del de VS Code.
Otro editor ha abierto y sobrescrito el archivo en una nueva codificación. Esto
suele ocurrir con el ISE.
El archivo se incorpora al control de código fuente en una codificación distinta a la
que VS Code o PowerShell espera. Esto puede ocurrir cuando los colaboradores
usan editores con distintas configuraciones de codificación.

Procedimiento para saber si tiene problemas de


codificación
Los errores de codificación, a menudo, se presentan como errores de análisis en los
scripts. Si encuentra secuencias de caracteres extraños en su script, éste puede ser el
problema. En el ejemplo siguiente, un guión corto ( – ) aparece como los caracteres
â&euro;" :

Output

Send-MailMessage : A positional parameter cannot be found that accepts


argument 'Testing FuseMail SMTP...'.
At C:\Users\<User>\<OneDrive>\Development\PowerShell\Scripts\Send-
EmailUsingSmtpRelay.ps1:6 char:1
+ Send-MailMessage â&euro;"From $from â&euro;"To $recipient1 â&euro;"Subject
$subject ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Send-MailMessage],
ParameterBindingException
+ FullyQualifiedErrorId :
PositionalParameterNotFound,Microsoft.PowerShell.Commands.SendMailMessage

Este problema se produce porque VS Code codifica el carácter – en UTF-8 como los
bytes 0xE2 0x80 0x93 . Cuando estos bytes se descodifican como Windows-1252, se
interpretan como los caracteres â&euro;" .

Entre algunas secuencias de caracteres extraños que podría ver se incluyen:

â&euro;" en lugar de –
â&euro;" en lugar de —

Ä2 en lugar de Ä
 en lugar de (un espacio de no separación)
Ã&copy; en lugar de é

Esta referencia práctica detalla los patrones comunes que indican un problema de
codificación UTF-8/Windows-1252.

De qué forma la extensión de PowerShell en VS


Code interactúa con las codificaciones
La extensión de PowerShell interactúa con los scripts de varias maneras:

1. Cuando los scripts se editan en VS Code, el contenido lo envía VS Code a la


extensión. El protocolo de servidor de lenguaje obliga a que este contenido se
transfiera en UTF-8. Por lo tanto, no es posible que la extensión obtenga la
codificación incorrecta.
2. Cuando los scripts se ejecutan directamente en la consola integrada, se leen desde
el archivo de PowerShell directamente. Si la codificación de PowerShell difiere de la
de VS Code, es posible que algo no funcione bien.
3. Cuando un script que está abierto en VS Code hace referencia a otro script que no
está abierto en VS Code, la extensión pasa de nuevo a cargar el contenido del
script desde el sistema de archivos. La extensión de PowerShell tiene como valor
predeterminado la codificación UTF-8, pero usa la detección de marca BOM para
seleccionar la codificación correcta.

El problema se produce cuando se asume la codificación de formatos sin BOM (como


UTF-8 sin BOM y Windows-1252 ). La extensión de PowerShell tiene como valor
predeterminado UTF-8. La extensión no puede cambiar la configuración de codificación
de VS Code. Para obtener más información, vea el problema #824 .

Elección de la codificación correcta


Las aplicaciones y los sistemas distintos pueden utilizar codificaciones diferentes:

En .NET Standard, en la web y en el entorno Linux, UTF-8 es ahora la codificación


dominante.
Muchas aplicaciones de .NET Framework usan UTF-16 . Por motivos históricos, a
veces recibe la denominación de "Unicode", un término que ahora hace referencia
a un amplio estándar que incluye tanto UTF-8 como UTF-16.
En Windows, muchas aplicaciones nativas anteriores a Unicode siguen usando
Windows-1252 de forma predeterminada.

Las codificaciones Unicode también tienen el concepto de una marca BOM. Las BOM se
producen al principio del texto para indicar a un descodificador la codificación que está
usando el texto. Para las codificaciones multibyte, la BOM también indica la marca
endianness de la codificación. Las BOM están diseñadas para ser bytes que rara vez se
producen en texto no Unicode, permitiendo una estimación razonable de que el texto
es Unicode cuando hay una BOM.

Las BOM son opcionales y su adopción no es tan popular en los entornos Linux, porque
se utiliza de forma generalizada una convención dependiente de UTF-8. La mayoría de
las aplicaciones Linux dan por supuesto que la entrada de texto está codificada en UTF-
8. Si bien muchas aplicaciones Linux reconocen y tratan correctamente una BOM,
algunas no lo hacen. y esto provoca anomalías en el texto manipulado con dichas
aplicaciones.

Por lo tanto:

Si trabaja principalmente con aplicaciones Windows y Windows PowerShell, es


preferible una codificación como UTF-8 con BOM o UTF-16.
Si trabaja en varias plataformas, es preferible UTF-8 con BOM.
Si trabaja principalmente en contextos asociados a Linux, es preferible UTF-8 sin
BOM.
Windows-1252 y Latín-1 son básicamente codificaciones heredadas que deben
evitarse en la medida de lo posible. Sin embargo, algunas aplicaciones más
antiguas de Windows pueden dependen de ellas.
También merece la pena mencionar que la firma de scripts depende de la
codificación , lo cual significa que un tras cambio de codificación en un script
firmado será necesario volver a firmar.

Configuración de VS Code
La codificación predeterminada de VS Code es UTF-8 sin BOM.

Para establecer la codificación de VS Code , vaya a la configuración de VS Code ( Ctrl

+ , ) y establezca la configuración de "files.encoding" :

JSON

"files.encoding": "utf8bom"
Algunos valores posibles son:

utf8 : [UTF-8] sin BOM


utf8bom : [UTF-8] con BOM

utf16le : little endian [UTF-16]


utf16be : big endian [UTF-16]

windows1252 : [Windows-1252]

Debe obtener una lista desplegable para esto en la vista de la interfaz gráfica de
usuario, o los resultados de ello en la vista de JSON.

También puede agregar lo siguiente para detectar automáticamente la codificación,


cuando sea posible:

JSON

"files.autoGuessEncoding": true

Si no desea que esta configuración afecte a todos los tipos de archivos, VS Code
también permite configuraciones por lenguaje. Cree un ajuste específico del lenguaje
colocando los ajustes en un campo [<language-name>] . Por ejemplo:

JSON

"[powershell]": {
"files.encoding": "utf8bom",
"files.autoGuessEncoding": true
}

También puede considerar la instalación del rastreador de Gremlins para


Visual Studio Code. Esta extensión revela algunos caracteres Unicode que se dañan
fácilmente porque son invisibles o tienen un aspecto similar al de otros caracteres
normales.

Configuración de PowerShell
La codificación predeterminada de PowerShell varía en función de la versión:

En PowerShell 6 +, la codificación predeterminada es UTF-8 sin BOM en todas las


plataformas.
En Windows PowerShell, la codificación predeterminada es normalmente Windows
1252, una extensión de latin-1 , también conocida como ISO 8859-1.
En PowerShell 5+ puede encontrar la codificación predeterminada con esto:

PowerShell

[psobject].Assembly.GetTypes() | Where-Object { $_.Name -eq 'ClrFacade'} |


ForEach-Object {
$_.GetMethod('GetDefaultEncoding',
[System.Reflection.BindingFlags]'nonpublic,static').Invoke($null, @())
}

El siguiente script puede usarse para determinar la codificación que la sesión de


PowerShell infiere para un script sin una BOM.

PowerShell

$badBytes = [byte[]]@(0xC3, 0x80)


$utf8Str = [System.Text.Encoding]::UTF8.GetString($badBytes)
$bytes = [System.Text.Encoding]::ASCII.GetBytes('Write-Output "') +
[byte[]]@(0xC3, 0x80) + [byte[]]@(0x22)
$path = Join-Path ([System.IO.Path]::GetTempPath()) 'encodingtest.ps1'

try
{
[System.IO.File]::WriteAllBytes($path, $bytes)

switch (& $path)


{
$utf8Str
{
return 'UTF-8'
break
}

default
{
return 'Windows-1252'
break
}
}
}
finally
{
Remove-Item $path
}

Es posible configurar PowerShell para que use una codificación determinada, de forma
más general mediante la configuración del perfil. Vea los artículos siguientes:

Respuesta sobre la codificación de PowerShell en StackOverflow, de


@mklement0 .
Entrada de blog sobre cómo tratar la entrada UTF-8 sin BOM en PowerShell, de
@rkeithhill .

No es posible obligar a PowerShell a usar una codificación de entrada específica.


PowerShell 5.1 y versiones anteriores, que se ejecutan en Windows con la configuración
regional establecida en en-US, tienen como de forma predeterminada la codificación
Windows-1252 cuando no hay ninguna marca BOM. Otros ajustes de configuración
regional pueden usar una codificación diferente. Para garantizar la interoperabilidad, es
mejor guardar los scripts en un formato Unicode con una BOM.

) Importante

Cualquier otra herramienta que tenga y entre en contacto con scripts de


PowerShell puede verse afectada por sus opciones de codificación o puede volver a
codificar los scripts a otra codificación.

Scripts existentes
Es posible que los scripts que ya se encuentran en el sistema de archivos deban volver a
codificarse a la nueva codificación elegida. En la barra inferior de VS Code, verá la
etiqueta UTF-8. Haga clic en ella para abrir la barra de acciones y seleccione Guardar
con codificación. Ahora puede elegir una codificación de nueva para ese archivo. Vea la
información sobre la codificación de VS Code para obtener instrucciones completas.

Si necesita volver a codificar varios archivos, puede usar el siguiente script:

PowerShell

Get-ChildItem *.ps1 -Recurse | ForEach-Object {


$content = Get-Content -Path $_
Set-Content -Path $_.Fullname -Value $content -Encoding UTF8 -PassThru -
Force
}

El entorno de scripting integrado (ISE) de PowerShell


Si también edita scripts con PowerShell ISE, deberá sincronizar la configuración de
codificación allí.

El ISE debe respetar una BOM, pero también es posible usar el reflejo para establecer la
codificación . Tenga en cuenta que esto no se mantiene entre los inicios.
Software de control de código fuente
Algunas herramientas de control de código fuente, como GIT, ignoran las codificaciones;
GIT simplemente realiza un seguimiento de los bytes. Otras, como Azure DevOps o
Mercurial, puede que no. Existen también algunas herramientas basadas en GIT que se
basan en la descodificación de texto.

Cuando esto sucede, asegúrese de llevar a cabo lo siguiente:

Configure la codificación de texto en el control de código fuente para que coincida


con la configuración de VS Code.
Asegúrese de que todos los archivos se incorporen al control de código fuente en
la codificación adecuada.
Sea precavido con los cambios en la codificación que se reciben a través del
control de código fuente. Una señal clave de esto son unas diferencias que indican
la presencia de cambios pero donde nada parece haber cambiado (porque los
bytes han cambiado, pero los caracteres no).

Entornos de colaboradores
Como paso previo a la configuración del control de código fuente, asegúrese de que los
colaboradores en cualquier archivo que comparta no tengan ninguna opción que
reemplace la codificación volviendo a codificar los archivos de PowerShell.

Otros programas
Cualquier otro programa que lea o escriba un script de PowerShell puede volver a
codificarlo.

Ejemplos:

Uso del Portapapeles para copiar y pegar un script. Esto es habitual en escenarios
como:
Copiar un script en una máquina virtual
Copiar un script fuera de un correo electrónico o una página web
Copiar un script dentro o fuera de un documento de Microsoft Word o
PowerPoint
Otros editores de texto, como:
Notepad
vim
Cualquier otro editor de scripts de PowerShell
Utilidades de edición de texto, como:
Get-Content / Set-Content / Out-File

Operadores de redirección de PowerShell, como > y >>


sed / awk

Programas de transferencia de archivos, como:


Un explorador web, al descargar scripts
Un recurso compartido de archivos

Algunas de estas herramientas manejan bytes en lugar de texto, pero otros ofrecen
configuraciones de codificación. En los casos en que deba configurar una codificación,
tendrá que hacer la misma codificación que su editor, para evitar problemas.

Otros recursos sobre la codificación en


PowerShell
Hay algunas otras publicaciones interesantes sobre la codificación y la configuración de
la codificación en PowerShell, que vale la pena leer:

Acerca de la codificación de caracteres


Resumen sobre la codificación de PowerShell en StackOverflow, de @mklement0
Problemas anteriores abiertos en VS Code-PowerShell para los problemas de
codificación:
#1308
#1628
#1680
#1744
#1751
El clásico informe de Joel on Software acerca de Unicode
Codificación en .NET Standard
Uso de Visual Studio Code para depurar
cmdlets compilados
Artículo • 13/04/2023

En esta guía se muestra cómo depurar el código fuente de C# de forma interactiva para
un módulo de PowerShell compilado mediante Visual Studio Code (VS Code) y la
extensión de C#.

Se da por hecho que está familiarizado con el depurador de Visual Studio Code.

Para obtener una introducción general al depurador de VS Code, vea Depuración


en Visual Studio Code .

Para obtener ejemplos de cómo depurar módulos y archivos de scripts de


PowerShell, vea Uso de Visual Studio Code para la edición y la depuración de
forma remota.

En esta guía se da por hecho que ha leído y seguido las instrucciones de la guía
Escritura de módulos portables.

Creación de una tarea de compilación


Compile el proyecto automáticamente antes de iniciar una sesión de depuración. La
recompilación garantiza que se depura la versión más reciente del código.

Para configurar una tarea de compilación, haga lo siguiente:

1. En la Paleta de comandos, ejecute el comando Configure Default Build Task.

Ejecución del comando Configure Default Build Task

2. En el cuadro de diálogo Select a task to configure (Seleccionar una tarea para


configurar), elija Create tasks.json file from template (Crear archivo tasks.json a
partir de una plantilla).

3. En el cuadro de diálogo Select a Task Template (Seleccionar una plantilla de tarea),


elija .NET Core.

Si aún no existe, se crea un archivo tasks.json .

Para probar la tarea de compilación, haga lo siguiente:

1. En la Paleta de comandos, ejecute el comando Run Build Task.


2. En el cuadro de diálogo Select the build task to run (Seleccionar la tarea de
compilación para ejecutar), elija Compilar.

Información sobre los archivos DLL bloqueados


De forma predeterminada, una compilación correcta no muestra la salida en el panel del
terminal. Si ve una salida que contiene el texto El archivo del proyecto no existe, debe
editar el archivo de tasks.json . Incluya la ruta de acceso explícita al proyecto de C#
expresada como "${workspaceFolder}/myModule" . En este ejemplo, myModule es el
nombre de la carpeta del proyecto. Esta entrada debe ir después de la entrada build en
la lista args de la siguiente manera:

JSON

{
"label": "build",
"command": "dotnet",
"type": "shell",
"args": [
"build",
"${workspaceFolder}/myModule",
// Ask dotnet build to generate full paths for file names.
"/property:GenerateFullPaths=true",
// Do not generate summary otherwise it leads to duplicate
errors in Problems panel
"/consoleloggerparameters:NoSummary",
],
"group": "build",
"presentation": {
"reveal": "silent"
},
"problemMatcher": "$msCompile"
}

Al depurar, el archivo DLL del módulo se importa en la sesión de PowerShell en el


terminal de VS Code. El archivo DLL se bloquea. El mensaje siguiente se muestra al
ejecutar la tarea de compilación sin cerrar la sesión de terminal:

Output

Could not copy "obj\Debug\netstandard2.0\myModule.dll" to


"bin\Debug\netstandard2.0\myModule.dll"`.

Las sesiones del terminal deben cerrarse antes de recompilar.


Configuración del depurador
Para depurar el cmdlet de PowerShell, debe establecer una configuración de inicio
personalizada. Esta configuración se usa para lo siguiente:

Compilar el código fuente


Iniciar PowerShell con el módulo cargado
Dejar PowerShell abierto en el panel del terminal

Al invocar el cmdlet en la sesión de terminal, el depurador se detiene en los puntos de


interrupción establecidos en el código fuente.

Configuración de launch.json para PowerShell


1. Instale la extensión de C# para Visual Studio Code .

2. En el panel Depurar, agregue una configuración de depuración.

3. En el cuadro de diálogo Select environment , elija .NET Core .

4. El archivo launch.json se abre en el editor. Con el cursor dentro de la matriz


configurations , verá el selector configuration . Si no ve esta lista, seleccione
Agregar configuración.

5. Para crear una configuración de depuración predeterminada, seleccione Launch


.NET Core Console App (Iniciar la aplicación de consola de .NET Core):

Inicio de la aplicación de consola de .NET Core

6. Edite los campos name , program , args y console de la manera siguiente:

JSON

{
"name": "PowerShell cmdlets: pwsh",
"type": "coreclr",
"request": "launch",
"preLaunchTask": "build",
"program": "pwsh",
"args": [
"-NoExit",
"-NoProfile",
"-Command",
"Import-Module
${workspaceFolder}/myModule/bin/Debug/netstandard2.0/myModule.dll",
],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal"
}

El campo program se usa para iniciar pwsh , de modo que se pueda ejecutar el cmdlet
que se está depurando. El argumento -NoExit impide que la sesión de PowerShell se
salga en cuanto se importe el módulo. La ruta de acceso del argumento Import-Module
es la ruta de acceso de salida de la compilación predeterminada cuando se ha seguido
la guía Escritura de módulos portables. Si se ha creado un manifiesto de módulo
(archivo .psd1 ), debe usar en su lugar la ruta de acceso a este. El separador de ruta de
acceso / funciona en Windows, Linux y macOS. Debe usar el terminal integrado para
ejecutar los comandos de PowerShell que se quieren depurar.

7 Nota

Si el depurador no se detiene en ningún punto de interrupción, busque en la


Consola de depuración de Visual Studio Code una línea que indique lo siguiente:

Loaded '/path/to/myModule.dll'. Skipped loading symbols. Module is


optimized and the debugger option 'Just My Code' is enabled.

Si ve esto, agregue "justMyCode": false a la configuración de inicio (en el mismo


nivel que "console": "integratedTerminal" ).

Configuración de launch.json para Windows PowerShell


Esta configuración de inicio funciona para probar los cmdlets en Windows PowerShell
( powershell.exe ). Cree una segunda configuración de inicio con los cambios siguientes:

1. name tiene que ser PowerShell cmdlets: powershell

2. type tiene que ser clr

3. program tiene que ser powershell

Debería ser parecido a este:

JSON

{
"name": "PowerShell cmdlets: powershell",
"type": "clr",
"request": "launch",
"preLaunchTask": "build",
"program": "powershell",
"args": [
"-NoExit",
"-NoProfile",
"-Command",
"Import-Module
${workspaceFolder}/myModule/bin/Debug/netstandard2.0/myModule.dll",
],
"cwd": "${workspaceFolder}",
"stopAtEntry": false,
"console": "integratedTerminal"
}

Inicio de una sesión de depuración


Ahora todo está listo para comenzar la depuración.

Coloque un punto de interrupción en el código fuente del cmdlet que quiere


depurar:

Un punto de interrupción se muestra como un punto rojo en la encuadernación

Asegúrese de que la configuración relevante de los cmdlets de PowerShell está


seleccionada en el menú desplegable de configuración de la vista Depuración:

Selección de la configuración de inicio

Presione F5 o haga clic en el botón Iniciar depuración.

Cambie al panel de terminal e invoque el cmdlet:

Invocación del cmdlet

La ejecución se detiene en el punto de interrupción:

La ejecución se detiene en el punto de interrupción

Puede recorrer el código fuente, e inspeccionar las variables y la pila de llamadas.

Para finalizar la depuración, haga clic en Detener en la barra de herramientas Depurar o


presione Mayús + F5 . El shell que se usa para la depuración se cierra y libera el bloqueo
en el archivo DLL compilado.
Consideraciones de rendimiento de
scripting de PowerShell
Artículo • 27/06/2023

Los scripts de PowerShell que aprovechan .NET directamente y evitan la canalización


tienden a ser más rápidos que PowerShell idiomático. PowerShell idiomático usa
cmdlets y funciones de PowerShell, a menudo aprovechando la canalización y
recurriendo a .NET solo cuando sea necesario.

7 Nota

Muchas de las técnicas que se describen aquí no son de PowerShell idiomático y


pueden reducir la legibilidad de un script de PowerShell. Se recomienda a los
creadores de scripts que usen PowerShell idiomático a menos que el rendimiento
indique lo contrario.

Supresión de la salida
Hay muchas maneras de evitar escribir objetos en la canalización.

Asignación a $null
Conversión a [void]
Redireccionamiento de archivos a $null
Canalización a Out-Null

Las velocidades de asignación a $null , la conversión a [void] y el redireccionamiento


de archivos a $null son casi idénticas. Sin embargo, llamar a Out-Null en un bucle
grande puede ser un proceso considerablemente más lento, especialmente en
PowerShell 5.1.x.

PowerShell

$tests = @{
'Assign to $null' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
$null = $arraylist.Add($i)
}
}
'Cast to [void]' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
[void]$arraylist.Add($i)
}
}
'Redirect to $null' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
$arraylist.Add($i) > $null
}
}
'Pipe to Out-Null' = {
$arrayList = [System.Collections.ArrayList]::new()
foreach ($i in 0..$args[0]) {
$arraylist.Add($i) | Out-Null
}
}
}

10kb, 50kb, 100kb | ForEach-Object {


$groupResult = foreach ($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value $_ }).TotalMilliseconds

[pscustomobject]@{
Iterations = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
}

[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}

$groupResult = $groupResult | Sort-Object TotalMilliseconds


$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds /
$groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}

Estas pruebas se ejecutaron en una máquina Windows 11 en PowerShell 7.3.4. A


continuación se muestran resultados:

Output

Iterations Test TotalMilliseconds RelativeSpeed


---------- ---- ----------------- -------------
10240 Assign to $null 36.74 1x
10240 Redirect to $null 55.84 1.52x
10240 Cast to [void] 62.96 1.71x
10240 Pipe to Out-Null 81.65 2.22x
51200 Assign to $null 193.92 1x
51200 Cast to [void] 200.77 1.04x
51200 Redirect to $null 219.69 1.13x
51200 Pipe to Out-Null 329.62 1.7x
102400 Redirect to $null 386.08 1x
102400 Assign to $null 392.13 1.02x
102400 Cast to [void] 405.24 1.05x
102400 Pipe to Out-Null 572.94 1.48x

Los tiempos y velocidades relativas pueden variar en función del hardware, la versión de
PowerShell y la carga de trabajo actual del sistema.

Adición de matrices
La generación de una lista de elementos a menudo se realiza mediante una matriz con
el operador de suma:

PowerShell

$results = @()
$results += Do-Something
$results += Do-SomethingElse
$results

La adición de matrices es ineficaz porque las matrices tienen un tamaño fijo. Cada
adición a la matriz crea una matriz lo suficientemente grande como para contener todos
los elementos de los operandos izquierdo y derecho. Los elementos de ambos
operandos se copian en la nueva matriz. En el caso de colecciones pequeñas, es posible
que esta sobrecarga no sea importante. En el caso de las colecciones de gran tamaño, el
rendimiento puede verse afectado.

Hay un par de alternativas. Si no necesita realmente una matriz, podría usar mejor una
lista genérica con tipo (List<T>):

PowerShell

$results = [System.Collections.Generic.List[object]]::new()
$results.AddRange((Do-Something))
$results.AddRange((Do-SomethingElse))
$results

El impacto que el uso de la adición de matrices tiene en el rendimiento crece


exponencialmente con el tamaño de la colección y el número de adiciones. Este código
compara explícitamente la asignación de valores a una matriz con la adición de matrices
y el uso del método Add() en List<T>. La asignación explícita se define como la línea de
base para el rendimiento.

PowerShell

$tests = @{
'PowerShell Explicit Assignment' = {
param($count)

$result = foreach($i in 1..$count) {


$i
}
}
'.Add(..) to List<T>' = {
param($count)

$result = [Collections.Generic.List[int]]::new()
foreach($i in 1..$count) {
$result.Add($i)
}
}
'+= Operator to Array' = {
param($count)

$result = @()
foreach($i in 1..$count) {
$result += $i
}
}
}

5kb, 10kb, 100kb | ForEach-Object {


$groupResult = foreach($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value -Count $_
}).TotalMilliseconds

[pscustomobject]@{
CollectionSize = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
}

[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}

$groupResult = $groupResult | Sort-Object TotalMilliseconds


$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds /
$groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}

Estas pruebas se ejecutaron en una máquina Windows 11 en PowerShell 7.3.4.

Output

CollectionSize Test TotalMilliseconds


RelativeSpeed
-------------- ---- ----------------- ------------
-
5120 PowerShell Explicit Assignment 26.65 1x
5120 .Add(..) to List<T> 110.98 4.16x
5120 += Operator to Array 402.91 15.12x
10240 PowerShell Explicit Assignment 0.49 1x
10240 .Add(..) to List<T> 137.67 280.96x
10240 += Operator to Array 1678.13 3424.76x
102400 PowerShell Explicit Assignment 11.18 1x
102400 .Add(..) to List<T> 1384.03 123.8x
102400 += Operator to Array 201991.06 18067.18x

Cuando se trabaja con colecciones grandes, la adición de matrices es


considerablemente más lenta que realizar adiciones a List<T>.

Al usar List<T>, debe crear la lista con un tipo específico, como String o Int. Al agregar
objetos de un tipo diferente a la lista, se convierten al tipo especificado. Si no se pueden
convertir al tipo especificado, el método genera una excepción.

PowerShell

$intList = [System.Collections.Generic.List[int]]::new()
$intList.Add(1)
$intList.Add('2')
$intList.Add(3.0)
$intList.Add('Four')
$intList

Output

MethodException:
Line |
5 | $intList.Add('Four')
| ~~~~~~~~~~~~~~~~~~~~
| Cannot convert argument "item", with value: "Four", for "Add" to type
"System.Int32": "Cannot convert value "Four" to type "System.Int32".
Error: "The input string 'Four' was not in a correct format.""

1
2
3

Cuando necesite que la lista sea una colección de distintos tipos de objetos, créela con
Object como tipo de lista. Puede enumerar la colección para inspeccionar los tipos de
los objetos que contiene.

PowerShell

$objectList = [System.Collections.Generic.List[object]]::new()
$objectList.Add(1)
$objectList.Add('2')
$objectList.Add(3.0)
$objectList.GetEnumerator().ForEach({ "$_ is $($_.GetType())" })

Output

1 is int
2 is string
3 is double

Si necesita una matriz, puede llamar al método ToArray() en la lista o permitir que
PowerShell cree la matriz automáticamente:

PowerShell

$results = @(
Do-Something
Do-SomethingElse
)

En este ejemplo, PowerShell crea un objeto ArrayList para que contenga los resultados
escritos en la canalización dentro de la expresión de matriz. Justo antes de la asignación
a $results , PowerShell convierte ArrayList en un elemento object[].

Adición de cadenas
Las cadenas son inmutables. Cada adición a la cadena crea realmente una cadena lo
suficientemente grande como para contener todos los elementos de los operandos
izquierdo y derecho y, después, copia los elementos de ambos operandos en la nueva
cadena. En el caso de cadenas pequeñas, es posible que esta sobrecarga no sea
importante. En el caso de las cadenas de gran tamaño, esto puede afectar al
rendimiento y al consumo de memoria.
Hay al menos dos alternativas:

El operador -join concatena cadenas


La clase StringBuilder de .NET proporciona una cadena mutable.

En el ejemplo siguiente se compara el rendimiento de estos tres métodos de creación


de una cadena.

PowerShell

$tests = @{
'StringBuilder' = {
$sb = [System.Text.StringBuilder]::new()
foreach ($i in 0..$args[0]) {
$sb = $sb.AppendLine("Iteration $i")
}
$sb.ToString()
}
'Join operator' = {
$string = @(
foreach ($i in 0..$args[0]) {
"Iteration $i"
}
) -join "`n"
$string
}
'Addition Assignment +=' = {
$string = ''
foreach ($i in 0..$args[0]) {
$string += "Iteration $i`n"
}
$string
}
}

10kb, 50kb, 100kb | ForEach-Object {


$groupResult = foreach ($test in $tests.GetEnumerator()) {
$ms = (Measure-Command { & $test.Value $_ }).TotalMilliseconds

[pscustomobject]@{
Iterations = $_
Test = $test.Key
TotalMilliseconds = [math]::Round($ms, 2)
}

[GC]::Collect()
[GC]::WaitForPendingFinalizers()
}

$groupResult = $groupResult | Sort-Object TotalMilliseconds


$groupResult | Select-Object *, @{
Name = 'RelativeSpeed'
Expression = {
$relativeSpeed = $_.TotalMilliseconds /
$groupResult[0].TotalMilliseconds
[math]::Round($relativeSpeed, 2).ToString() + 'x'
}
}
}

Estas pruebas se ejecutaron en una máquina Windows 10 en PowerShell 7.3.4. La salida


muestra que el operador -join es el más rápido, seguido de la clase StringBuilder.

Output

Iterations Test TotalMilliseconds RelativeSpeed


---------- ---- ----------------- -------------
10240 Join operator 7.08 1x
10240 StringBuilder 54.10 7.64x
10240 Addition Assignment += 724.16 102.28x
51200 Join operator 41.76 1x
51200 StringBuilder 318.06 7.62x
51200 Addition Assignment += 17693.06 423.68x
102400 Join operator 106.98 1x
102400 StringBuilder 543.84 5.08x
102400 Addition Assignment += 90693.13 847.76x

Los tiempos y velocidades relativas pueden variar en función del hardware, la versión de
PowerShell y la carga de trabajo actual del sistema.

Procesamiento de archivos grandes


La manera idiomática de procesar un archivo en PowerShell podría similar a lo siguiente:

PowerShell

Get-Content $path | Where-Object { $_.Length -gt 10 }

Esto puede ser un orden de magnitud más lento que usar de forma directa las API de
.NET:

PowerShell

try
{
$stream = [System.IO.StreamReader]::new($path)
while ($line = $stream.ReadLine())
{
if ($line.Length -gt 10)
{
$line
}
}
}
finally
{
$stream.Dispose()
}

Búsqueda de entradas por propiedad en colecciones


grandes
Es habitual usar una propiedad compartida para identificar el mismo registro en
colecciones diferentes, como usar un nombre para recuperar un identificador de una
lista y un correo electrónico de otro. El proceso de iterar por la primera lista para buscar
el registro coincidente en la segunda colección es lento. En concreto, el filtrado repetido
de la segunda colección tiene una gran sobrecarga.

Dadas dos colecciones, una con un elemento ID y Name, y la otra con un elemento
Name y Email:

PowerShell

$Employees = 1..10000 | ForEach-Object {


[PSCustomObject]@{
Id = $_
Name = "Name$_"
}
}

$Accounts = 2500..7500 | ForEach-Object {


[PSCustomObject]@{
Name = "Name$_"
Email = "Name$_@fabrikam.com"
}
}

La manera habitual de conciliar estas colecciones para devolver una lista de objetos con
las propiedades ID, Name y Email podría tener este aspecto:

PowerShell

$Results = $Employees | ForEach-Object -Process {


$Employee = $_

$Account = $Accounts | Where-Object -FilterScript {


$_.Name -eq $Employee.Name
}

[pscustomobject]@{
Id = $Employee.Id
Name = $Employee.Name
Email = $Account.Email
}
}

Pero esa implementación tiene que filtrar los 5000 elementos de la colección $Accounts
una vez por cada elemento de la colección $Employee . Esto puede tardar minutos,
incluso para esta búsqueda de un solo valor.

En su lugar, puede crear una tabla hash que use la propiedad Name compartida como
clave y la cuenta coincidente como valor.

PowerShell

$LookupHash = @{}
foreach ($Account in $Accounts) {
$LookupHash[$Account.Name] = $Account
}

Buscar claves en una tabla hash es mucho más rápido que filtrar una colección por
valores de propiedad. En lugar de comprobar cada elemento de la colección, PowerShell
puede comprobar si la clave está definida y usar su valor.

PowerShell

$Results = $Employees | ForEach-Object -Process {


$Email = $LookupHash[$_.Name].Email
[pscustomobject]@{
Id = $_.Id
Name = $_.Name
Email = $Email
}
}

Esto es mucho más rápido. Mientras el filtro de bucle tardó minutos en completarse, la
búsqueda de hash tardó menos de un segundo.

Evitar Write-Host
Por lo general, se considera un procedimiento incorrecto escribir la salida directamente
en la consola, pero cuando tiene sentido, muchos scripts usan Write-Host .
Si tiene que escribir muchos mensajes en la consola, Write-Host puede ser un orden de
magnitud más lento que [Console]::WriteLine() para hosts específicos como pwsh.exe ,
powershell.exe o powershell_ise.exe . Sin embargo, no se garantiza que

[Console]::WriteLine() funcione en todos los hosts. Además, la salida escrita mediante


[Console]::WriteLine() no se escribe en transcripciones iniciadas por Start-

Transcript .

En lugar de usar Write-Host , considere la posibilidad de usar Write-Output.

compilación Just-In-Time
PowerShell compila el código de script en el código de bytes que se interpreta. A partir
de PowerShell 3, para el código que se ejecuta repetidamente en un bucle, PowerShell
puede mejorar el rendimiento mediante la compilación Just-In-Time (JIT) del código en
código nativo.

Los bucles que tienen menos de 300 instrucciones son aptos para la compilación JIT. Los
bucles más grandes son demasiado costosos de compilar. Cuando el bucle se ha
ejecutado 16 veces, el script se compila con JIT en segundo plano. Cuando se completa
la compilación con JIT, la ejecución se transfiere al código compilado.

Evitar llamadas repetidas a una función


Llamar a una función puede ser una operación costosa. Si llama a una función en un
bucle estrecho de larga duración, considere la posibilidad de mover el bucle dentro de
la función.

Considere los siguientes ejemplos:

PowerShell

$ranGen = New-Object System.Random


$RepeatCount = 10000

'Basic for-loop = {0}ms' -f (Measure-Command -Expression {


for ($i = 0; $i -lt $RepeatCount; $i++) {
$Null = $ranGen.Next()
}
}).TotalMilliseconds

'Wrapped in a function = {0}ms' -f (Measure-Command -Expression {


function Get-RandNum_Core {
param ($ranGen)
$ranGen.Next()
}
for ($i = 0; $i -lt $RepeatCount; $i++) {
$Null = Get-RandNum_Core $ranGen
}
}).TotalMilliseconds

'For-loop in a function = {0}ms' -f (Measure-Command -Expression {


function Get-RandNum_All {
param ($ranGen)
for ($i = 0; $i -lt $RepeatCount; $i++) {
$Null = $ranGen.Next()
}
}

Get-RandNum_All $ranGen
}).TotalMilliseconds

El ejemplo Basic for-loop es la base de referencia para el rendimiento. El segundo


ejemplo encapsula el generador de números aleatorios en una función a la que se llama
en un bucle ajustado. El tercer ejemplo mueve el bucle dentro de la función. Solo se
llama a la función una vez, pero el código sigue generando 10 000 números aleatorios.
Observe la diferencia en los tiempos de ejecución de cada ejemplo.

Output

Basic for-loop = 47.8668ms


Wrapped in a function = 820.1396ms
For-loop in a function = 23.3193ms

Evitar el encapsulamiento de canalizaciones de


cmdlet
La mayoría de los cmdlets se implementan para la canalización, que es un proceso y una
sintaxis de carácter secuencial. Por ejemplo:

PowerShell

cmdlet1 | cmdlet2 | cmdlet3

La inicialización de una nueva canalización puede ser costosa, por lo que debe evitar
encapsular una canalización de cmdlet en otra canalización existente.

Considere el ejemplo siguiente. El archivo Input.csv contiene 2100 líneas. El comando


Export-Csv se encapsula dentro de la canalización ForEach-Object . El cmdlet Export-
Csv se invoca para cada iteración del bucle ForEach-Object .
PowerShell

'Wrapped = {0:N2} ms' -f (Measure-Command -Expression {


Import-Csv .\Input.csv | ForEach-Object -Begin { $Id = 1 } -Process {
[PSCustomObject]@{
Id = $Id
Name = $_.opened_by
} | Export-Csv .\Output1.csv -Append
}
}).TotalMilliseconds

Wrapped = 15,968.78 ms

En el ejemplo siguiente, el comando Export-Csv se movió fuera de la canalización


ForEach-Object . En este caso, Export-Csv se invoca solo una vez, pero sigue procesando

todos los objetos pasados fuera de ForEach-Object .

PowerShell

'Unwrapped = {0:N2} ms' -f (Measure-Command -Expression {


Import-Csv .\Input.csv | ForEach-Object -Begin { $Id = 2 } -Process {
[PSCustomObject]@{
Id = $Id
Name = $_.opened_by
}
} | Export-Csv .\Output2.csv
}).TotalMilliseconds

Unwrapped = 42.92 ms

El ejemplo desencapsulado es 372 veces más rápido. Además, tenga en cuenta que la
primera implementación requiere el parámetro Append , que no es necesario para la
implementación posterior.
Consideraciones sobre la creación de
módulos de PowerShell
Artículo • 13/04/2023

En este documento se incluyen algunas instrucciones relacionadas con la creación de un


módulo para obtener el mejor rendimiento.

Creación de manifiestos de módulo


Un manifiesto de módulo en el que no se usen las instrucciones siguientes puede
afectar notablemente el rendimiento general de PowerShell incluso si el módulo no se
usa en una sesión.

La detección automática de comandos analiza cada módulo para determinar qué


comandos exporta, y este análisis puede ser costoso. Los resultados del análisis del
módulo se almacenan en caché por cada usuario, pero la caché no está disponible en la
primera ejecución, que es un escenario típico con los contenedores. Durante el análisis
del módulo, si los comandos exportados se pueden determinar de manera completa a
partir del manifiesto, se puede evitar un análisis más costoso del módulo.

Directrices
No uses caracteres comodín en las entradas AliasesToExport , CmdletsToExport y
FunctionsToExport del manifiesto del módulo.

Si el módulo no exporta comandos de un tipo determinado, es necesario


especificarlo de forma explícita en el manifiesto mediante @() . Una entrada que
falta o que sea $null equivale a especificar el carácter comodín * .

Siempre que sea posible, se debe evitar lo siguiente:

PowerShell

@{
FunctionsToExport = '*'

# Also avoid omitting an entry, it's equivalent to using a wildcard


# CmdletsToExport = '*'
# AliasesToExport = '*'
}
En su lugar, use:

PowerShell

@{
FunctionsToExport = 'Format-Hex', 'Format-Octal'
CmdletsToExport = @() # Specify an empty array, not $null
AliasesToExport = @() # Also ensure all three entries are present
}

Evitar CDXML
A la hora de decidir cómo implementar el módulo, hay tres opciones principales:

Binario (normalmente C#)


Script (PowerShell)
CDXML (un archivo XML que encapsule CIM)

Si la velocidad de carga del módulo es importante, CDXML es aproximadamente un


orden de magnitud más lento que un módulo binario.

Un módulo binario tiene la carga más rápida porque se compila con antelación y puede
usar NGen para compilar JIT una vez por máquina.

Normalmente, un módulo de script se carga más lentamente que un módulo binario


porque PowerShell debe analizar el script antes de compilarlo y ejecutarlo.

Un módulo CDXML suele ser mucho más lento que un módulo de script porque debe
analizar primero un archivo XML que, después, genera bastantes scripts de PowerShell
que se analizan y se compilan luego.
Prevención de ataques por inyección de
script
Artículo • 13/04/2023

Los scripts de PowerShell, como cualquier otro lenguaje de programación, pueden ser
vulnerables a ataques por inyección. Un ataque por inyección se produce cuando un
usuario proporciona una entrada a una función vulnerable que incluye comandos
adicionales. La función vulnerable ejecuta esos comandos adicionales, lo que puede
suponer una vulnerabilidad de seguridad grave. Por ejemplo, un usuario
malintencionado podría abusar de la función vulnerable para ejecutar código arbitrario
en un equipo remoto, lo que podría poner en peligro ese equipo y permitir el acceso a
otras máquinas de la red.

Una vez se tiene conocimiento del problema, existen varias formas de protegerse de
ataques por inyección.

Ejemplo de código vulnerable


En las vulnerabilidades de inyección de código de PowerShell participa una entrada de
usuario que contiene código de script. La entrada de usuario se agrega a un script
vulnerable donde se analiza y ejecuta mediante PowerShell.

PowerShell

function Get-ProcessById
{
param ($ProcId)

Invoke-Expression -Command "Get-Process -Id $ProcId"


}

La función Get-ProcessById busca un proceso local por su valor de identificador. Toma


un argumento de parámetro $ProcId de cualquier tipo. Luego, $ProcId se convierte en
una cadena y se inserta en otro script que se analiza y ejecuta mediante el cmdlet
Invoke-Expression . Esta función se comporta correctamente cuando se pasa un entero
de identificador de proceso válido.

PowerShell

Get-ProcessById $pid

NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName


------ ----- ----- ------ -- -- -----------
97 50.09 132.72 1.20 12528 3 pwsh

Sin embargo, el parámetro $ProcId no especifica un tipo. Acepta cualquier valor de


cadena arbitrario que pueda incluir otros comandos.

PowerShell

Get-ProcessById "$pid; Write-Host 'pwnd!'"

En este ejemplo, la función recuperó correctamente el proceso identificado mediante


$pid , pero también ejecutó el script insertado Write-Host 'pwnd!' .

Output

NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName


------ ----- ----- ------ -- -- -----------
92 45.66 122.52 1.06 21736 3 pwsh
pwnd!

Formas de protegerse de ataques por inyección


Existen varias formas de protegerse de un ataque por inyección.

Usar una entrada con tipo


Se puede especificar un tipo para el argumento $ProcId .

PowerShell

function Get-ProcessById
{
param ([int] $ProcId)

Invoke-Expression -Command "Get-Process -Id $ProcId"


}
Get-ProcessById "$pid; Write-Host 'pwnd!'"

Output

Get-ProcessById:
Line |
7 | Get-ProcessById "$pid; Write-Host 'pwnd!'"
| ~~~~~~~~~~~~~~~~~~~~~~~~~
| Cannot process argument transformation on parameter 'ProcId'. Cannot
convert value
"8064; Write-Host 'pwnd!'" to type "System.Int32". Error: "The input string
'8064; Write-Host 'pwnd!'
was not in a correct format."

En este caso, el parámetro de entrada $ProcId está restringido a un tipo entero, por lo
que se produce un error cuando se pasa una cadena que no se puede convertir en un
entero.

No use Invoke-Expression .
En lugar de usar Invoke-Expression , llame directamente a Get-Process y deje que el
enlazador de parámetros de PowerShell valide la entrada.

PowerShell

function Get-ProcessById
{
param ($ProcId)

Get-Process -Id $ProcId


}
Get-ProcessById "$pid; Write-Host 'pwnd!'"

Output

Get-Process:
Line |
5 | Get-Process -Id $ProcId
| ~~~~~~~
| Cannot bind parameter 'Id'. Cannot convert value "8064; Write-Host
'pwnd!'" to type
"System.Int32". Error: "The input string '8064; Write-Host 'pwnd!' was not
in a correct
format."

Como procedimiento recomendado, absténgase de usar Invoke-Expression ,


especialmente al controlar entradas de usuario. Invoke-Expression es peligroso porque
analiza y ejecuta el contenido de cadena que se haya proporcionado, lo que hace que
sea vulnerable a ataques por inyección. Es mejor recurrir al enlace de parámetros de
PowerShell.

Entrecomillar las cadenas con comillas simples


Sin embargo, hay veces en las que usar Invoke-Expression es inevitable, y también es
necesario controlar la entrada de cadenas de usuario. La entrada de usuario se puede
controlar de forma segura entrecomillando cada variable de entrada de la cadena con
comillas simples. Las comillas simples hacen que el analizador de PowerShell trate la
entrada de usuario como un literal de cadena único.

PowerShell

function Get-ProcessById
{
param ($ProcId)

Invoke-Expression -Command "Get-Process -Id '$ProcId'"


}

Get-ProcessById "$pid; Write-Host 'pwnd!'"

Output

Get-Process: Cannot bind parameter 'Id'. Cannot convert value "8064; Write-
Host " to type
"System.Int32". Error: "The input string '8064; Write-Host' was not in a
correct format."

Sin embargo, esta versión de la función todavía no es completamente segura frente a


ataques de inyección. Un usuario malintencionado también podría usar comillas simples
en su entrada para insertar código.

PowerShell

Get-ProcessById "$pid'; Write-Host 'pwnd!';'"

En este ejemplo se usan comillas simples en la entrada de usuario para forzar a la


función a ejecutar tres instrucciones por separado, una de las cuales es código arbitrario
insertado por el usuario.

Output

NPM(K) PM(M) WS(M) CPU(s) Id SI ProcessName


------ ----- ----- ------ -- -- -----------
97 46.08 183.10 1.08 2524 3 pwsh
pwnd!

Uso del método EscapeSingleQuotedStringContent()


Para protegerse de la posibilidad de que un usuario inserte sus propias comillas simples
para aprovechar la función, hay que usar la API EscapeSingleQuotedStringContent() . Se
trata de un método público estático de la clase
System.Management.Automation.Language.CodeGeneration de PowerShell. Este
método hace que la entrada de usuario sea segura, para lo cual se escapa cualquier
carácter de comilla simple incluido en la entrada de usuario.

PowerShell

function Get-ProcessById
{
param ($ProcId)

$ProcIdClean = [System.Management.Automation.Language.CodeGeneration]::
EscapeSingleQuotedStringContent("$ProcId")
Invoke-Expression -Command "Get-Process -Id '$ProcIdClean'"
}
Get-ProcessById "$pid'; Write-Host 'pwnd!';'"

Output

Get-Process: Cannot bind parameter 'Id'. Cannot convert value "8064'; Write-
Host 'pwnd!';'" to type
"System.Int32". Error: "The input string '8064'; Write-Host 'pwnd!';'' was
not in a correct format."

Para obtener más información, vea EscapeSingleQuotedStringContent().

Detección de código vulnerable con Injection


Hunter
Injection Hunter es un módulo escrito por Lee Holmes que contiene reglas del
analizador de scripts de PowerShell para detectar vulnerabilidades de inyección de
código. Use uno de los siguientes comandos para instalar el módulo desde la Galería de
PowerShell:

PowerShell

# Use PowerShellGet v2.x


Install-Module InjectionHunter

# Use PowerShellGet v3.x


Install-PSResource InjectionHunter
Puede usarlo para automatizar los análisis de seguridad durante las compilaciones, los
procesos de integración continua, las implementaciones y otros escenarios.

PowerShell

$RulePath = (Get-Module -list InjectionHunter).Path


Invoke-ScriptAnalyzer -CustomRulePath $RulePath -Path .\Invoke-Dangerous.ps1

Output

RuleName Severity ScriptName Line Message


-------- -------- ---------- ---- -------
InjectionRisk.InvokeExpression Warning Invoke-Dan 3 Possible
script injection risk via the
gerous.ps1 Invoke-
Expression cmdlet. Untrusted input can cause
arbitrary
PowerShell expressions to be run.
Variables
may be used directly for dynamic parameter
arguments,
splatting can be used for dynamic
parameter
names, and the invocation operator can be
used for
dynamic command names. If content escaping
is truly
needed, PowerShell has several valid quote

characters, so [System.Management.Automation.Languag

e.CodeGeneration]::Escape* should be used.

Para obtener más información, vea PSScriptAnalyzer.

Vínculos relacionados
Entrada de blog de Lee Holmes sobre Injection Hunter
Injection Hunter
Securing a restricted PowerShell
remoting session
Article • 10/10/2023

There are scenarios where you want to host a PowerShell session that, for security
reasons, has been limited to a subset of PowerShell commands.

By definition, a restricted session is one where Import-Module isn't allowed to be used.


There may be other limitations, but this is the primary requirement. If the user can
import a module, then they can run anything they want.

Examples of restricted sessions include:

Just-Enough-Administration (JEA)
Custom restricted remoting implementations such as the Exchange and Teams
modules

For most system administrators, JEA provides the best experience for creating restricted
sessions and should be your first choice. For more information about JEA, see the JEA
Overview.

Recommendations for custom session


implementations
If your scenario requires a custom implementation, then you should follow these
recommendations.

Limit the use and capabilities of PowerShell providers


Review how the allowed providers are used to ensure that you don't create
vulnerabilities in your restricted session implementation.

2 Warning

Don't allow the FileSystem provider. If users can write to any part of the file system,
it's possible to completely bypass security.

Don't allow the Certificate provider. With the provider enabled, a user could gain
access to stored private keys.
Don't allow commands that can create new runspaces

2 Warning

The *-Job cmdlets can create new runspaces without the restrictions.

Don't allow the Trace-Command cmdlet.

2 Warning

Using Trace-Command brings all traced commands into the session.

Don't create your own proxy implementations for the


restricted commands
PowerShell has a set of proxy commands for restricted command scenarios. These proxy
commands ensure that input parameters can't compromise the security of the session.
The following commands have restricted proxies:

Exit-PSSession
Get-Command

Get-FormatData

Get-Help
Measure-Object

Out-Default
Select-Object

If you create your own implementation of these commands, you may inadvertently allow
users to run code prohibited by the JEA proxy commands.

You can run the following command to get a list of restricted commands:

PowerShell

$commands =
[System.Management.Automation.CommandMetadata]::GetRestrictedCommands(
[System.Management.Automation.SessionCapabilities]::RemoteServer
)

You can examine the restricted proxy commands by using the following command:
PowerShell

$commands =
[System.Management.Automation.CommandMetadata]::GetRestrictedCommands(
[System.Management.Automation.SessionCapabilities]::RemoteServer
)
$getHelpProxyBlock =
[System.Management.Automation.ProxyCommand]::Create($commands['Get-Help'])

Configure the session to use NoLanguage mode


PowerShell NoLanguage mode disables the PowerShell scripting language completely.
You can't run scripts or use variables. You can only run native commands and cmdlets.

For more information about language modes, see about_Language_Modes.

Don't allow the debugger to be used in the session


By default, the PowerShell debugger runs code in FullLanguage mode. Set the
UseFullLanguageModeInDebugger property in the SessionState to false.

For more information, see UseFullLanguageModeInDebugger.

6 Collaborate with us on
PowerShell feedback
GitHub
PowerShell is an open source
The source for this content can project. Select a link to provide
be found on GitHub, where you feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Módulos portables
Artículo • 13/04/2023

Windows PowerShell está escrito para .NET Framework, mientras que PowerShell Core
está escrito para .NET Core. Los módulos portables son módulos que funcionan en
Windows PowerShell y PowerShell Core. Si bien .NET Framework y .NET Core son
altamente compatibles, existen diferencias en las API disponibles entre los dos. También
hay diferencias en las API disponibles en Windows PowerShell y PowerShell Core. Los
módulos destinados para su uso en ambos entornos deben tener en cuenta estas
diferencias.

Portabilidad de un módulo existente

Migración de un elemento PSSnapIn


Los complementos PowerShell SnapIns no se admiten en PowerShell Core. Sin embargo,
resulta trivial convertir un PSSnapIn en un módulo de PowerShell. Normalmente, el
código de registro del PSSnapIn se encuentra en un único archivo de código fuente de
una clase que se deriva de PSSnapIn. Quite este archivo de código fuente de la
compilación; ya no es necesario.

Use New-ModuleManifest para crear un nuevo manifiesto de módulo que reemplace la


necesidad del código de registro del PSSnapIn. Algunos de los valores del complemento
PSSnapIn (como la descripción) se pueden reutilizar en el manifiesto del módulo.

La propiedad RootModule del manifiesto del módulo debe establecerse en el nombre


del ensamblado ( .dll ) que implementa los cmdlets.

Analizador de portabilidad de .NET (también conocido


como APIPort)
Para migrar los módulos escritos para Windows PowerShell para que funcionen con
PowerShell Core, empiece con el analizador de portabilidad de .NET . Ejecute esta
herramienta en su ensamblado compilado para determinar si las API de .NET utilizadas
en el módulo son compatibles con .NET Framework, .NET Core y otros entornos de
ejecución de .NET. La herramienta sugiere API alternativas si existen. En caso contrario,
es posible que deba agregar comprobaciones del entorno de ejecución y restringir las
funciones no disponibles en los entornos de ejecución específicos.
Creación de un módulo
Si crea un nuevo módulo, la recomendación es que use la CLI de .NET.

Instalación de la plantilla del módulo de PowerShell


Estándar
Una vez que la CLI de .NET esté instalada, instale una biblioteca de plantillas para
generar un módulo de PowerShell simple. El módulo será compatible con Windows
PowerShell, PowerShell Core, Windows, Linux y macOS.

En el ejemplo siguiente se muestra cómo instalar la plantilla:

PowerShell

dotnet new install Microsoft.PowerShell.Standard.Module.Template

Resultados

The following template packages will be installed:


Microsoft.PowerShell.Standard.Module.Template

Success: Microsoft.PowerShell.Standard.Module.Template::0.1.3 installed the


following templates:
Template Name Short Name Language Tags
-------------------------- ---------- -------- -------------------------
PowerShell Standard Module psmodule [C#] Library/PowerShell/Module

Creación de un proyecto de módulo


Después de instalar la plantilla, puede crear un nuevo proyecto de módulo de
PowerShell con esa plantilla. En este ejemplo, el módulo de ejemplo se denomina
"myModule".

PS> mkdir myModule

Directory: C:\Users\Steve

Mode LastWriteTime Length Name


---- ------------- ------ ----
d----- 8/3/2018 2:41 PM myModule

PS> cd myModule
PS C:\Users\Steve\myModule> dotnet new psmodule
The template "PowerShell Standard Module" was created successfully.

Processing post-creation actions...


Restoring C:\Users\Steve\myModule\myModule.csproj:
Determining projects to restore...
Restored C:\Users\Steve\myModule\myModule.csproj (in 184 ms).
Restore succeeded.

Compilación del módulo


Use los comandos CLI de .NET estándar para compilar el proyecto.

PowerShell

dotnet build

Resultados

PS C:\Users\Steve\myModule> dotnet build


MSBuild version 17.6.3+07e294721 for .NET
Determining projects to restore...
All projects are up-to-date for restore.
PowerShellPG ->
C:\Users\Steve\myModule\bin\Debug\netstandard2.0\myModule.dll

Build succeeded.
0 Warning(s)
0 Error(s)

Time Elapsed 00:00:02.36

Prueba del módulo


Después de compilar el módulo, puede importarlo y ejecutar el cmdlet de ejemplo.

PowerShell

Import-Module .\bin\Debug\netstandard2.0\myModule.dll
Test-SampleCmdlet -?
Test-SampleCmdlet -FavoriteNumber 7 -FavoritePet Cat

Resultados

NAME
Test-SampleCmdlet
SYNTAX
Test-SampleCmdlet [-FavoriteNumber] <int> [[-FavoritePet] {Cat | Dog |
Horse}] [<CommonParameters>]

ALIASES
None

REMARKS
None

FavoriteNumber FavoritePet
-------------- -----------
7 Cat

Depuración del módulo


Para obtener una guía sobre cómo configurar Visual Studio Code a fin de depurar el
módulo, vea Uso de Visual Studio Code para depurar cmdlets compilados.

Tecnologías de apoyo
Las secciones siguientes describen en detalle algunas de las tecnologías usadas por esta
plantilla.

Biblioteca de .NET Standard


.NET standard es una especificación formal de las API de .NET que están disponibles en
todas las implementaciones de. NET. El código administrado destinado a .NET Standard
funciona con las versiones .NET Framework y .NET Core que son compatibles con esa
versión de .NET Standard.

7 Nota

Aunque puede existir una API en .NET Standard, la implementación de la API de


.NET Core puede producir un PlatformNotSupportedException en el entorno de
ejecución; así pues, para comprobar la compatibilidad con Windows PowerShell y
PowerShell Core, el procedimiento recomendado es ejecutar pruebas para el
módulo en ambos entornos. También debe ejecutar las pruebas en Linux y macOS
si el módulo está pensado para ser multiplataforma.
Destinarlo a .NET Standard ayuda a garantizar que, a medida que evoluciona el módulo,
las API incompatibles no se introduzcan involuntariamente en el módulo. Las
incompatibilidades se detectan en tiempo de compilación en lugar de en tiempo de
ejecución.

Sin embargo, no es necesario que un módulo tenga como destino .NET Standard para
que funcione con Windows PowerShell y PowerShell Core, siempre que use API
compatibles. El lenguaje intermedio (IL) es compatible entre los dos tiempos de
ejecución. Puede tener como destino .NET Framework 4.6.1, que es compatible con .NET
Standard 2.0. Si no usa las API fuera de .NET Standard 2.0, el módulo funciona con
PowerShell Core 6 sin volver a compilar.

Biblioteca de PowerShell estándar


La biblioteca de PowerShell estándar es una especificación formal de las API de
PowerShell disponibles en todas las versiones de PowerShell que sean superiores o
iguales a la versión de ese estándar.

Por ejemplo, PowerShell estándar 5.1 es compatible con Windows PowerShell 5.1 y
PowerShell Core 6.0 o posterior.

Se recomienda que compile el módulo mediante la biblioteca estándar de PowerShell.


La biblioteca garantiza que las API están disponibles y se implementan en Windows
PowerShell y PowerShell Core 6. PowerShell estándar está concebido para que sea
compatible siempre con versiones posteriores. Un módulo compilado con la biblioteca
de PowerShell estándar 5.1 siempre será compatible con versiones futuras de
PowerShell.

Manifiesto de módulo

Indicación de la compatibilidad con Windows PowerShell y


PowerShell Core
Después de comprobar que el módulo funciona con Windows PowerShell y PowerShell
Core, el manifiesto del módulo debe indicar explícitamente la compatibilidad mediante
el uso de la propiedad CompatiblePSEditions. Un valor de Desktop significa que el
módulo es compatible con Windows PowerShell, mientras que un valor de Core
significa que el módulo es compatible con PowerShell Core. La inclusión de Desktop y
Core significa que el módulo es compatible con Windows PowerShell y PowerShell Core.
7 Nota

Core no significa que el módulo sea compatible con Windows, Linux y macOS de
manera automática. La propiedad CompatiblePSEditions se introdujo en
PowerShell v5. Los manifiestos de módulo que usan la propiedad
CompatiblePSEditions no se pueden cargar en las versiones anteriores de
PowerShell v5.

Indicación de la compatibilidad del SO


En primer lugar, valide que el módulo funciona en Linux y macOS. A continuación,
indique la compatibilidad con esos sistemas operativos en el manifiesto del módulo.
Esto facilita a los usuarios encontrar el módulo para su sistema operativo cuando se
publican en la Galería de PowerShell .

En el manifiesto del módulo, la propiedad PrivateData tiene una subpropiedad PSData .


La propiedad Tags opcional de PSData toma una matriz de valores que se muestran en
la Galería de PowerShell. La Galería de PowerShell admite los siguientes valores de
compatibilidad:

Etiqueta Descripción

PSEdition_Core Compatible con PowerShell Core 6

PSEdition_Desktop Compatible con Windows PowerShell

Windows Compatible con Windows

Linux Compatible con Linux (ninguna distribución específica)

macOS Compatible con macOS

Ejemplo:

PowerShell

@{
GUID = "4ae9fd46-338a-459c-8186-07f910774cb8"
Author = "Microsoft Corporation"
CompanyName = "Microsoft Corporation"
Copyright = "(C) Microsoft Corporation. All rights reserved."
HelpInfoUri = "https://go.microsoft.com/fwlink/?linkid=855962"
ModuleVersion = "1.2.4"
PowerShellVersion = "3.0"
ClrVersion = "4.0"
RootModule = "PackageManagement.psm1"
Description = 'PackageManagement (a.k.a. OneGet) is a new way to
discover and install software packages from around the web.
it's a manager or multiplexer of existing package managers (also called
package providers) that unifies Windows package management with a single
Windows PowerShell interface. With PackageManagement, you can do the
following.
- Manage a list of software repositories in which packages can be
searched, acquired and installed
- Discover software packages
- Seamlessly install, uninstall, and inventory packages from one or more
software repositories'

CmdletsToExport = @(
'Find-Package',
'Get-Package',
'Get-PackageProvider',
'Get-PackageSource',
'Install-Package',
'Import-PackageProvider'
'Find-PackageProvider'
'Install-PackageProvider'
'Register-PackageSource',
'Set-PackageSource',
'Unregister-PackageSource',
'Uninstall-Package'
'Save-Package'
)

FormatsToProcess = @('PackageManagement.format.ps1xml')

PrivateData = @{
PSData = @{
Tags = @('PackageManagement', 'PSEdition_Core',
'PSEdition_Desktop', 'Windows', 'Linux', 'macOS')
ProjectUri = 'https://oneget.org'
}
}
}

Dependencia de bibliotecas nativas


Los módulos destinados a usarse en diferentes sistemas operativos o arquitecturas de
procesador pueden depender de una biblioteca administrada que dependa de algunas
bibliotecas nativas.

Antes de PowerShell 7, había que tener código personalizado para cargar la dll nativa
adecuada de modo que la biblioteca administrada pudiera encontrarla correctamente.

Con PowerShell 7, los archivos binarios nativos que se van a cargar se buscan en las
subcarpetas de la ubicación de la biblioteca administrada situada después de un
subconjunto de la notación Catálogo de identificadores de entorno de ejecución (RID)
de .NET

managed.dll folder
|
|--- 'win-x64' folder
| |--- native.dll
|
|--- 'win-x86' folder
| |--- native.dll
|
|--- 'win-arm' folder
| |--- native.dll
|
|--- 'win-arm64' folder
| |--- native.dll
|
|--- 'linux-x64' folder
| |--- native.so
|
|--- 'linux-x86' folder
| |--- native.so
|
|--- 'linux-arm' folder
| |--- native.so
|
|--- 'linux-arm64' folder
| |--- native.so
|
|--- 'osx-x64' folder
| |--- native.dylib
Cómo crear un módulo binario de
biblioteca estándar
Artículo • 13/04/2023

Recientemente tuve una idea para el módulo que quería implementar como módulo
binario. Aún tengo que crear uno mediante la biblioteca de PowerShell estándar , por
lo que me pareció que se trataba de una buena oportunidad. Usé la guía sobre cómo
Creación de un módulo binario multiplataforma para crear este módulo sin ningún
obstáculo. Vamos a recorrer ese mismo proceso y agregaré un pequeño comentario
adicional durante el mismo.

7 Nota

La versión original de este artículo apareció en el blog escrito por


@KevinMarquette . El equipo de PowerShell agradece a Kevin que comparta este
contenido con nosotros. Visite su blog en PowerShellExplained.com .

¿Qué es la biblioteca de PowerShell estándar?


La biblioteca de PowerShell estándar nos permite crear módulos multiplataforma que
funcionan tanto en PowerShell como en Windows PowerShell 5.1.

¿Por qué módulos binarios?


Al escribir un módulo en C#, renuncia a un acceso sencillo a las funciones y los cmdlets
de PowerShell. Sin embargo, si crea un módulo que no depende de muchos otros
comandos de PowerShell, la ventaja de rendimiento puede ser significativa. PowerShell
se optimizó para el administrador, no el equipo. Al cambiar a C#, logra perder la
sobrecarga agregada por PowerShell.

Por ejemplo, tenemos un proceso crítico que realiza mucho trabajo con JSON y tablas
hash. Hemos optimizado PowerShell todo lo posible, pero el proceso aún tarda 12
minutos en completarse. El módulo ya contenía una gran cantidad de PowerShell de
estilo de C#. Esto hace que la conversión a un módulo binario sea limpia y simple. Al
efectuar la conversión a un módulo binario, se ha reducido el tiempo de proceso de más
de 12 minutos a menos de cuatro minutos.

Módulos híbridos
Pueden mezclarse cmdlets binarios con funciones avanzadas de PowerShell. Todos sus
conocimientos sobre los módulos de script se aplican de la misma manera. Se incluye el
archivo vacío psm1 para que pueda agregar otras funciones de PowerShell
posteriormente.

Casi todos los cmdlets compilados que he creado comenzaron como funciones de
PowerShell en primer lugar. Todos nuestros módulos binarios son en realidad módulos
híbridos.

Scripts de compilación
He simplificado el script de compilación aquí. En general, se usa un script Invoke-Build
de gran tamaño como parte de mi canalización de CI/CD. Realiza otros trucos mágicos,
como la ejecución de pruebas de Pester, la ejecución de PSScriptAnalyzer, la
administración de versiones y la publicación en PSGallery. Una vez que empecé a usar
un script de compilación para mis módulos, pude encontrar muchas cosas que agregar
a este.

Planificación del módulo


El plan de este módulo es crear una carpeta src para el código de C# y estructurar el
resto como lo haría para un módulo de script. Esto incluye el uso de un script de
compilación para compilar todo en una carpeta Output . La estructura de carpetas tiene
este aspecto:

MyModule
├───src
├───Output
│ └───MyModule
├───MyModule
│ ├───Data
│ ├───Private
│ └───Public
└───Tests

Introducción
En primer lugar, es necesario crear la carpeta y el repositorio de Git. Utilizo $module
como marcador de posición para el nombre del módulo. Esto debería facilitarle la
reutilización de estos ejemplos si es necesario.
PowerShell

$module = 'MyModule'
New-Item -Path $module -Type Directory
Set-Location $module
git init

A continuación, cree las carpetas de nivel de raíz.

PowerShell

New-Item -Path 'src' -Type Directory


New-Item -Path 'Output' -Type Directory
New-Item -Path 'Tests' -Type Directory
New-Item -Path $module -Type Directory

Configuración del módulo binario


Este artículo se centra en el módulo binario, de modo que ahí es donde empezaremos.
En esta sección se extraen ejemplos de la guía sobre cómo Creación de un módulo
binario multiplataforma . Revise dicha guía si necesita más detalles o tiene alguna
incidencia.

Lo primero que queremos hacer es comprobar la versión del SDK principal de dotnet
que hemos instalado. Utilizo 2.1.4, pero debe tener 2.0.0 o una versión más reciente
antes de continuar.

PowerShell

PS> dotnet --version


2.1.4

Trabajo fuera de la carpeta src para esta sección.

PowerShell

Set-Location 'src'

Con el comando dotnet, cree una nueva biblioteca de clases.

PowerShell

dotnet new classlib --name $module


Esto creó el proyecto de biblioteca en una subcarpeta, pero no deseo ese nivel de
anidamiento adicional. Voy a subir esos archivos un nivel.

PowerShell

Move-Item -Path .\$module\* -Destination .\


Remove-Item $module -Recurse

Establezca la versión del SDK de .NET Core para el proyecto. Tengo el SDK 2.1, de modo
que voy a especificar 2.1.0 . Use 2.0.0 si usa el SDK 2.0.

PowerShell

dotnet new globaljson --sdk-version 2.1.0

Agregue el paquete NuGet de la biblioteca de PowerShell estándar al proyecto.


Asegúrese de usar la versión más reciente disponible para el nivel de compatibilidad
que necesite. Usaría la versión más reciente como valor predeterminado, pero no creo
que este módulo aproveche ninguna característica que sea más reciente que PowerShell
3.0.

PowerShell

dotnet add package PowerShellStandard.Library --version 7.0.0-preview.1

Debemos tener una carpeta src similar a la siguiente:

PowerShell

PS> Get-ChildItem
Directory: \MyModule\src

Mode LastWriteTime Length Name


---- ------------- ------ ----
d----- 7/14/2018 9:51 PM obj
-a---- 7/14/2018 9:51 PM 86 Class1.cs
-a---- 7/14/2018 10:03 PM 259 MyModule.csproj
-a---- 7/14/2018 10:05 PM 45 global.json

Ahora estamos listos para agregar nuestro propio código al proyecto.

Compilación de un cmdlet binario


Debemos actualizar src\Class1.cs para que contenga este cmdlet de inicio:
C#

using System;
using System.Management.Automation;

namespace MyModule
{
[Cmdlet( VerbsDiagnostic.Resolve , "MyCmdlet")]
public class ResolveMyCmdletCommand : PSCmdlet
{
[Parameter(Position=0)]
public Object InputObject { get; set; }

protected override void EndProcessing()


{
this.WriteObject(this.InputObject);
base.EndProcessing();
}
}
}

Cambie el nombre del archivo para que coincida con el nombre de clase.

PowerShell

Rename-Item .\Class1.cs .\ResolveMyCmdletCommand.cs

A continuación, podemos compilar nuestro módulo.

PowerShell

PS> dotnet build

Microsoft (R) Build Engine version 15.5.180.51428 for .NET Core


Copyright (C) Microsoft Corporation. All rights reserved.

Restore completed in 18.19 ms for C:\workspace\MyModule\src\MyModule.csproj.


MyModule -> C:\workspace\MyModule\src\bin\Debug\netstandard2.0\MyModule.dll

Build succeeded.
0 Warning(s)
0 Error(s)

Time Elapsed 00:00:02.19

Podemos llamar a Import-Module en el nuevo archivo dll para cargar nuestro nuevo
cmdlet.

PowerShell
PS> Import-Module .\bin\Debug\netstandard2.0\$module.dll
PS> Get-Command -Module $module

CommandType Name Version Source


----------- ---- ------- ------
Cmdlet Resolve-MyCmdlet 1.0.0.0 MyModule

Si no se puede realizar la importación en el sistema, intente actualizar .NET a 4.7.1 o una


versión más reciente. En la guía sobre cómo Creación de un módulo binario
multiplataforma se tratan con mayor detalle la compatibilidad con .NET y versiones
anteriores.

Manifiesto de módulo
Es genial que podamos importar el archivo dll y tener un módulo de trabajo. Me gusta
continuar trabajando con él y crear un manifiesto de módulo. Necesitamos el manifiesto
si queremos publicar en PSGallery más adelante.

En la raíz de nuestro proyecto, podemos ejecutar este comando para crear el manifiesto
de módulo que necesitamos.

PowerShell

$manifestSplat = @{
Path = ".\$module\$module.psd1"
Author = 'Kevin Marquette'
NestedModules = @('bin\MyModule.dll')
RootModule = "$module.psm1"
FunctionsToExport = @('Resolve-MyCmdlet')
}
New-ModuleManifest @manifestSplat

También voy a crear un módulo raíz vacío para futuras funciones de PowerShell.

PowerShell

Set-Content -Value '' -Path ".\$module\$module.psm1"

Esto me permite mezclar cmdlets binarios y funciones de PowerShell normales en el


mismo proyecto.

Compilación del módulo completo


Compilo todo junto en una carpeta de salida. Para ello debemos crear un script de
compilación. Normalmente lo agregaría a un script Invoke-Build , pero podemos
hacerlo de forma sencilla en este ejemplo. Agréguelo a un archivo build.ps1 en la raíz
del proyecto.

PowerShell

$module = 'MyModule'
Push-Location $PSScriptRoot

dotnet build $PSScriptRoot\src -o $PSScriptRoot\output\$module\bin


Copy-Item "$PSScriptRoot\$module\*" "$PSScriptRoot\output\$module" -Recurse
-Force

Import-Module "$PSScriptRoot\Output\$module\$module.psd1"
Invoke-Pester "$PSScriptRoot\Tests"

Estos comandos compilan nuestro archivo DLL y lo colocan en nuestra carpeta


output\$module\bin . A continuación, copia los otros archivos del módulo en su lugar.

Output
└───MyModule
├───MyModule.psd1
├───MyModule.psm1
└───bin
├───MyModule.deps.json
├───MyModule.dll
└───MyModule.pdb

En este momento, podemos importar nuestro módulo con el archivo psd1.

PowerShell

Import-Module ".\Output\$module\$module.psd1"

Desde aquí, podemos colocar la carpeta .\Output\$module en nuestro directorio


$env:PSModulePath y carga automáticamente nuestro comando siempre que lo

necesitamos.

Actualización: nuevo PSModule de dotnet


He aprendido que la herramienta dotnet tiene una plantilla PSModule .
Todos los pasos que he descrito anteriormente siguen siendo válidos, pero en esta
plantilla se suprimen muchos de ellos. Sigue siendo una plantilla bastante nueva a la
que aún se aplican mejoras. Espere que siga mejorando a partir de ahora.

Así es como usa la instalación y la plantilla PSModule.

PowerShell

dotnet new -i Microsoft.PowerShell.Standard.Module.Template


dotnet new psmodule
dotnet build
Import-Module "bin\Debug\netstandard2.0\$module.dll"
Get-Module $module

Esta plantilla mínimamente viable se encarga de agregar el SDK de .NET, la biblioteca de


PowerShell estándar y crea una clase de ejemplo en el proyecto. Puede compilarla y
ejecutarla inmediatamente.

Detalles importantes
Antes de finalizar este artículo, estos son algunos otros detalles que merece la pena
mencionar.

Descarga de archivos DLL


Una vez que se carga un módulo binario, no puede descargarlo realmente. El archivo
DLL se bloquea hasta que lo descarga. Esto puede resultar molesto durante el
desarrollo, ya que cada vez que realiza un cambio y quiere compilarlo, el archivo suele
bloquearse. La única forma fiable de resolver esto es cerrar la sesión de PowerShell que
cargó el archivo DLL.

Acción Recargar ventana de VS Code


Realizo la mayoría de mi trabajo de desarrollo de PowerShell en Código de VS . Al
trabajar en un módulo binario (o un módulo con clases), he adquirido el hábito de
recargar VS Code cada vez que realizo la compilación. Ctrl + Mayús + P extrae la
ventana de comandos y Reload Window siempre se encuentra al principio de mi lista.

Sesiones de PowerShell anidadas


Otra opción es tener buena cobertura de prueba de Pester. Después, puede ajustar el
script build.ps1 para iniciar una nueva sesión de PowerShell, realizar la compilación,
ejecutar las pruebas y cerrar la sesión.

Actualización de los módulos instalados


Este bloqueo puede resultar molesto al intentar actualizar el módulo instalado
localmente. Si alguna sesión lo ha cargado, debe localizarlo y cerrarlo. Esto deja de ser
un problema al instalar desde PSGallery porque el control de versiones del módulo
incluye el nuevo en otra carpeta.

Puede configurar una PSGallery local y publicarlo ahí como parte de su compilación. A
continuación, realice la instalación local desde esa PSGallery. Esto suena como una gran
cantidad de trabajo, pero puede ser tan sencillo como iniciar un contenedor de Docker.
Explico una forma de hacerlo en mi publicación en el artículo sobre cómo Uso de un
servidor NuGet para un repositorio PSRepository .

Consideraciones finales
No hablé sobre la sintaxis de C# para crear un cmdlet, pero hay mucha documentación
al respecto en el SDK de Windows PowerShell. Definitivamente es algo con lo que
merece la pena experimentar como trampolín hacia C# más serio.
Elección del paquete NuGet de
PowerShell adecuado para un proyecto
de .NET
Artículo • 13/04/2023

Junto con los paquetes pwsh ejecutables publicados con cada versión de PowerShell, el
equipo de PowerShell también mantiene varios paquetes disponibles en NuGet . Estos
paquetes permiten que PowerShell se establezca como destino como una plataforma de
API en .NET.

Como aplicación de .NET que proporciona API y espera cargar las bibliotecas de .NET
que implementan sus propios módulos binarios, es fundamental que PowerShell esté
disponible en forma de paquete NuGet.

Actualmente hay varios paquetes NuGet que proporcionan alguna representación del
área expuesta de la API de PowerShell. No siempre se ha determinado con claridad qué
paquete usar con un proyecto en concreto. En este artículo se arroja luz sobre algunos
escenarios comunes para los proyectos de .NET que tienen como destino PowerShell y
sobre cómo elegir el paquete NuGet adecuado que establecer como destino para el
proyecto .NET orientado a PowerShell.

Hospedaje frente a referencia


Algunos proyectos de .NET buscan escribir código para que se cargue en un entorno de
ejecución de PowerShell ya existente (como pwsh , powershell.exe , la consola integrada
de PowerShell o el ISE), mientras que otros quieren ejecutar PowerShell en sus propias
aplicaciones.

Las referencias son para cuando un proyecto, normalmente un módulo, está


diseñado a fin de cargarse en PowerShell. Se debe compilar en las API que
proporciona PowerShell para interactuar con este, pero la implementación de
PowerShell la proporciona el proceso de PowerShell que se carga en él. Para las
referencias, un proyecto puede usar ensamblados de referencia o ensamblados de
entorno de ejecución reales como un destino de compilación, pero es necesario
asegurarse de no publicar ninguno de estos con su compilación.
El hospedaje es cuando un proyecto necesita su propia implementación de
PowerShell, normalmente porque es una aplicación independiente que necesita
ejecutar PowerShell. En este caso, no se pueden utilizar ensamblados de referencia
puros. En su lugar, conviene depender de una implementación concreta de
PowerShell. Dado que se debe usar una implementación concreta de PowerShell,
es necesario elegir una versión específica de PowerShell para el hospedaje; una
única aplicación host no puede tener como destino varias versiones de PowerShell.

Publicación de proyectos que tienen como destino


PowerShell como referencia

7 Nota

En este artículo usamos el término publicación para hacer referencia a la ejecución


de dotnet publish , que coloca una biblioteca de .NET en un directorio con todas
sus dependencias, a punto para su implementación en un entorno de ejecución
determinado.

Para evitar la publicación de dependencias del proyecto que se estén usando como
destinos de referencia de compilación, se recomienda establecer el atributo
PrivateAssets:

XML

<PackageReference Include="PowerShellStandard.Library" Version="5.1.0.0"


PrivateAssets="all" />

Si olvida hacerlo y usa un ensamblado de referencia como destino, es posible que


observe incidencias relacionadas con el uso de la implementación predeterminada del
ensamblado de referencia en lugar de la implementación real. Esto puede adoptar la
forma de un elemento NullReferenceException , ya que los ensamblados de referencia
suelen simular la API de implementación simplemente devolviendo null .

Tipos de claves de proyectos de .NET con


destino en PowerShell
Aunque cualquier biblioteca o aplicación de .NET puede insertar PowerShell, hay
algunos escenarios comunes en los que se usan las API de PowerShell:

Implementación de un módulo binario de PowerShell

Los módulos binarios de PowerShell son bibliotecas de .NET que PowerShell carga
y que deben implementar las API de PowerShell, como los tipos PSCmdlet o
CmdletProvider, para exponer los cmdlets o proveedores, respectivamente. Puesto
que se cargan, los módulos buscan realizar la compilación en las referencias a
PowerShell sin publicarlo en su compilación. También es habitual que los módulos
quieran admitir varias plataformas y versiones de PowerShell, idealmente con una
sobrecarga de espacio en disco, complejidad o implementación repetida mínimas.
Para obtener más información sobre los módulos, vea about_Modules.

Implementación de un host de PowerShell

Un host de PowerShell proporciona una capa de interacción para el entorno de


ejecución de PowerShell. Es una forma específica de hospedaje, donde un elemento
PSHost se implementa como una interfaz de usuario nueva en PowerShell. Por
ejemplo, ConsoleHost de PowerShell proporciona una interfaz de usuario de
terminal para los ejecutables de PowerShell, mientras que el host de servicios del
editor de PowerShell y el host de ISE proporcionan una interfaz gráfica de usuario
parcialmente integrada en el editor en torno a PowerShell. Aunque es posible
cargar un host en un proceso de PowerShell existente, es mucho más habitual que
una implementación de host actúe como una implementación de PowerShell
independiente que redistribuye el motor de PowerShell.

Llamada a PowerShell desde otra aplicación .NET

Al igual que con cualquier aplicación, se puede llamar a PowerShell como un


subproceso para ejecutar cargas de trabajo. Sin embargo, como aplicación de
.NET, también es posible invocar PowerShell en el proceso con el fin de obtener
objetos .NET completos para su uso en la aplicación que realiza la llamada. Se trata
de una forma más general de hospedaje, donde la aplicación mantiene su propia
implementación de PowerShell para uso interno. Ejemplos de ello podrían ser un
servicio o un demonio que ejecuten PowerShell para administrar el estado de la
máquina, o una aplicación web que ejecute PowerShell a petición para hacer tareas
como, por ejemplo, administrar implementaciones en la nube.

Pruebas unitarias de módulos de PowerShell desde .NET

Aunque los módulos y otras bibliotecas diseñadas para exponer la función en


PowerShell deben probarse principalmente desde PowerShell (se recomienda
Pester ), a veces es necesario realizar pruebas unitarias de las API escritas para un
módulo de PowerShell desde .NET. Esta situación implica que el código del
módulo intenta tener como destino varias versiones de PowerShell, mientras que
las pruebas deben ejecutarlo en implementaciones concretas y específicas.

Resumen de los paquetes NuGet de PowerShell


En este artículo, trataremos los paquetes NuGet siguientes que exponen las API de
PowerShell:

PowerShellStandard.Library es un ensamblado de referencia que permite


compilar un ensamblado único que pueden cargar varios entornos de ejecución de
PowerShell.
Microsoft.PowerShell.SDK es el modo de establecer como destino y volver a
hospedar todo el SDK de PowerShell.
El paquete System.Management.Automation es la implementación principal del
entorno en ejecución y el motor de PowerShell, lo cual puede resultar útil en
implementaciones hospedadas mínimas y en escenarios de destino específicos de
la versión.
Los ensamblados de referencia de Windows PowerShell son la manera de
establecer como destino y volver a hospedar de forma eficaz Windows PowerShell
(versiones 5.1 y anteriores de PowerShell).

7 Nota

El paquete NuGet de PowerShell no es en absoluto un paquete de la biblioteca


de .NET, sino que proporciona la implementación de la herramienta global dotnet
de PowerShell. No debe usarse en ningún proyecto, ya que solo proporciona un
ejecutable.

PowerShellStandard.Library
La biblioteca de PowerShell estándar es un ensamblado de referencia que captura la
intersección de las API de las versiones 7, 6 y 5.1 de PowerShell. Esto proporciona una
superficie de API comprobada en tiempo de compilación para compilar código de .NET,
lo que permite a los proyectos de .NET tener como destino las versiones 7, 6 y 5.1 de
PowerShell sin poner en riesgo la llamada a una API que no esté presente.

PowerShell estándar está diseñado a fin de escribir módulos de PowerShell u otro


código previsto solo para ejecutarse después de cargarlo en un proceso de PowerShell.
Dado que se trata de un ensamblado de referencia, PowerShell estándar no contiene
ninguna implementación, por lo que no proporciona ninguna función para las
aplicaciones independientes.

Uso de PowerShell estándar con diferentes entornos de


ejecución de .NET
PowerShell estándar tiene como destino el entorno de ejecución de destino .NET
Standard 2.0, que es un entorno de ejecución de fachada diseñado para proporcionar
una área expuesta común compartida por .NET Framework y .NET Core. Esto permite
establecer como destino un único entorno de ejecución para generar un ensamblado
único que funcionará con varias versiones de PowerShell. Sin embargo, conlleva las
consecuencias siguientes:

La instancia de PowerShell que carga el módulo o la biblioteca debe ejecutar como


mínimo .NET 4.6.1; .NET 4.6 y .NET 4.5.2 no admiten .NET Standard. Tenga en
cuenta que una versión más reciente de Windows PowerShell no significa una
versión más reciente de .NET Framework; Windows PowerShell 5.1 puede
ejecutarse en .NET 4.5.2.
Para trabajar con una instancia de PowerShell que ejecute .NET Framework 4.7.1 o
una versión inferior, se requiere la implementación NETStandard.Library de
.NET 4.6.1 para proporcionar netstandard.dll y otros ensamblados de correcciones
de compatibilidad (shim) en versiones anteriores de .NET Framework.

PowerShell 6 y versiones posteriores proporcionan sus propios ensamblados de


correcciones de compatibilidad (shim) para el reenvío de tipos de .NET Framework 4.6.1
(y versiones posteriores) a .NET Core. Esto significa que, siempre que un módulo use
solo las API que existen en .NET Core, PowerShell 6 y versiones posteriores podrán
cargarlo y ejecutarlo cuando se haya compilado para .NET Framework 4.6.1 (el destino
del entorno de ejecución de net461 ).

Esto significa que los módulos binarios que usan PowerShell estándar para establecer
como destino varias versiones de PowerShell con un solo archivo .dll publicado tienen
dos opciones:

1. Publicar un ensamblado compilado para el entorno de ejecución de destino de


net461 . Esto implica lo siguiente:

Publicar el proyecto para el entorno de ejecución de net461 .


Realizar la compilación también con el entorno de ejecución de
netstandard2.0 (sin usar su salida de compilación) para asegurarse de que
todas las API usadas también están presentes en .NET Core.

2. Publicar un ensamblado compilado para el entorno de ejecución de destino de


netstandard2.0 . Esto requiere lo siguiente:

Publicar el proyecto para el entorno de ejecución de netstandard2.0 .


Tomar las dependencias de net461 de NETStandard.Library y copiarlas en la
ubicación de publicación del ensamblado del proyecto para que el
ensamblado reenvíe el tipo corregido en .NET Framework.
Para compilar módulos o bibliotecas de PowerShell que tengan como destino versiones
anteriores de .NET Framework, es posible que se prefiera establecer como destino varios
entornos de ejecución de .NET. Esto publicará un ensamblado para cada entorno de
ejecución de destino y el ensamblado correcto tendrá que cargarse en el momento de la
carga del módulo (por ejemplo, con un archivo psm1 pequeño como módulo raíz).

Prueba de proyectos de PowerShell estándar en .NET


En cuanto a la prueba del módulo en los ejecutores de pruebas de .NET como xUnit,
recuerde que las comprobaciones en tiempo de compilación solo pueden llegar hasta
cierto punto. Debe probar el módulo en las plataformas de PowerShell pertinentes.

Para probar las API compiladas con PowerShell estándar en .NET, debe agregar
Microsoft.Powershell.SDK como una dependencia de prueba con .NET Core (con la

versión establecida para que coincida con la versión de PowerShell deseada) y los
ensamblados de referencia de Windows PowerShell adecuados con .NET Framework.

Para obtener más información sobre PowerShell estándar y usarlo a fin de escribir un
módulo binario que funcione en varias versiones de PowerShell, vea esta entrada de
blog . Vea también el repositorio de PowerShell estándar en GitHub.

Microsoft.PowerShell.SDK
Microsoft.PowerShell.SDK es un metapaquete que reúne todos los componentes del

SDK de PowerShell en un único paquete NuGet. Una aplicación de .NET independiente


puede usar Microsoft.PowerShell.SDK para ejecutar una función arbitraria de PowerShell
sin depender de las instalaciones o bibliotecas externas de PowerShell.

7 Nota

El SDK de PowerShell solo hace referencia a todos los paquetes de los


componentes que conforman PowerShell y que se pueden usar para el desarrollo
de .NET con PowerShell.

Una versión de Microsoft.Powershell.SDK determinada contiene la implementación


concreta de la misma versión de la aplicación de PowerShell; la versión 7.0 contiene la
implementación de PowerShell 7.0, y los comandos o scripts que se ejecuten en esta se
comportarán en gran medida como si se ejecutaran en PowerShell 7.0.

La ejecución de comandos de PowerShell desde el SDK es, sobre todo, pero no del todo,
lo mismo que ejecutarlos desde pwsh . Por ejemplo, Start-Job actualmente depende de
que el ejecutable pwsh esté disponible, por lo que no funcionará con
Microsoft.Powershell.SDK de forma predeterminada.

Establecer como destino Microsoft.Powershell.SDK desde una aplicación .NET permite


la integración con todos los ensamblados de implementación de PowerShell, como
System.Management.Automation , Microsoft.PowerShell.Management y otros ensamblados

de módulo.

La publicación de una aplicación que tiene como destino Microsoft.Powershell.SDK


incluirá todos los ensamblados y las dependencias que requiera PowerShell. También
incluirá otros recursos que PowerShell necesita en su compilación, como los manifiestos
de módulo para los módulos de Microsoft.PowerShell.* y el directorio ref que
necesita Add-Type.

Dada la integridad de Microsoft.Powershell.SDK , resulta idóneo para lo siguiente:

Implementación de hosts de PowerShell.


Pruebas xUnit de las bibliotecas que tienen como destino ensamblados de
referencia de PowerShell.
Invocación de PowerShell en curso desde una aplicación .NET.

Microsoft.PowerShell.SDK también se puede usar como un destino de referencia


cuando un proyecto de .NET está diseñado para que PowerShell lo use como un módulo
o lo cargue de otro modo, pero depende de las API que solo están presentes en una
versión concreta de PowerShell. Tenga en cuenta que un ensamblado publicado en una
versión específica de Microsoft.PowerShell.SDK solo se cargará y usará de forma segura
en esa versión de PowerShell. Para tener como destino varias versiones de PowerShell
con API específicas, se necesitan varias compilaciones, habiendo establecido como
destino para cada una de ellas su propia versión de Microsoft.Powershell.SDK .

7 Nota

El SDK de PowerShell solo está disponible para las versiones 6 y posteriores de


PowerShell. Para proporcionar una función equivalente con Windows PowerShell,
use los ensamblados de referencia de Windows PowerShell que se describen a
continuación.

System.Management.Automation
El paquete System.Management.Automation es el corazón del SDK de PowerShell. Existe en
NuGet, principalmente, como un recurso para que Microsoft.Powershell.SDK lo extraiga.
Sin embargo, también se puede usar directamente como un paquete para escenarios de
hospedaje más pequeños y módulos que tengan como destino la versión.

En concreto, el paquete System.Management.Automation puede ser un proveedor


preferido de la función de PowerShell en casos como los siguientes:

Únicamente quiere usar la función del lenguaje de PowerShell (en el espacio de


nombres System.Management.Automation.Language ), como las API del analizador de
PowerShell, AST y AST Visitor (por ejemplo, para el análisis estático de PowerShell).
Únicamente quiere ejecutar comandos específicos desde el módulo
Microsoft.PowerShell.Core y poder ejecutarlos en un estado de sesión creado con
el Factory Method CreateDefault2.

Además, System.Management.Automation es un ensamblado de referencia útil en los


siguientes casos:

Quiere tener como destino las API que solo están presentes en una versión
específica de PowerShell.
No va a depender de los tipos que se produzcan fuera del ensamblado
System.Management.Automation (por ejemplo, los tipos que exporten los cmdlets en

módulos Microsoft.PowerShell.* ).

Ensamblados de referencia de Windows


PowerShell
En las versiones 5.1 y anteriores de PowerShell (Windows PowerShell), no hay ningún
SDK que proporcione una implementación de PowerShell, ya que la implementación de
Windows PowerShell forma parte de Windows.

En su lugar, los ensamblados de referencia de Windows PowerShell proporcionan


destinos de referencia y una manera de volver a hospedar Windows PowerShell,
actuando igual que el SDK de PowerShell para las versiones 6 y posteriores.

En lugar de diferenciarse por versión, los ensamblados de referencia de Windows


PowerShell tienen un paquete diferente para cada versión de Windows PowerShell:

PowerShell 5.1
PowerShell 4
PowerShell 3

Puede encontrar información sobre cómo usar los ensamblados de referencia de


Windows PowerShell en el SDK de Windows PowerShell.
Ejemplos reales con estos paquetes NuGet
Diferentes proyectos de herramientas de PowerShell tienen como destino paquetes
NuGet distintos de PowerShell en función de sus necesidades. Aquí se muestran algunos
ejemplos importantes.

PSReadLine
PSReadLine , el módulo de PowerShell que proporciona gran parte de la amplia
experiencia de la consola de PowerShell, establece como destino PowerShell estándar
como una dependencia en lugar de una versión específica de PowerShell y el entorno de
ejecución net461 de .NET en su archivo csproj .

PowerShell 6 y versiones posteriores proporciona sus propios ensamblados de


correcciones de compatibilidad (shim) que permiten que un archivo .dll que tiene como
destino el entorno de ejecución net461 "solo funcione" cuando se cargue (mediante el
redireccionamiento del enlace al elemento mscorlib.dll de .NET Framework al
ensamblado de .NET Core correspondiente).

Esto simplifica el diseño y la entrega del módulo de PSReadLine de forma significativa,


ya que PowerShell estándar garantiza que las únicas API utilizadas estarán presentes en
PowerShell 5.1, y PowerShell 6 y versiones posteriores, a la vez que permite que el
módulo se envíe solo con un único ensamblado.

El destino de .NET 4.6.1 significa que Windows PowerShell en ejecución en .NET 4.5.2 y
.NET 4.6 no es compatible.

Servicios del editor de PowerShell


Los Servicios del editor de PowerShell (PSES) son el back-end de la extensión de
PowerShell para Visual Studio Code y, en realidad, son una forma del módulo de
PowerShell que se carga mediante un ejecutable de PowerShell y, después, asume ese
proceso para volver a hospedar PowerShell dentro de sí mismo, a la vez que
proporciona las características adaptador de depuración y protocolo de servicio de
lenguaje.

PSES proporciona destinos de implementación concretos para netcoreapp2.1 a fin de


establecer como destino PowerShell 6 y versiones posteriores (dado que el entorno de
ejecución netcoreapp3.1 de PowerShell 7 es compatible con versiones anteriores) y
net461 con el fin de establecer como destino Windows PowerShell 5.1, pero contiene la

mayor parte de su lógica en un segundo ensamblado que tiene como destino


netstandard2.0 y PowerShell estándar. Esto permite extraer las dependencias requeridas

para las plataformas .NET Core y .NET Framework, a la vez que todavía simplifica la
mayor parte del código base detrás de una abstracción uniforme.

Dado que se basa en PowerShell estándar, PSES requiere una implementación del
entorno de ejecución de PowerShell para que se pueda probar correctamente. Para ello,
las pruebas xUnit de PSES se extraen en Microsoft.PowerShell.SDK y
Microsoft.PowerShell.5.ReferenceAssemblies para proporcionar una implementación de
PowerShell en el entorno de prueba.

Al igual que con PSReadLine, PSES no admite .NET 4.6 y versiones anteriores, pero
realiza una comprobación en tiempo de ejecución antes de llamar a cualquiera de las
API que podrían provocar un bloqueo en los entornos de ejecución anteriores de .NET
Framework.

PSScriptAnalyzer
PSScriptAnalyzer , el linter para PowerShell, debe tener como destino los elementos
sintácticos introducidos únicamente en determinadas versiones de PowerShell. Dado
que el reconocimiento de estos elementos sintácticos se logra mediante la
implementación de un elemento AstVisitor2, no es posible usar PowerShell estándar y, a
la vez, implementar métodos de AST Visitor para las sintaxis de PowerShell más
recientes.

En su lugar, PSScriptAnalyzer establece como destino cada versión de PowerShell


como una configuración de compilación y genera un archivo .dll independiente para
cada una de ellas. Esto aumenta el tamaño y la complejidad de la compilación, pero
permite lo siguiente:

Destinatarios de API específicos de la versión.


Función específica de la versión que se va a implementar básicamente sin costo del
entorno de ejecución.
Compatibilidad total para Windows PowerShell directamente con .NET
Framework 4.5.2.

Resumen
En este artículo, hemos enumerado y descrito los paquetes NuGet disponibles para
establecer como destino al implementar un proyecto de .NET que usa PowerShell y los
motivos por los que podría tener que usar uno u otro.

Si ha ido directamente al resumen, estas son algunas recomendaciones generales:


Los módulos de PowerShell deben compilarse con PowerShell estándar si solo
requieren las API comunes en diferentes versiones de PowerShell.
Los hosts y aplicaciones de PowerShell que necesitan ejecutar PowerShell
internamente deben tener como destino el SDK de PowerShell para PowerShell 6 y
versiones posteriores, o los ensamblados de referencia de Windows PowerShell
pertinentes para Windows PowerShell.
Los módulos de PowerShell que necesitan API específicas de la versión deben
tener como destino el SDK de PowerShell o los ensamblados de referencia de
Windows PowerShell para las versiones de PowerShell requeridas, usándolas como
ensamblados de referencia (es decir, sin publicar las dependencias de PowerShell).
Resolución de conflictos con las
dependencias de ensamblado de
módulos de PowerShell
Artículo • 13/04/2023

Al escribir un módulo binario de PowerShell en C#, es normal usar dependencias de


otros paquetes o bibliotecas para proporcionar la funcionalidad. Es recomendable usar
dependencias de otras bibliotecas para reutilizar el código. PowerShell siempre carga los
ensamblados en el mismo contexto. Esto presenta problemas cuando las dependencias
de un módulo entran en conflicto con los archivos DLL ya cargados y puede impedir el
uso de dos módulos que de otro modo no estarían relacionados en la misma sesión de
PowerShell.

Si ha tenido este problema, le habrá aparecido un mensaje de error como el siguiente:

En este artículo, se examinan algunas de las maneras en que se producen conflictos con
las dependencias en PowerShell y las formas de mitigar los problemas derivados de
estos conflictos. A continuación, se exponen algunos trucos que pueden resultarle útiles
para los conflictos con las dependencias que se produzcan en los módulos que usa,
aunque no sea el autor del módulo.

¿Por qué se producen conflictos con las


dependencias?
En .NET, los conflictos con las dependencias se producen cuando dos versiones del
mismo ensamblado se cargan en el mismo contexto de carga de ensamblados. El
significado de este término varía ligeramente en las diferentes plataformas de .NET, lo
que se aborda más adelante en este artículo. Este conflicto es un problema que suele
producirse en cualquier software en el que se usan dependencias con versiones.

Los problemas de conflictos se ven agravados por el hecho de que un proyecto casi
nunca depende de forma deliberada o directa de dos versiones de la misma
dependencia. En su lugar, el proyecto tiene dos o más dependencias, cada una de las
cuales requiere una versión diferente de la misma dependencia.

Por ejemplo, supongamos que su aplicación de .NET, DuckBuilder , incorpora dos


dependencias para ejecutar elementos de su funcionalidad y tiene el siguiente aspecto:

Dado que Contoso.ZipTools y Fabrikam.FileHelpers dependen de versiones diferentes


de Newtonsoft.Json, puede haber un conflicto con las dependencias en función de
cómo se cargue cada una de ellas.

Conflictos con las dependencias de PowerShell


En PowerShell, el problema de los conflictos con las dependencias se magnifica porque
las dependencias propias de PowerShell se cargan en el mismo contexto compartido.
Esto significa que el motor de PowerShell y todos los módulos de PowerShell cargados
no deben tener dependencias en conflicto. Un ejemplo clásico de esto es
Newtonsoft.Json:
En este ejemplo, el módulo FictionalTools depende de la versión 12.0.3 de
Newtonsoft.Json, que es una versión de Newtonsoft.Json más reciente que la 11.0.2
que se incluye en el PowerShell de ejemplo.

7 Nota

Esto es un ejemplo. PowerShell 7.0 se distribuye actualmente con Newtonsoft.Json


12.0.3. Las versiones más recientes de PowerShell tienen versiones más recientes de
Newtonsoft.Json.

Dado que el módulo depende de una versión más reciente del ensamblado, no aceptará
la versión que PowerShell ha cargado. Pero, como PowerShell ya ha cargado una versión
del ensamblado, el módulo no puede cargar su propia versión mediante el mecanismo
de carga convencional.

Conflictos con las dependencias de otro módulo


Otro escenario común en PowerShell se da cuando se carga un módulo que depende de
una versión de un ensamblado y, más adelante, se carga otro que depende de otra
versión de ese ensamblado.

Suele tener el siguiente aspecto:

En este caso, el módulo FictionalTools requiere una versión de


Microsoft.Extensions.Logging más reciente que el módulo FilesystemManager .

Imagine que estos módulos cargan sus dependencias colocando los ensamblados de
estas en el mismo directorio que el ensamblado del módulo raíz. Esto permite que .NET
las cargue implícitamente por nombre. Si ejecutamos PowerShell 7.0 (además de .NET
Core 3.1), podemos cargar y ejecutar FictionalTools y, a continuación, cargar y ejecutar
FilesystemManager sin problemas. Sin embargo, en una nueva sesión, si cargamos y
ejecutamos FilesystemManager y, a continuación, cargamos FictionalTools , obtenemos
un objeto FileLoadException del comando FictionalTools porque requiere una versión
de Microsoft.Extensions.Logging más reciente que la cargada. FictionalTools no
puede cargar la versión necesaria porque ya se ha cargado un ensamblado con el
mismo nombre.
PowerShell y .NET
PowerShell se ejecuta en la plataforma .NET, que es responsable de resolver y cargar
dependencias de ensamblado. Debemos comprender cómo funciona .NET para
comprender los conflictos entre dependencias.

También nos encontraremos con que se ejecutan versiones diferentes de PowerShell en


diferentes implementaciones de .NET. En general, PowerShell 5.1 y las versiones
anteriores se ejecutan en .NET Framework, mientras que PowerShell 6 y las versiones
posteriores se ejecutan en .NET Core. Estas dos implementaciones de .NET cargan y
controlan los ensamblados de manera diferente. Esto significa que la resolución de los
conflictos con las dependencias puede variar en función de cuál sea la plataforma de
.NET subyacente.

Contextos de carga de ensamblados


En .NET, un contexto de carga de ensamblados (ALC) es un espacio de nombres del
entorno de ejecución en el que se cargan los ensamblados. Los nombres de los
ensamblados tienen que ser únicos. Este concepto permite que los ensamblados se
resuelvan de forma única por nombre en cada ALC.

Carga de referencias de ensamblado en .NET


La semántica de la carga de ensamblados depende tanto de la implementación de .NET
(.NET Core frente a .NET Framework) como de la API de .NET que se usa para cargar un
ensamblado determinado. No entraremos en detalles aquí, pero hay vínculos en la
sección Lecturas adicionales en los que se explica de forma minuciosa el funcionamiento
de la carga de ensamblados de .NET en cada implementación de .NET.

En este artículo, se hará referencia a los siguientes mecanismos:

Carga implícita de ensamblados (en la práctica, Assembly.Load(AssemblyName) )


cuando .NET intente cargar implícitamente un ensamblado por nombre desde una
referencia de ensamblado estática en el código de .NET.
Assembly.LoadFrom() , una API de carga orientada a complementos que agrega
controladores para resolver las dependencias del archivo DLL cargado. Es posible
que este método no resuelva las dependencias tal y como queremos.
Assembly.LoadFile() , una API de carga básica diseñada para cargar solo el
ensamblado solicitado; no controla ninguna dependencia.

Diferencias entre .NET Framework y .NET Core


La forma en que estas API funcionan ha cambiado de manera sutil de .NET Core a .NET
Framework, por lo que merece la pena leer la información de los vínculos incluidos. Es
importante destacar que los contextos de carga de ensamblados y otros mecanismos de
resolución de ensamblados han cambiado de .NET Framework a .NET Core.

En concreto, .NET Framework tiene las siguientes características:

La caché global de ensamblados, para la resolución de ensamblados en toda la


máquina.
Dominios de aplicación, que funcionan como espacios aislados en proceso para el
aislamiento de ensamblados, pero también presentan una capa de serialización
con la que lidiar.
Un modelo de contexto de carga de ensamblados limitado, que tiene un conjunto
fijo de contextos de carga de ensamblados, cada uno con su propio
comportamiento:
Contexto de carga predeterminado, en el que los ensamblados se cargan de
forma predeterminada.
Contexto de carga de origen, en el que se cargan los ensamblados de forma
manual en el entorno de ejecución.
Contexto de solo reflexión, en el que se cargan los ensamblados de forma
segura para leer sus metadatos sin tener que ejecutarlos.
A raíz del misterioso vacío que los ensamblados cargados con
Assembly.LoadFile(string path) y Assembly.Load(byte[] asmBytes)
experimentan en

Para obtener más información, consulte Procedimientos recomendados para cargar


ensamblados.

.NET Core, así como en .NET 5 y versiones posteriores, se ha reemplazado esta


complejidad por un modelo más sencillo:

No hay caché global de ensamblados. Las aplicaciones traen todas sus


dependencias. Esto elimina un factor externo para la resolución de las
dependencias en aplicaciones, lo que permite que esta sea más reproducible.
PowerShell, como host del complemento, hace que esto sea ligeramente más
complicado para los módulos. Sus dependencias de $PSHOME se comparten con
todos los módulos.
Solo existe un dominio de aplicación, y no es posible crear más. El concepto
"dominio de aplicación" se mantiene en .NET como estado global del proceso de
.NET.
Se proporciona un nuevo modelo de contexto de carga de ensamblados (ALC)
extensible. La resolución de ensamblados puede estar en el espacio de nombres si
se coloca en un nuevo ALC. Los procesos de .NET comienzan con un único ALC
predeterminado en el que se cargan todos los ensamblados (excepto los que se
cargan con Assembly.LoadFile(string) y Assembly.Load(byte[]) ). Pero el proceso
puede crear y definir sus propios ALC personalizados con una lógica de carga
propia. Cuando se carga un ensamblado, el primer ALC en el que se carga es el
responsable de resolver sus dependencias. Esto crea oportunidades para
implementar mecanismos de carga de complementos de .NET eficaces.

En ambas implementaciones, los ensamblados se cargan de forma diferida. Esto significa


que se cargan cuando se ejecuta por primera vez un método que requiere su tipo.

Por ejemplo, a continuación se muestran dos versiones del mismo código que cargarán
una dependencia en momentos diferentes.

La primera cargará siempre su dependencia cuando se llame a Program.GetRange() , ya


que la referencia de la dependencia está presente léxicamente en el método:

C#

using Dependency.Library;

public static class Program


{
public static List<int> GetRange(int limit)
{
var list = new List<int>();
for (int i = 0; i < limit; i++)
{
if (i >= 20)
{
// Dependency.Library will be loaded when GetRange is run
// because the dependency call occurs directly within the
method
DependencyApi.Use();
}

list.Add(i);
}
return list;
}
}

La segunda carga su dependencia solo si el valor del parámetro limit es 20 como


mínimo, ya que realiza un direccionamiento indirecto interno a través de un método:

C#
using Dependency.Library;

public static class Program


{
public static List<int> GetNumbers(int limit)
{
var list = new List<int>();
for (int i = 0; i < limit; i++)
{
if (i >= 20)
{
// Dependency.Library is only referenced within
// the UseDependencyApi() method,
// so will only be loaded when limit >= 20
UseDependencyApi();
}

list.Add(i);
}
return list;
}

private static void UseDependencyApi()


{
// Once UseDependencyApi() is called, Dependency.Library is loaded
DependencyApi.Use();
}
}

Este es un procedimiento adecuado, ya que minimiza la memoria y la E/S del sistema de


archivos y usa los recursos de manera más eficaz. Lamentablemente, el efecto
secundario de esto es que no sabremos que el ensamblado no se puede cargar hasta
que lleguemos a la ruta de acceso al código que intenta cargar el ensamblado.

También puede crear una condición de control de tiempo para los conflictos con la
carga de ensamblados. Si dos partes del mismo programa intentan cargar versiones
diferentes del mismo ensamblado, la versión cargada dependerá de qué ruta de acceso
al código se haya ejecutado en primer lugar.

Para PowerShell, esto significa que los siguientes factores pueden afectar a un conflicto
con la carga de ensamblados:

¿Qué módulo se cargó primero?


¿Se ha ejecutado la ruta de acceso al código que usa la biblioteca de
dependencias?
¿PowerShell carga una dependencia en conflicto en el momento del inicio o solo
en determinadas rutas de acceso al código?
Correcciones rápidas y sus limitaciones
En algunos casos, es posible realizar pequeños ajustes en el módulo y aplicar
correcciones con un esfuerzo mínimo. Sin embargo, para aplicar estas soluciones, hay
que tener en cuenta algunas advertencias. Aunque es posible que puedan aplicarse a su
módulo, no funcionarán para todos.

Cambio de la versión de su dependencia


La manera más sencilla de evitar conflictos con las dependencias es convenir el uso de
una dependencia. Esto es posible en las siguientes situaciones:

El conflicto se produce con una dependencia directa del módulo y usted controla
la versión.
El conflicto se produce con una dependencia indirecta, pero puede configurar las
dependencias directas para que usen una versión de la dependencia indirecta
factible.
Conoce la versión en conflicto y puede confiar en que no cambiará.

El paquete Newtonsoft.Json es un buen ejemplo de este último escenario. Esta es una


dependencia de PowerShell 6 y las versiones posteriores que no se usa en Windows
PowerShell. Es decir, una manera sencilla de resolver los conflictos con el control de
versiones es tener como destino la versión más antigua de Newtonsoft.Json en las
versiones de PowerShell a las que quiera dirigirse.

Por ejemplo, tanto PowerShell 6.2.6 como PowerShell 7.0.2 usan actualmente la
versión 12.0.3 de Newtonsoft.Json. Para crear un módulo destinado a Windows
PowerShell, PowerShell 6 y PowerShell 7, debería tener como destino Newtonsoft.Json
12.0.3 en calidad de dependencia e incluirlo en el módulo creado. Cuando el módulo se
cargue en PowerShell 6 o 7, el propio ensamblado de Newtonsoft.Json de PowerShell
ya estará cargado. Dado que es la versión necesaria para el módulo, la resolución se
realiza correctamente. En Windows PowerShell, el ensamblado aún no está presente en
PowerShell, por lo que se carga desde la carpeta del módulo.

Normalmente, si el destino es un paquete de PowerShell concreto, como


Microsoft.PowerShell.Sdk or System.Management.Automation, NuGet debe poder
resolver las versiones de dependencia correctas necesarias. Definir como destino
Windows PowerShell y PowerShell 6 o versiones posteriores es más difícil, ya que debe
elegir como destino varios marcos de trabajo o PowerShellStandard.Library.

Que el anclaje a una versión de dependencia común no funcione puede deberse a varias
circunstancias, entre las cuales se incluyen las siguientes:
El conflicto se ha producido con una dependencia indirecta y ninguna de las
dependencias puede configurarse para que use una versión común.
Es probable que la versión de la otra dependencia cambie con frecuencia, por lo
que el establecimiento de una versión común es solo una corrección a corto plazo.

Uso de la dependencia fuera del proceso


Esta solución es más conveniente para los usuarios de módulos que para los autores de
módulos. Es una solución a la que podemos recurrir si nos encontramos ante un módulo
que no funciona porque hay un conflicto con las dependencias.

Los conflictos con las dependencias se producen cuando dos versiones del mismo
ensamblado se cargan en el mismo proceso de .NET. Una solución sencilla consiste en
cargarlas en procesos diferentes, siempre y cuando se pueda utilizar la funcionalidad de
ambas a la vez.

En PowerShell, hay varias maneras de conseguir esto:

Invocación de PowerShell como subproceso

Para ejecutar un comando de PowerShell fuera del proceso actual, debe iniciar un
nuevo proceso de PowerShell directamente con la llamada del comando:

PowerShell

pwsh -c 'Invoke-ConflictingCommand'

La limitación principal de este procedimiento es que la reestructuración del


resultado puede ser más complicada o más propensa a errores que otras opciones.

Sistema de trabajo de PowerShell

El sistema de trabajo de PowerShell también ejecuta comandos fuera del proceso


mediante el envío de los comandos a un nuevo proceso de PowerShell y la
devolución de los resultados:

PowerShell

$result = Start-Job { Invoke-ConflictingCommand } | Receive-Job -Wait

En este caso, solo tiene que asegurarse de que las variables y el estado se pasen
correctamente.
El sistema de trabajo también puede ser ligeramente complicado cuando se
ejecuten comandos pequeños.

Comunicación remota con PowerShell

Cuando esté disponible, la comunicación remota de PowerShell puede ser una


forma útil de ejecutar comandos fuera del proceso. Con la comunicación remota,
puede crear un objeto PSSession en un nuevo proceso, llamar a sus comandos a
través de la comunicación remota de PowerShell y, a continuación, usar los
resultados de forma local con los otros módulos que contienen las dependencias
en conflicto.

Este podría ser un ejemplo:

PowerShell

# Create a local PowerShell session


# where the module with conflicting assemblies will be loaded
$s = New-PSSession

# Import the module with the conflicting dependency via remoting,


# exposing the commands locally
Import-Module -PSSession $s -Name ConflictingModule

# Run a command from the module with the conflicting dependencies


Invoke-ConflictingCommand

Comunicación remota implícita con Windows PowerShell

Otra opción en PowerShell 7 es usar la marca -UseWindowsPowerShell en Import-


Module . Así, se importa el módulo a través de una sesión de comunicación remota

local en Windows PowerShell:

PowerShell

Import-Module -Name ConflictingModule -UseWindowsPowerShell

Tenga en cuenta que es posible que los módulos no sean compatibles con
Windows PowerShell o que lo hagan de forma diferente.

Casos en los que no se debe recurrir a la invocación fuera del


proceso
Como autor de un módulo, la invocación de comandos fuera del proceso le resultará
difícil de simular mediante "bake" en un módulo y puede tener casos perimetrales que
causen problemas. En concreto, es posible que la comunicación remota y los trabajos no
estén disponibles en todos los entornos en los que el módulo necesite trabajar. Aun así,
sigue siendo aplicable el principio general de sacar la implementación del proceso y
permitir que el módulo de PowerShell sea un cliente más ligero.

Como usuario de un módulo, la invocación fuera de proceso no le funcionará en los


siguientes casos:

Cuando la comunicación remota de PowerShell no esté disponible porque no tiene


privilegios para usarla o porque no está habilitada.
Cuando se necesite un tipo de .NET determinado de la salida como entrada para
un método u otro comando. Los comandos que se ejecutan a través de la
comunicación remota de PowerShell emiten objetos deserializados en lugar de
objetos de .NET fuertemente tipados. Esto significa que las llamadas de método y
las API fuertemente tipadas no funcionan con la salida de los comandos
importados a través de la comunicación remota.

Soluciones más fiables


Las soluciones anteriores no funcionan con todos los módulos y escenarios. Sin
embargo, tienen la ventaja de ser relativamente sencillas de implementar de forma
correcta. Las siguientes soluciones son más fiables, pero requieren más esfuerzo para
implementarse correctamente y pueden generar errores sutiles si no se escriben de
forma minuciosa.

Carga a través de contextos de carga de ensamblados de


.NET Core
Los contextos de carga de ensamblados (ALC) se incorporaron en .NET Core 1.0 para
abordar específicamente la necesidad de cargar varias versiones del mismo ensamblado
en el mismo entorno de ejecución.

En .NET son la solución más fiable al problema de cargar versiones en conflicto de un


ensamblado. Sin embargo, los ALC personalizados no están disponibles en .NET
Framework. Esto significa que esta solución solo funciona en PowerShell 6 y las
versiones posteriores.

Actualmente, el mejor ejemplo del uso de ALC para el aislamiento de dependencias en


PowerShell está en PowerShell Editor Services, el servidor de lenguaje para la extensión
de PowerShell para Visual Studio Code. Un ALC se usa para evitar que las
dependencias propias de PowerShell Editor Services entren en conflicto con las de los
módulos de PowerShell.

La implementación del aislamiento de las dependencias del módulo con un ALC es difícil
en términos conceptuales, pero vamos a usar un ejemplo simplificado. Imagine que
tenemos un módulo simple que solo está pensado para funcionar en PowerShell 7. El
código fuente se organiza de la siguiente manera:

+ AlcModule.psd1
+ src/
+ TestAlcModuleCommand.cs
+ AlcModule.csproj

La implementación del cmdlet tiene este aspecto:

C#

using Shared.Dependency;

namespace AlcModule
{
[Cmdlet(VerbsDiagnostic.Test, "AlcModule")]
public class TestAlcModuleCommand : Cmdlet
{
protected override void EndProcessing()
{
// Here's where our dependency gets used
Dependency.Use();
// Something trivial to make our cmdlet do *something*
WriteObject("done!");
}
}
}

Este es el manifiesto (muy simplificado):

PowerShell

@{
Author = 'Me'
ModuleVersion = '0.0.1'
RootModule = 'AlcModule.dll'
CmdletsToExport = @('Test-AlcModule')
PowerShellVersion = '7.0'
}
Y el objeto csproj es el siguiente:

XML

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Shared.Dependency" Version="1.0.0" />
<PackageReference Include="Microsoft.PowerShell.Sdk" Version="7.0.1"
PrivateAssets="all" />
</ItemGroup>
</Project>

Al crear este módulo, la salida generada tiene el siguiente diseño:

AlcModule/
+ AlcModule.psd1
+ AlcModule.dll
+ Shared.Dependency.dll

En este ejemplo, el problema se encuentra en el ensamblado Shared.Dependency.dll ,


que es nuestra dependencia imaginaria en conflicto. Esta es la dependencia que
necesitamos colocar en un ALC para poder usar la versión específica del módulo.

Es necesario volver a diseñar el módulo para lograr lo siguiente:

Que las dependencias del módulo solo se carguen en nuestro ALC personalizado y
no en el ALC de PowerShell, por lo que no puede haber ningún conflicto. Además,
no querremos agregar continuamente más código para que la carga siga
funcionando a medida que agreguemos más dependencias a nuestro proyecto. En
su lugar, queremos lógica de resolución de dependencias genérica y reutilizable.
Que la carga del módulo siga funcionando de la forma habitual en PowerShell. Los
cmdlets y otros tipos que el sistema del módulo de PowerShell necesita se definen
en el propio ALC de PowerShell.

Para encontrar una solución que cumpla estos dos requisitos, debemos dividir nuestro
módulo en dos ensamblados:

Un ensamblado de cmdlets, AlcModule.Cmdlets.dll , que contenga definiciones de


todos los tipos que el sistema de módulos de PowerShell necesita para cargar el
módulo correctamente. Es decir, las implementaciones de la clase base Cmdlet y la
clase que implementa IModuleAssemblyInitializer , que configura el controlador
de eventos para que AssemblyLoadContext.Default.Resolving cargue
correctamente AlcModule.Engine.dll a través de nuestro ACL personalizado. Dado
que PowerShell 7 oculta deliberadamente los tipos definidos en los ensamblados
cargados en otros ALC, cualquier tipo que esté destinado a exponerse
públicamente a PowerShell también debe definirse aquí. Por último, nuestro ALC
personalizado debe definirse en este ensamblado. Aparte de eso, debería haber la
menor cantidad de código posible en este ensamblado.
Un ensamblado de motor, AlcModule.Engine.dll , que controle la implementación
real del módulo. Los tipos de este caso están disponibles en el ALC de PowerShell,
pero inicialmente se cargan a través de nuestro ALC personalizado. Sus
dependencias solo se cargarán en el ALC personalizado. De hecho, esto se
convierte en un puente entre los dos ALC.

Con este concepto de puente, nuestra nueva situación de ensamblados tiene el


siguiente aspecto:

Para asegurarnos de que la lógica de sondeo de dependencias predeterminada del ALC


no resuelve las dependencias que se van a cargar en el ALC personalizado, es necesario
separar estas dos partes del módulo en directorios diferentes. El nuevo diseño del
módulo tiene la estructura siguiente:

AlcModule/
AlcModule.Cmdlets.dll
AlcModule.psd1
Dependencies/
| + AlcModule.Engine.dll
| + Shared.Dependency.dll
Para ver cómo cambia la implementación, comenzaremos con la implementación de
AlcModule.Engine.dll :

C#

using Shared.Dependency;

namespace AlcModule.Engine
{
public class AlcEngine
{
public static void Use()
{
Dependency.Use();
}
}
}

Este es un contenedor simple para la dependencia, Shared.Dependency.dll , pero debe


visualizarlo como la API de .NET para su funcionalidad que los cmdlets del otro
ensamblado ajustan para PowerShell.

El cmdlet en AlcModule.Cmdlets.dll tiene el siguiente aspecto:

C#

// Reference our module's Engine implementation here


using AlcModule.Engine;

namespace AlcModule.Cmdlets
{
[Cmdlet(VerbsDiagnostic.Test, "AlcModule")]
public class TestAlcModuleCommand : Cmdlet
{
protected override void EndProcessing()
{
AlcEngine.Use();
WriteObject("done!");
}
}
}

En este momento, si cargáramos AlcModule y ejecutáramos Test-AlcModule ,


obtendríamos un objeto FileNotFoundException cuando el ALC predeterminado
intentara cargar Alc.Engine.dll para ejecutar EndProcessing() . Esto es buena señal, ya
que significa que el ALC predeterminado no encontraría las dependencias que
queremos ocultar.
Ahora debemos agregar código a AlcModule.Cmdlets.dll para que sepa cómo resolver
AlcModule.Engine.dll . En primer lugar, debemos definir el ALC personalizado que
resolverá los ensamblados desde el directorio Dependencies del módulo:

C#

namespace AlcModule.Cmdlets
{
internal class AlcModuleAssemblyLoadContext : AssemblyLoadContext
{
private readonly string _dependencyDirPath;

public AlcModuleAssemblyLoadContext(string dependencyDirPath)


{
_dependencyDirPath = dependencyDirPath;
}

protected override Assembly Load(AssemblyName assemblyName)


{
// We do the simple logic here of looking for an assembly of the
given name
// in the configured dependency directory.
string assemblyPath = Path.Combine(
_dependencyDirPath,
$"{assemblyName.Name}.dll");

if (File.Exists(assemblyPath))
{
// The ALC must use inherited methods to load assemblies.
// Assembly.Load*() won't work here.
return LoadFromAssemblyPath(assemblyPath);
}

// For other assemblies, return null to allow other resolutions


to continue.
return null;
}
}
}

A continuación, es necesario enlazar el ALC personalizado al evento Resolving del ALC


predeterminado, que es la versión del ALC del evento AssemblyResolve en los dominios
de aplicación. Este evento se desencadena para buscar AlcModule.Engine.dll cuando se
llama a EndProcessing() .

C#

namespace AlcModule.Cmdlets
{
public class AlcModuleResolveEventHandler : IModuleAssemblyInitializer,
IModuleAssemblyCleanup
{
// Get the path of the dependency directory.
// In this case we find it relative to the AlcModule.Cmdlets.dll
location
private static readonly string s_dependencyDirPath =
Path.GetFullPath(
Path.Combine(

Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
"Dependencies"));

private static readonly AlcModuleAssemblyLoadContext s_dependencyAlc


=
new AlcModuleAssemblyLoadContext(s_dependencyDirPath);

public void OnImport()


{
// Add the Resolving event handler here
AssemblyLoadContext.Default.Resolving += ResolveAlcEngine;
}

public void OnRemove(PSModuleInfo psModuleInfo)


{
// Remove the Resolving event handler here
AssemblyLoadContext.Default.Resolving -= ResolveAlcEngine;
}

private static Assembly ResolveAlcEngine(AssemblyLoadContext


defaultAlc, AssemblyName assemblyToResolve)
{
// We only want to resolve the Alc.Engine.dll assembly here.
// Because this will be loaded into the custom ALC,
// all of *its* dependencies will be resolved
// by the logic we defined for that ALC's implementation.
//
// Note that we are safe in our assumption that the name is
enough
// to distinguish our assembly here,
// since it's unique to our module.
// There should be no other AlcModule.Engine.dll on the system.
if (!assemblyToResolve.Name.Equals("AlcModule.Engine"))
{
return null;
}

// Allow our ALC to handle the directory discovery concept


//
// This is where Alc.Engine.dll is loaded into our custom ALC
// and then passed through into PowerShell's ALC,
// becoming the bridge between both
return s_dependencyAlc.LoadFromAssemblyName(assemblyToResolve);
}
}
}
Con la nueva implementación, eche un vistazo a la secuencia de llamadas que se
produce cuando se carga el módulo y se ejecuta Test-AlcModule :

Estos son algunos puntos de interés:

El objeto IModuleAssemblyInitializer se ejecuta primero cuando el módulo carga


y establece el evento Resolving .
No cargamos las dependencias hasta la ejecución de Test-AlcModule y la llamada
a su método EndProcessing() .
Cuando se llama a EndProcessing() , el ALC predeterminado no encuentra el objeto
AlcModule.Engine.dll y activa el evento Resolving .

Nuestro controlador de eventos enlaza el ALC personalizado al ALC


predeterminado y solo carga el objeto AlcModule.Engine.dll .
Cuando se llama a AlcEngine.Use() en AlcModule.Engine.dll , vuelve a activarse el
ALC personalizado para resolver Shared.Dependency.dll . En concreto, siempre
carga el objeto Shared.Dependency.dll , ya que nunca entra en conflicto con nada
en el ALC predeterminado y solo busca en el directorio Dependencies .

Al ensamblar la implementación, el diseño de nuestro nuevo código fuente tiene el


siguiente aspecto:

+ AlcModule.psd1
+ src/
+ AlcModule.Cmdlets/
| + AlcModule.Cmdlets.csproj
| + TestAlcModuleCommand.cs
| + AlcModuleAssemblyLoadContext.cs
| + AlcModuleInitializer.cs
|
+ AlcModule.Engine/
| + AlcModule.Engine.csproj
| + AlcEngine.cs

El objeto AlcModule.Cmdlets.csproj tiene este aspecto:

XML

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\AlcModule.Engine\AlcModule.Engine.csproj"
/>
<PackageReference Include="Microsoft.PowerShell.Sdk" Version="7.0.1"
PrivateAssets="all" />
</ItemGroup>
</Project>

El objeto AlcModule.Engine.csproj tiene el siguiente aspecto:

XML

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Shared.Dependency" Version="1.0.0" />
</ItemGroup>
</Project>

Por lo tanto, cuando creemos el módulo, nuestra estrategia será la siguiente:

Crearemos el objeto AlcModule.Engine .


Crearemos el objeto AlcModule.Cmdlets .
Copiaremos todo el contenido de AlcModule.Engine en el directorio Dependencies
y recordaremos lo que hemos copiado.
Copiaremos todos los datos de AlcModule.Cmdlets que no se encontraban en
AlcModule.Engine en el directorio del módulo base.

Dado que, en este caso, el diseño del módulo es muy importante para la separación de
dependencias, a continuación le detallamos un script de compilación para que lo use
desde la raíz de origen:

PowerShell

param(
# The .NET build configuration
[ValidateSet('Debug', 'Release')]
[string]
$Configuration = 'Debug'
)

# Convenient reusable constants


$mod = "AlcModule"
$netcore = "netcoreapp3.1"
$copyExtensions = @('.dll', '.pdb')

# Source code locations


$src = "$PSScriptRoot/src"
$engineSrc = "$src/$mod.Engine"
$cmdletsSrc = "$src/$mod.Cmdlets"

# Generated output locations


$outDir = "$PSScriptRoot/out/$mod"
$outDeps = "$outDir/Dependencies"

# Build AlcModule.Engine
Push-Location $engineSrc
dotnet publish -c $Configuration
Pop-Location

# Build AlcModule.Cmdlets
Push-Location $cmdletsSrc
dotnet publish -c $Configuration
Pop-Location

# Ensure out directory exists and is clean


Remove-Item -Path $outDir -Recurse -ErrorAction Ignore
New-Item -Path $outDir -ItemType Directory
New-Item -Path $outDeps -ItemType Directory

# Copy manifest
Copy-Item -Path "$PSScriptRoot/$mod.psd1"

# Copy each Engine asset and remember it


$deps = [System.Collections.Generic.Hashtable[string]]::new()
Get-ChildItem -Path "$engineSrc/bin/$Configuration/$netcore/publish/" |
Where-Object { $_.Extension -in $copyExtensions } |
ForEach-Object { [void]$deps.Add($_.Name); Copy-Item -Path $_.FullName -
Destination $outDeps }

# Now copy each Cmdlets asset, not taking any found in Engine
Get-ChildItem -Path "$cmdletsSrc/bin/$Configuration/$netcore/publish/" |
Where-Object { -not $deps.Contains($_.Name) -and $_.Extension -in
$copyExtensions } |
ForEach-Object { Copy-Item -Path $_.FullName -Destination $outDir }

Por último, tenemos una manera general de usar un contexto de carga de ensamblados
para aislar las dependencias de nuestro módulo que sigue siendo fiable aunque se
agreguen más dependencias.

Para ver un ejemplo más detallado, vaya a este repositorio de GitHub . En este
ejemplo, se muestra cómo migrar un módulo para utilizar un ALC sin que el módulo
deje de funcionar en .NET Framework. También se muestra cómo usar .NET Standard y
PowerShell Standard para simplificar la implementación principal.

El módulo de Bicep PowerShell también usa esta solución, y la entrada de blog


Resolución de conflictos de módulos de PowerShell es otra buena lectura sobre esta
solución.

Controlador de resolución de ensamblados para la carga


en paralelo
Aunque es sólida, la solución descrita anteriormente requiere que el ensamblado del
módulo no haga referencia directamente a los ensamblados de dependencia, sino que
haga referencia a un ensamblado contenedor que, a continuación, haga referencia a los
ensamblados de dependencia. El ensamblado contenedor actúa como un puente,
reenviando las llamadas desde el ensamblado del módulo a los ensamblados de
dependencia. Por ello, la adopción de esta solución suele suponer una cantidad de
trabajo no trivial:

Para un nuevo módulo, esto agregaría complejidad adicional al diseño y la


implementación.
Para un módulo existente, esto requeriría una refactorización significativa.

Hay una solución simplificada para lograr la carga de ensamblados en paralelo mediante
la conexión de un evento Resolving con una instancia AssemblyLoadContext
personalizada. El uso de este método es más fácil para el autor del módulo, pero tiene
dos limitaciones. Consulte el repositorio PowerShell-ALC-Samples para obtener el
código de ejemplo y la documentación que describe estas limitaciones y escenarios
detallados para esta solución.

) Importante

No use Assembly.LoadFile para el propósito de aislamiento de dependencias. El


uso de Assembly.LoadFile crea un problema de identidad de tipo cuando otro
módulo carga una versión diferente del mismo ensamblado en el
AssemblyLoadContext predeterminado. Aunque esta API carga un ensamblado en
una instancia independiente AssemblyLoadContext , el código de resolución de
tipos de PowerShell detecta los ensamblados cargados. Por lo tanto, podría
haber tipos duplicados con el mismo nombre completo disponible en dos ALC
diferentes.

Dominios de aplicación personalizados


La opción final y más extrema para el aislamiento de ensamblados es usar dominios de
aplicación personalizados. Los dominios de aplicación solo están disponibles en .NET
Framework. Se usan para proporcionar aislamiento en el proceso entre las partes de una
aplicación de .NET. Uno de los usos es aislar las cargas de ensamblados entre sí dentro
del mismo proceso.

Sin embargo, los dominios de aplicación son límites de serialización. Los objetos de un
dominio de aplicación no pueden usar objetos de otro dominio de aplicación ni referirse
a ellos de forma directa. Una solución alternativa a este problema es la implementación
de MarshalByRefObject . Pero, cuando no controla los tipos, como suele ser el caso con
las dependencias, no es posible forzar una implementación aquí. La única solución es
realizar grandes cambios en la arquitectura. El límite de serialización también tiene
implicaciones de rendimiento graves.

Dado que los dominios de aplicación tienen esta limitación importante, son
complicados de implementar y solo funcionan en .NET Framework, no mostraremos
ningún ejemplo de cómo puede usarlos aquí. Si bien vale la pena mencionarlos como
una posibilidad, no se recomiendan.

Si le interesa intentar usar un dominio de aplicación personalizado, puede que le


resulten útiles los siguientes vínculos:

Documentación conceptual sobre dominios de aplicación


Ejemplos de uso de dominios de aplicación

Soluciones para los conflictos con las


dependencias que no funcionan en PowerShell
Finalmente, abordaremos algunas posibilidades que surgen al investigar los conflictos
con las dependencias de .NET en .NET que pueden parecer prometedoras, pero que no
suelen funcionar para PowerShell.
Estas soluciones tienen en común que son cambios en las configuraciones de la
implementación para un entorno en el que puede controlar la aplicación y,
posiblemente, toda la máquina. Estas soluciones están orientadas a escenarios como
servidores web y otras aplicaciones implementadas en entornos de servidor, donde el
entorno está destinado a hospedar la aplicación y permite la configuración por parte del
usuario de la implementación. También tienden a estar muy orientadas a .NET
Framework, lo que significa que no funcionan con PowerShell 6 ni con las versiones
posteriores.

Si sabe que su módulo solo se usa en entornos de Windows PowerShell 5.1 en los que
tiene control total, algunas de estas soluciones pueden ser una opción. Sin embargo, en
general, los módulos no deberían modificar el estado de la máquina global de esta
forma. Esto puede interrumpir las configuraciones y causar problemas en
powershell.exe , otros módulos u otras aplicaciones dependientes y que se produzca un

error en el módulo de manera inesperada.

Redirección de enlaces estáticos con el archivo app.config


para forzar el uso de la misma versión de la dependencia
Las aplicaciones de .NET Framework pueden aprovechar un archivo app.config para
configurar algunos de los comportamientos de la aplicación mediante declaración. Es
posible escribir una entrada de app.config que configure el enlace de ensamblados
para redirigir la carga de ensamblados a una versión determinada.

Esta solución tiene dos problemas para PowerShell:

.NET Core no admite app.config , por lo que esta solución solo se aplica a
powershell.exe .
powershell.exe es una aplicación compartida que reside en el directorio System32 .

Es probable que el módulo no pueda modificar su contenido en muchos sistemas.


Y, aunque pudiera, modificar el archivo app.config podría interrumpir una
configuración existente o afectar a la carga de otros módulos.

Configuración de codebase con app.config


Por las mismas razones, el intento de configurar la opción codebase en app.config no
funcionará en los módulos de PowerShell.

Instalación de dependencias en la caché global de


ensamblados (GAC)
Otra manera de resolver conflictos con las versiones de las dependencia en .NET
Framework es instalar dependencias en la GAC de modo que se puedan cargar
versiones diferentes en paralelo desde esta.

De nuevo, para los módulos de PowerShell, los principales problemas son los siguientes:

La GAC solo se aplica a .NET Framework, por lo que esto no resulta útil en
PowerShell 6 ni en las versiones posteriores.
La instalación de ensamblados en la GAC es una modificación del estado de la
máquina global y puede producir efectos secundarios en otras aplicaciones o en
otros módulos. También puede resultar difícil aplicar esta solución correctamente,
aunque el módulo tenga los privilegios de acceso necesarios. Aplicarla de forma
incorrecta podría provocar problemas graves en toda la máquina en otras
aplicaciones de .NET.

Información adicional
Hay mucho más contenido disponible sobre los conflictos con las dependencias de las
versiones de ensamblados de .NET. A continuación, se muestran algunos puntos de
partida muy interesantes:

.NET: Ensamblados de .NET


.NET Core: Algoritmo de carga de ensamblado administrado
.NET Core: Descripción de System.Runtime.Loader.AssemblyLoadContext
.NET Core: Debate sobre las soluciones de carga de ensamblados en paralelo
.NET Framework: Redirección de versiones de ensamblado
.NET Framework: Procedimientos recomendados para cargar ensamblados
.NET Framework: Procedimiento del entorno de ejecución para localizar
ensamblados
.NET Framework: Resolución de cargas de ensamblado
StackOverflow: Procedimiento de uso y utilidad de la redirección de enlaces de
ensamblados
PowerShell: Debate sobre la implementación de AssemblyLoadContexts
PowerShell: Assembly.LoadFile() no se carga en el objeto AssemblyLoadContext
predeterminado
Rick Strahl: Casos en los que se carga una dependencia de ensamblado de .NET
Jon Skeet: Resumen del control de versiones en .NET
Nate McMaster: Análisis exhaustivo de los tipos primitivos de .NET Core
Creación de un predictor de línea de
comandos
Artículo • 13/07/2023

PSReadLine 2.1.0 introdujo el concepto de predicción de línea de comandos inteligente


mediante la implementación de la característica IntelliSense predictivo. PSReadLine 2.2.2
expandió esa característica agregando un modelo de complemento que le permite crear
sus propios predictores de línea de comandos.

IntelliSense predictivo mejora la finalización con tabulación al proporcionar sugerencias,


en la línea de comandos, a medida que escribe. La sugerencia de predicción aparece
como texto coloreado después del cursor. Esto le permite detectar, editar y ejecutar
comandos completos en función de las predicciones correspondientes del historial de
comandos o los complementos adicionales específicos del dominio.

Requisitos del sistema


Para crear y usar un predictor de complemento, debe usar las siguientes versiones de
software:

PowerShell 7.2 (o superior): proporciona las API necesarias para crear un predictor
de comandos.
PSReadLine 2.2.2 (o superior): permite configurar PSReadLine para usar el
complemento.

Información general de un predictor


Un predictor es un módulo binario de PowerShell. Este objeto debe implementar la
interfaz System.Management.Automation.Subsystem.Prediction.ICommandPredictor . Esta
interfaz declara los métodos usados para consultar los resultados de la predicción y
proporcionar comentarios.

Un módulo de predicción debe registrar un subsistema CommandPredictor con


SubsystemManager de PowerShell cuando se carga y anular el registro cuando se

descarga.

En el siguiente diagrama, se muestra la arquitectura de un predictor en PowerShell.


Creación del código
Para crear un predictor, debe tener instalado el SDK de .NET 6 para la plataforma. Para
más información sobre el SDK, consulte Descarga de .NET 6.0 .

Siga estos pasos para crear un nuevo proyecto de módulo de PowerShell:

1. Use la herramienta de línea de comandos dotnet para crear un proyecto de


biblioteca de clases de inicio.

PowerShell

dotnet new classlib --name SamplePredictor

2. Edite SamplePredictor.csproj para que contenga la información siguiente:

XML

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.PowerShell.SDK"
Version="7.2.0" />
</ItemGroup>

</Project>

3. Elimine el archivo Class1.cs predeterminado creado por dotnet y copie el código


siguiente en un archivo SamplePredictorClass.cs de la carpeta del proyecto.

C#

using System;
using System.Collections.Generic;
using System.Threading;
using System.Management.Automation;
using System.Management.Automation.Subsystem;
using System.Management.Automation.Subsystem.Prediction;

namespace PowerShell.Sample
{
public class SamplePredictor : ICommandPredictor
{
private readonly Guid _guid;

internal SamplePredictor(string guid)


{
_guid = new Guid(guid);
}

/// <summary>
/// Gets the unique identifier for a subsystem implementation.
/// </summary>
public Guid Id => _guid;

/// <summary>
/// Gets the name of a subsystem implementation.
/// </summary>
public string Name => "SamplePredictor";

/// <summary>
/// Gets the description of a subsystem implementation.
/// </summary>
public string Description => "A sample predictor";

/// <summary>
/// Get the predictive suggestions. It indicates the start of a
suggestion rendering session.
/// </summary>
/// <param name="client">Represents the client that initiates
the call.</param>
/// <param name="context">The <see cref="PredictionContext"/>
object to be used for prediction.</param>
/// <param name="cancellationToken">The cancellation token to
cancel the prediction.</param>
/// <returns>An instance of <see cref="SuggestionPackage"/>.
</returns>
public SuggestionPackage GetSuggestion(PredictionClient client,
PredictionContext context, CancellationToken cancellationToken)
{
string input = context.InputAst.Extent.Text;
if (string.IsNullOrWhiteSpace(input))
{
return default;
}

return new SuggestionPackage(new List<PredictiveSuggestion>


{
new PredictiveSuggestion(string.Concat(input, " HELLO
WORLD"))
});
}

#region "interface methods for processing feedback"

/// <summary>
/// Gets a value indicating whether the predictor accepts a
specific kind of feedback.
/// </summary>
/// <param name="client">Represents the client that initiates
the call.</param>
/// <param name="feedback">A specific type of feedback.</param>
/// <returns>True or false, to indicate whether the specific
feedback is accepted.</returns>
public bool CanAcceptFeedback(PredictionClient client,
PredictorFeedbackKind feedback) => false;

/// <summary>
/// One or more suggestions provided by the predictor were
displayed to the user.
/// </summary>
/// <param name="client">Represents the client that initiates
the call.</param>
/// <param name="session">The mini-session where the displayed
suggestions came from.</param>
/// <param name="countOrIndex">
/// When the value is greater than 0, it's the number of
displayed suggestions from the list
/// returned in <paramref name="session"/>, starting from the
index 0. When the value is
/// less than or equal to 0, it means a single suggestion from
the list got displayed, and
/// the index is the absolute value.
/// </param>
public void OnSuggestionDisplayed(PredictionClient client, uint
session, int countOrIndex) { }

/// <summary>
/// The suggestion provided by the predictor was accepted.
/// </summary>
/// <param name="client">Represents the client that initiates
the call.</param>
/// <param name="session">Represents the mini-session where the
accepted suggestion came from.</param>
/// <param name="acceptedSuggestion">The accepted suggestion
text.</param>
public void OnSuggestionAccepted(PredictionClient client, uint
session, string acceptedSuggestion) { }

/// <summary>
/// A command line was accepted to execute.
/// The predictor can start processing early as needed with the
latest history.
/// </summary>
/// <param name="client">Represents the client that initiates
the call.</param>
/// <param name="history">History command lines provided as
references for prediction.</param>
public void OnCommandLineAccepted(PredictionClient client,
IReadOnlyList<string> history) { }

/// <summary>
/// A command line was done execution.
/// </summary>
/// <param name="client">Represents the client that initiates
the call.</param>
/// <param name="commandLine">The last accepted command line.
</param>
/// <param name="success">Shows whether the execution was
successful.</param>
public void OnCommandLineExecuted(PredictionClient client,
string commandLine, bool success) { }

#endregion;
}

/// <summary>
/// Register the predictor on module loading and unregister it on
module un-loading.
/// </summary>
public class Init : IModuleAssemblyInitializer,
IModuleAssemblyCleanup
{
private const string Identifier = "843b51d0-55c8-4c1a-8116-
f0728d419306";

/// <summary>
/// Gets called when assembly is loaded.
/// </summary>
public void OnImport()
{
var predictor = new SamplePredictor(Identifier);

SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor,
predictor);
}
/// <summary>
/// Gets called when the binary module is unloaded.
/// </summary>
public void OnRemove(PSModuleInfo psModuleInfo)
{

SubsystemManager.UnregisterSubsystem(SubsystemKind.CommandPredictor,
new Guid(Identifier));
}
}
}

El código de ejemplo siguiente devuelve la cadena "HELLO WORLD" para el


resultado de la predicción para todas las entradas del usuario. Como el predictor
de ejemplo no procesa ningún comentario, el código no implementa los métodos
de comentarios desde la interfaz. Cambie el código de predicción y comentarios
para satisfacer las necesidades del predictor.

7 Nota

La vista de lista de PSReadLine no admite sugerencias de varias líneas. Cada


sugerencia debe ser una sola línea. Si el código tiene una sugerencia de varias
líneas, debe dividir las líneas en sugerencias independientes o combinar las
líneas con un punto y coma ( ; ).

4. Ejecute dotnet build para generar el ensamblado. Puede encontrar el ensamblado


compilado en la ubicación bin/Debug/net6.0 de la carpeta del proyecto.

7 Nota

Para garantizar una experiencia de usuario dinámica, la interfaz


ICommandPredictor tiene un tiempo de espera de 20 ms para las respuestas
de los predictores. El código del predictor debe devolver resultados en menos
de 20 ms para que se muestren.

Uso del complemento predictor


Para probar el nuevo predictor, abra una nueva sesión de PowerShell 7.2 y ejecute los
siguientes comandos:

PowerShell
Set-PSReadLineOption -PredictionSource HistoryAndPlugin
Import-Module .\bin\Debug\net6.0\SamplePredictor.dll

Con el ensamblado cargado en la sesión, verá que el texto "HELLO WORLD" aparece a
medida que escribe en el terminal. Puede presionar F2 para cambiar entre la vista
Inline y la vista List .

Para más información sobre las opciones de PSReadLine, consulte Set-


PSReadLineOption.

Puede obtener una lista de los predictores instalados con el siguiente comando:

PowerShell

Get-PSSubsystem -Kind CommandPredictor

Output

Kind SubsystemType IsRegistered Implementations


---- ------------- ------------ ---------------
CommandPredictor ICommandPredictor True {SamplePredictor}

7 Nota

Get-PSSubsystem es un cmdlet experimental que se introdujo en PowerShell 7.1.

Debe habilitar la característica experimental PSSubsystemPluginModel para usar este


cmdlet. Para obtener más información, vea Uso de las características
experimentales.
Creación de un proveedor de
comentarios
Artículo • 11/09/2023

PowerShell 7.4-preview.3 introdujo el concepto de proveedores de comentarios. Un


proveedor de comentarios es un módulo de PowerShell que implementa la interfaz
IFeedbackProvider para proporcionar sugerencias de comandos basadas en intentos de

ejecución de comandos de usuario. El proveedor se desencadena cuando se produce


una ejecución correcta o de error. Los proveedores de comentarios usan información del
éxito o error para proporcionar comentarios.

Requisitos previos
Para crear un proveedor de comentarios, debe cumplir los siguientes requisitos previos:

Instalación de PowerShell 7.4-preview.3 o posterior


Debe habilitar la característica experimental PSFeedbackProvider para habilitar la
compatibilidad con proveedores de comentarios y predictores. Para obtener
más información, vea Uso de las características experimentales.
Instalación del SDK de .NET 8: 8.0-preview.3 o posterior
Consulte la página Descargar .NET 8.0 para obtener la versión más reciente
del SDK.

Información general sobre un proveedor de


comentarios
Un proveedor de comentarios es un módulo binario de PowerShell que implementa la
interfaz System.Management.Automation.Subsystem.Feedback.IFeedbackProvider . Esta
interfaz declara los métodos para obtener comentarios en función de la entrada de la
línea de comandos. La interfaz de comentarios puede proporcionar sugerencias basadas
en el éxito o error del comando invocado por el usuario. Las sugerencias pueden ser
cualquier cosa que desee. Por ejemplo, puede sugerir formas de solucionar un error o
mejores prácticas, como evitar el uso de alias. Para obtener más información, vea la
¿Qué son los proveedores de comentarios? entrada de blog.

En el diagrama siguiente se muestra la arquitectura de un proveedor de comentarios:


Los ejemplos siguientes le guiarán por el proceso de creación de un proveedor de
comentarios sencillo. Además, puede registrar el proveedor con la interfaz de predicción
de comandos para agregar sugerencias de comentarios a la experiencia de predicción
de línea de comandos. Para obtener más información sobre los predictores, vea Uso de
predictores en PSReadLine y Cómo crear un predictor de línea de comandos.

Paso 1: Crear un nuevo proyecto de biblioteca


de clases
Use el comando siguiente para crear un nuevo proyecto en el directorio del proyecto:

PowerShell

dotnet new classlib --name MyFeedbackProvider

Agregue una referencia de paquete para el System.Management.Automation paquete al


archivo .csproj . En el ejemplo siguiente se muestra el archivo .csproj actualizado:

XML
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Management.Automation" Version="7.4.0-
preview.3">
<ExcludeAssets>contentFiles</ExcludeAssets>
<PrivateAssets>All</PrivateAssets>
</PackageReference>
</ItemGroup>
</Project>

7 Nota

Debe cambiar la versión del ensamblado de System.Management.Automation para


que coincida con la versión de la versión preliminar de PowerShell que tiene como
destino. La versión mínima es 7.4.0-preview.3.

Paso 2: Agregar la definición de clase para el


proveedor
Cambie el nombre del archivo Class1.cs para que coincida con el nombre del
proveedor. En este ejemplo se usa myFeedbackProvider.cs . Este archivo contiene las dos
clases principales que definen el proveedor de comentarios. En el ejemplo siguiente se
muestra la plantilla básica para las definiciones de clase.

C#

using System.Management.Automation;
using System.Management.Automation.Subsystem;
using System.Management.Automation.Subsystem.Feedback;
using System.Management.Automation.Subsystem.Prediction;
using System.Management.Automation.Language;

namespace myFeedbackProvider;

public sealed class myFeedbackProvider : IFeedbackProvider,


ICommandPredictor
{
}

public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup


{

Paso 3: Implementar la clase Init


La clase Init registra y anula el registro del proveedor de comentarios con el
administrador del subsistema. El OnImport() método se ejecuta cuando se carga el
módulo binario. El método OnRemove() se ejecuta cuando se quita el módulo binario. En
este ejemplo se registran tanto el proveedor de comentarios como el subsistema de
predicción de comandos.

C#

public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup


{
private const string Id = "<ADD YOUR GUID HERE>";

public void OnImport()


{
var feedback = new myFeedbackProvider(Id);
SubsystemManager.RegisterSubsystem(SubsystemKind.FeedbackProvider,
feedback);
SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor,
feedback);
}

public void OnRemove(PSModuleInfo psModuleInfo)


{
SubsystemManager.UnregisterSubsystem<ICommandPredictor>(new
Guid(Id));
SubsystemManager.UnregisterSubsystem<IFeedbackProvider>(new
Guid(Id));
}
}

Reemplace el valor de marcador de posición <ADD YOUR GUID HERE> por un GUID único.
Puede generar un GUID mediante el cmdlet New-Guid .

PowerShell

New-Guid
El GUID es un identificador único para el proveedor. El proveedor debe tener un
identificador único para registrarse en el subsistema.

Paso 4: Agregar miembros de clase y definir el


constructor
El código siguiente implementa las propiedades definidas en las interfaces, agrega
miembros de clase necesarios y crea el constructor para la clase myFeedbackProvider .

C#

/// <summary>
/// Gets the global unique identifier for the subsystem implementation.
/// </summary>
private readonly Guid _guid;
public Guid Id => _guid;

/// <summary>
/// Gets the name of a subsystem implementation, this will be the name
displayed when triggered
/// </summary>
public string Name => "myFeedbackProvider";

/// <summary>
/// Gets the description of a subsystem implementation.
/// </summary>
public string Description => "This is very simple feedback provider";

/// <summary>
/// Default implementation. No function is required for a feedback provider.
/// </summary>
Dictionary<string, string>? ISubsystem.FunctionsToDefine => null;

/// <summary>
/// Gets the types of trigger for this feedback provider.
/// </summary>
/// <remarks>
/// The default implementation triggers a feedback provider by <see
cref="FeedbackTrigger.CommandNotFound"/> only.
/// </remarks>
public FeedbackTrigger Trigger => FeedbackTrigger.All;

/// <summary>
/// List of candidates from the feedback provider to be passed as predictor
results
/// </summary>
private List<string>? _candidates;

/// <summary>
/// PowerShell session used to run PowerShell commands that help create
suggestions.
/// </summary>
private PowerShell _powershell;

internal myFeedbackProvider(string guid)


{
_guid = new Guid(guid); // Save guid
_powershell = PowerShell.Create(); // Create PowerShell instance
}

Paso 5: Creación del método GetFeedback()


El método GetFeedback toma dos parámetros, context y token . El parámetro context
recibe la información sobre el desencadenador para que pueda decidir cómo responder
con sugerencias. El parámetro token se usa para la cancelación. Esta función devuelve
un FeedbackItem que contiene la sugerencia.

C#

/// <summary>
/// Gets feedback based on the given commandline and error record.
/// </summary>
/// <param name="context">The context for the feedback call.</param>
/// <param name="token">The cancellation token to cancel the operation.
</param>
/// <returns>The feedback item.</returns>
public FeedbackItem? GetFeedback(FeedbackContext context, CancellationToken
token)
{
// Target describes the different kinds of triggers to activate on,
var target = context.Trigger;
var commandLine = context.CommandLine;
var ast = context.CommandLineAst;

// defining the header and footer variables


string header;
string footer;

// List of the actions


List<string>? actions = new List<string>();

// Trigger on success code goes here

// Trigger on error code goes here

return null;
}
En la imagen siguiente se muestra cómo se usan estos campos en las sugerencias que
se muestran al usuario.

Creación de sugerencias para un desencadenador


correcto
Para una invocación correcta, queremos expandir los alias usados en la última ejecución.
Con el CommandLineAst , identificamos los comandos con alias y creamos una sugerencia
para usar el nombre de comando completo en su lugar.

C#

// Trigger on success
if (target == FeedbackTrigger.Success)
{
// Getting the commands from the AST and only finding those that are
Commands
var astCmds = ast.FindAll((cAst) => cAst is CommandAst, true);

// Inspect each of the commands


foreach(var command in astCmds)
{

// Get the command name


var aliasedCmd = ((CommandAst) command).GetCommandName();

// Check if its an alias or not, if so then add it to the list of


actions
if(TryGetAlias(aliasedCmd, out string commandString))
{
actions.Add($"{aliasedCmd} --> {commandString}");
}
}

// If no alias was found return null


if(actions.Count == 0)
{
return null;
}

// If aliases are found, set the header to a description and return a


new FeedbackItem.
header = "You have used an aliased command:";
// Copy actions to _candidates for the predictor
_candidates = actions;

return new FeedbackItem(header, actions);


}

Implementación del método TryGetAlias()


El método TryGetAlias() es una función auxiliar privada que devuelve un valor
booleano para indicar si el comando es un alias. En el constructor de clase, creamos una
instancia de PowerShell que podemos usar para ejecutar comandos de PowerShell. El
método TryGetAlias() usa esta instancia de PowerShell para invocar el método
GetCommand para determinar si el comando es un alias. El objeto AliasInfo devuelto por
GetCommand contiene el nombre completo del comando con alias.

C#

/// <summary>
/// Checks if a command is an alias.
/// </summary>
/// <param name="command">The command to check if alias</param>
/// <param name="targetCommand">The referenced command by the aliased
command</param>
/// <returns>True if an alias and false if not</returns>
private bool TryGetAlias(string command, out string targetCommand)
{
// Create PowerShell runspace as a session state proxy to run GetCommand
and check
// if its an alias
AliasInfo? pwshAliasInfo =

_powershell.Runspace.SessionStateProxy.InvokeCommand.GetCommand(command,
CommandTypes.Alias) as AliasInfo;

// if its null then it is not an aliased command so just return false


if(pwshAliasInfo is null)
{
targetCommand = String.Empty;
return false;
}

// Set targetCommand to referenced command name


targetCommand = pwshAliasInfo.ReferencedCommand.Name;
return true;
}
Creación de sugerencias para un desencadenador de
error
Cuando se produce un error en la ejecución de un comando, queremos sugerir que el
usuario Get-Help que obtenga más información sobre cómo usar el comando.

C#

// Trigger on error
if (target == FeedbackTrigger.Error)
{
// Gets the command that caused the error.
var erroredCommand = context.LastError?.InvocationInfo.MyCommand;
if (erroredCommand is null)
{
return null;
}

header = $"You have triggered an error with the command


{erroredCommand}. Try using the following command to get help:";

actions.Add($"Get-Help {erroredCommand}");
footer = $"You can also check online documentation at
https://learn.microsoft.com/en-us/powershell/module/?term={erroredCommand}";

// Copy actions to _candidates for the predictor


_candidates = actions;
return new FeedbackItem(header, actions, footer,
FeedbackDisplayLayout.Portrait);
}

Paso 6: Envío de sugerencias al predictor de la


línea de comandos
Otra manera de que el proveedor de comentarios pueda mejorar la experiencia del
usuario es proporcionar sugerencias de comandos a la interfaz de ICommandPredictor.
Para obtener más información sobre cómo crear un predictor de línea de comandos, vea
Creación de un predictor de línea de comandos.

El código siguiente implementa los métodos necesarios desde la interfaz


ICommandPredictor para agregar el comportamiento de predicción al proveedor de
comentarios.

CanAcceptFeedback() : Este método devuelve un valor booleano que indica si el

predictor acepta un tipo específico de comentarios.


GetSuggestion() : Este método devuelve un objeto SuggestionPackage que

contiene las sugerencias que va a mostrar el predictor.


OnCommandLineAccepted() : Se llama a este método cuando se acepta una línea de

comandos para ejecutarse.

C#

/// <summary>
/// Gets a value indicating whether the predictor accepts a specific kind of
feedback.
/// </summary>
/// <param name="client">Represents the client that initiates the call.
</param>
/// <param name="feedback">A specific type of feedback.</param>
/// <returns>True or false, to indicate whether the specific feedback is
accepted.</returns>
public bool CanAcceptFeedback(PredictionClient client, PredictorFeedbackKind
feedback)
{
return feedback switch
{
PredictorFeedbackKind.CommandLineAccepted => true,
_ => false,
};
}

/// <summary>
/// Get the predictive suggestions. It indicates the start of a suggestion
rendering session.
/// </summary>
/// <param name="client">Represents the client that initiates the call.
</param>
/// <param name="context">The <see cref="PredictionContext"/> object to be
used for prediction.</param>
/// <param name="cancellationToken">The cancellation token to cancel the
prediction.</param>
/// <returns>An instance of <see cref="SuggestionPackage"/>.</returns>
public SuggestionPackage GetSuggestion(
PredictionClient client,
PredictionContext context,
CancellationToken cancellationToken)
{
if (_candidates is not null)
{
string input = context.InputAst.Extent.Text;
List<PredictiveSuggestion>? result = null;

foreach (string c in _candidates)


{
if (c.StartsWith(input, StringComparison.OrdinalIgnoreCase))
{
result ??= new List<PredictiveSuggestion>
(_candidates.Count);
result.Add(new PredictiveSuggestion(c));
}
}

if (result is not null)


{
return new SuggestionPackage(result);
}
}

return default;
}

/// <summary>
/// A command line was accepted to execute.
/// The predictor can start processing early as needed with the latest
history.
/// </summary>
/// <param name="client">Represents the client that initiates the call.
</param>
/// <param name="history">History command lines provided as references for
prediction.</param>
public void OnCommandLineAccepted(PredictionClient client,
IReadOnlyList<string> history)
{
// Reset the candidate state once the command is accepted.
_candidates = null;
}

Paso 7: Compilación del proveedor de


comentarios
Ahora ya está listo para compilar y empezar a usar su proveedor de comentarios. Para
compilar el proyecto, ejecute el siguiente comando:

PowerShell

dotnet build

Este comando crea el módulo de PowerShell como un archivo DLL en la siguiente ruta
de acceso de la carpeta del proyecto: bin/Debug/net8.0/myFeedbackProvider

Es posible que se produzca el error error NU1101: Unable to find package


System.Management.Automation. al compilar en máquinas Windows. Para corregir este

problema, agregue un archivo nuget.config al directorio del proyecto y agregue lo


siguiente:
YAML

<?xml version="1.0" encoding="utf-8"?>


<configuration>
<packageSources>
<clear />
<add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
</packageSources>
<disabledPackageSources>
<clear />
</disabledPackageSources>
</configuration>

Uso de un proveedor de comentarios


Para probar el nuevo proveedor de comentarios, importe el módulo compilado en la
sesión de PowerShell. Para ello, importe la carpeta descrita después de que la
compilación se haya realizado correctamente:

PowerShell

Import-Module ./bin/Debug/net8.0/myFeedbackProvider

Una vez que esté satisfecho con el módulo, debe crear un manifiesto de módulo,
publicarlo en la Galería de PowerShell e instalarlo en el $env:PSModulePath . Para obtener
más información, vea Creación de un manifiesto de módulo. Puede agregar el Import-
Module comando al script de $PROFILE para que el módulo esté disponible en la sesión

de PowerShell.

Puede obtener una lista de proveedores de comentarios instalados mediante el


siguiente comando:

PowerShell

Get-PSSubsystem -Kind FeedbackProvider

Output

Kind SubsystemType IsRegistered Implementations


---- ------------- ------------ ---------------
FeedbackProvider IFeedbackProvider True {general}

7 Nota
Get-PSSubsystem es un cmdlet experimental que se introdujo en PowerShell 7.1.

Debe habilitar la característica experimental PSSubsystemPluginModel para usar este


cmdlet. Para obtener más información, vea Uso de las características
experimentales.

En la captura de pantalla siguiente se muestran algunas sugerencias de ejemplo del


nuevo proveedor.

A continuación se muestra un GIF que muestra cómo funciona la integración de


predicción desde el nuevo proveedor.

Otros proveedores de comentarios


Hemos creado otro proveedor de comentarios que se puede usar como una buena
referencia para obtener ejemplos más profundos.

No se encontró el comando
El command-not-found proveedor de comentarios utiliza la command-not-found
herramienta de utilidad en sistemas Linux para proporcionar sugerencias cuando se
intentan ejecutar comandos nativos, pero faltan. Puede encontrar el código en el
Repositorio de GitHub o puede descargarse automáticamente en la Galería de
PowerShell .

Adaptador de PowerShell
El Microsoft.PowerShell.PowerShellAdapter es un proveedor de comentarios que le
ayuda a convertir las salidas de texto de comandos nativos en objetos de PowerShell.
Detecta "adaptadores" en el sistema y le sugiere que los use al usar el comando nativo.
Puede obtener más información sobre los adaptadores de PowerShell desde entrada de
blog proveedor de comentarios del adaptador de PowerShell . También puede
encontrar el código en el Repositorio de GitHub o puede descargarse
automáticamente en la Galería de PowerShell .

Apéndice: Código de implementación


completo
El código siguiente combina los ejemplos anteriores en la implementación completa de
búsqueda de la clase de proveedor.

C#

using System.Management.Automation;
using System.Management.Automation.Subsystem;
using System.Management.Automation.Subsystem.Feedback;
using System.Management.Automation.Subsystem.Prediction;
using System.Management.Automation.Language;

namespace myFeedbackProvider;

public sealed class myFeedbackProvider : IFeedbackProvider,


ICommandPredictor
{
/// <summary>
/// Gets the global unique identifier for the subsystem implementation.
/// </summary>
private readonly Guid _guid;
public Guid Id => _guid;

/// <summary>
/// Gets the name of a subsystem implementation, this will be the name
displayed when triggered
/// </summary>
public string Name => "myFeedbackProvider";
/// <summary>
/// Gets the description of a subsystem implementation.
/// </summary>
public string Description => "This is very simple feedback provider";

/// <summary>
/// Default implementation. No function is required for a feedback
provider.
/// </summary>
Dictionary<string, string>? ISubsystem.FunctionsToDefine => null;

/// <summary>
/// Gets the types of trigger for this feedback provider.
/// </summary>
/// <remarks>
/// The default implementation triggers a feedback provider by <see
cref="FeedbackTrigger.CommandNotFound"/> only.
/// </remarks>
public FeedbackTrigger Trigger => FeedbackTrigger.All;

/// <summary>
/// List of candidates from the feedback provider to be passed as
predictor results
/// </summary>
private List<string>? _candidates;

/// <summary>
/// PowerShell session used to run PowerShell commands that help create
suggestions.
/// </summary>
private PowerShell _powershell;

// Constructor
internal myFeedbackProvider(string guid)
{
_guid = new Guid(guid); // Save guid
_powershell = PowerShell.Create(); // Create PowerShell instance
}

#region IFeedbackProvider
/// <summary>
/// Gets feedback based on the given commandline and error record.
/// </summary>
/// <param name="context">The context for the feedback call.</param>
/// <param name="token">The cancellation token to cancel the operation.
</param>
/// <returns>The feedback item.</returns>
public FeedbackItem? GetFeedback(FeedbackContext context,
CancellationToken token)
{
// Target describes the different kinds of triggers to activate on,
var target = context.Trigger;
var commandLine = context.CommandLine;
var ast = context.CommandLineAst;
// defining the header and footer variables
string header;
string footer;

// List of the actions


List<string>? actions = new List<string>();

// Trigger on success
if (target == FeedbackTrigger.Success)
{
// Getting the commands from the AST and only finding those that
are Commands
var astCmds = ast.FindAll((cAst) => cAst is CommandAst, true);

// Inspect each of the commands


foreach(var command in astCmds)
{

// Get the command name


var aliasedCmd = ((CommandAst) command).GetCommandName();

// Check if its an alias or not, if so then add it to the


list of actions
if(TryGetAlias(aliasedCmd, out string commandString))
{
actions.Add($"{aliasedCmd} --> {commandString}");
}
}

// If no alias was found return null


if(actions.Count == 0)
{
return null;
}

// If aliases are found, set the header to a description and


return a new FeedbackItem.
header = "You have used an aliased command:";
// Copy actions to _candidates for the predictor
_candidates = actions;

return new FeedbackItem(header, actions);


}

// Trigger on error
if (target == FeedbackTrigger.Error)
{
// Gets the command that caused the error.
var erroredCommand =
context.LastError?.InvocationInfo.MyCommand;
if (erroredCommand is null)
{
return null;
}
header = $"You have triggered an error with the command
{erroredCommand}. Try using the following command to get help:";

actions.Add($"Get-Help {erroredCommand}");
footer = $"You can also check online documentation at
https://learn.microsoft.com/en-us/powershell/module/?term={erroredCommand}";

// Copy actions to _candidates for the predictor


_candidates = actions;
return new FeedbackItem(header, actions, footer,
FeedbackDisplayLayout.Portrait);
}
return null;
}

/// <summary>
/// Checks if a command is an alias.
/// </summary>
/// <param name="command">The command to check if alias</param>
/// <param name="targetCommand">The referenced command by the aliased
command</param>
/// <returns>True if an alias and false if not</returns>
private bool TryGetAlias(string command, out string targetCommand)
{
// Create PowerShell runspace as a session state proxy to run
GetCommand and check
// if its an alias
AliasInfo? pwshAliasInfo =

_powershell.Runspace.SessionStateProxy.InvokeCommand.GetCommand(command,
CommandTypes.Alias) as AliasInfo;

// if its null then it is not an aliased command so just return


false
if(pwshAliasInfo is null)
{
targetCommand = String.Empty;
return false;
}

// Set targetCommand to referenced command name


targetCommand = pwshAliasInfo.ReferencedCommand.Name;
return true;
}
#endregion IFeedbackProvider

#region ICommandPredictor

/// <summary>
/// Gets a value indicating whether the predictor accepts a specific
kind of feedback.
/// </summary>
/// <param name="client">Represents the client that initiates the call.
</param>
/// <param name="feedback">A specific type of feedback.</param>
/// <returns>True or false, to indicate whether the specific feedback is
accepted.</returns>
public bool CanAcceptFeedback(PredictionClient client,
PredictorFeedbackKind feedback)
{
return feedback switch
{
PredictorFeedbackKind.CommandLineAccepted => true,
_ => false,
};
}

/// <summary>
/// Get the predictive suggestions. It indicates the start of a
suggestion rendering session.
/// </summary>
/// <param name="client">Represents the client that initiates the call.
</param>
/// <param name="context">The <see cref="PredictionContext"/> object to
be used for prediction.</param>
/// <param name="cancellationToken">The cancellation token to cancel the
prediction.</param>
/// <returns>An instance of <see cref="SuggestionPackage"/>.</returns>
public SuggestionPackage GetSuggestion(
PredictionClient client,
PredictionContext context,
CancellationToken cancellationToken)
{
if (_candidates is not null)
{
string input = context.InputAst.Extent.Text;
List<PredictiveSuggestion>? result = null;

foreach (string c in _candidates)


{
if (c.StartsWith(input, StringComparison.OrdinalIgnoreCase))
{
result ??= new List<PredictiveSuggestion>
(_candidates.Count);
result.Add(new PredictiveSuggestion(c));
}
}

if (result is not null)


{
return new SuggestionPackage(result);
}
}

return default;
}

/// <summary>
/// A command line was accepted to execute.
/// The predictor can start processing early as needed with the latest
history.
/// </summary>
/// <param name="client">Represents the client that initiates the call.
</param>
/// <param name="history">History command lines provided as references
for prediction.</param>
public void OnCommandLineAccepted(PredictionClient client,
IReadOnlyList<string> history)
{
// Reset the candidate state once the command is accepted.
_candidates = null;
}

#endregion;
}

public class Init : IModuleAssemblyInitializer, IModuleAssemblyCleanup


{
private const string Id = "<ADD YOUR GUID HERE>";

public void OnImport()


{
var feedback = new myFeedbackProvider(Id);
SubsystemManager.RegisterSubsystem(SubsystemKind.FeedbackProvider,
feedback);
SubsystemManager.RegisterSubsystem(SubsystemKind.CommandPredictor,
feedback);
}

public void OnRemove(PSModuleInfo psModuleInfo)


{
SubsystemManager.UnregisterSubsystem<ICommandPredictor>(new
Guid(Id));
SubsystemManager.UnregisterSubsystem<IFeedbackProvider>(new
Guid(Id));
}
}
Creación de ayuda basada en XML
mediante PlatyPS
Artículo • 28/06/2023

Al crear un módulo de PowerShell, siempre se recomienda incluir ayuda detallada para


los cmdlets que cree. Si los cmdlets se implementan en código compilado, debe usar la
ayuda basada en XML. Este formato XML se conoce como lenguaje de marcado de
asistencia de Microsoft (MAML).

La documentación heredada del SDK de PowerShell cubre los detalles de la creación de


ayuda para los cmdlets de PowerShell empaquetados en módulos. Sin embargo,
PowerShell no proporciona ninguna herramienta para crear la ayuda basada en XML. La
documentación del SDK explica la estructura de la ayuda de MAML, pero, en cuanto a la
creación del contenido de MAML, que es complejo y profundamente anidado, solo se
contempla hacerlo a mano.

Aquí es donde puede ser útil el módulo PlatyPS .

¿Qué es PlatyPS?
PlatyPS es una herramienta de código abierto que se inició como un proyecto de
hackathon para facilitar la creación y el mantenimiento de MAML. PlatyPS documenta la
sintaxis de los conjuntos de parámetros y los parámetros individuales para cada cmdlet
del módulo. PlatyPS crea archivos Markdown estructurados que contienen la
información de la sintaxis. No puede crear descripciones ni proporcionar ejemplos.

PlatyPS crea marcadores de posición para que pueda completar descripciones y


ejemplos. Después de agregar la información necesaria, PlatyPS compila los archivos
Markdown en archivos MAML. El sistema de ayuda de PowerShell también admite
archivos de ayuda conceptuales de texto sin formato (temas Acerca de). PlatyPS tiene un
cmdlet para crear una plantilla Markdown estructurada para un nuevo archivo about,
pero estos archivos about_*.help.txt deben mantenerse manualmente.

Puede incluir los archivos de ayuda de texto y MAML con el módulo. También puede
usar PlatyPS para compilar los archivos de ayuda en un paquete CAB que se puede
alojar para obtener ayuda actualizable.

Introducción al uso de PlatyPS


En primer lugar, debe instalar PlatyPS desde la Galería de PowerShell.
PowerShell

Install-Module platyps -Force


Import-Module platyps

En el siguiente diagrama de flujo se describe el proceso para crear o actualizar el


contenido de referencia de PowerShell.

Creación de contenido Markdown para un


módulo de PowerShell
1. Importe el nuevo módulo a la sesión. Repita este paso para cada módulo que
necesite documentar.

Ejecute el siguiente comando para importar los módulos:

PowerShell

Import-Module <your module name>

2. Use PlatyPS para generar archivos Markdown para la página de módulo y todos los
cmdlets asociados en el módulo. Repita este paso para cada módulo que necesite
documentar.
PowerShell

$OutputFolder = <output path>


$parameters = @{
Module = <ModuleName>
OutputFolder = $OutputFolder
AlphabeticParamsOrder = $true
WithModulePage = $true
ExcludeDontShow = $true
Encoding = [System.Text.Encoding]::UTF8
}
New-MarkdownHelp @parameters

New-MarkdownAboutHelp -OutputFolder $OutputFolder -AboutName


"topic_name"

Si la carpeta de salida no existe, New-MarkdownHelp la crea. En este ejemplo, New-


MarkdownHelp crea un archivo Markdown para cada cmdlet del módulo. También

crea la página del módulo en un archivo denominado <ModuleName>.md . Esta página


del módulo contiene una lista de los cmdlets incluidos en el módulo y los
marcadores de posición de la descripción del elemento Synopsis. Los metadatos
de la página de módulo proceden del manifiesto de módulo y se usan en PlatyPS
para crear el archivo XML HelpInfo (como se explica a continuación).

New-MarkdownAboutHelp crea un nuevo archivo about denominado


about_topic_name.md .

Para obtener más información, consulte New-MarkdownHelp y New-


MarkdownAboutHelp.

Actualización del contenido Markdown existente cuando


cambia el módulo
PlatyPS también puede actualizar archivos Markdown existentes para un módulo. Use
este paso para actualizar los módulos que tienen nuevos cmdlets, parámetros nuevos o
parámetros que han cambiado.

1. Importe el nuevo módulo a la sesión. Repita este paso para cada módulo que
necesite documentar.

Ejecute el siguiente comando para importar los módulos:

PowerShell
Import-Module <your module name>

2. Use PlatyPS para actualizar archivos Markdown para la página de aterrizaje del
módulo y todos los cmdlets asociados en el módulo. Repita este paso para cada
módulo que necesite documentar.

PowerShell

$parameters = @{
Path = <folder with Markdown>
RefreshModulePage = $true
AlphabeticParamsOrder = $true
UpdateInputOutput = $true
ExcludeDontShow = $true
LogPath = <path to store log file>
Encoding = [System.Text.Encoding]::UTF8
}
Update-MarkdownHelpModule @parameters

Update-MarkdownHelpModule actualiza el cmdlet y los archivos Markdown del

módulo en la carpeta especificada. No actualiza los about_*.md archivos. El archivo


de módulo ( ModuleName.md ) recibe todo texto nuevo de Synopsis que se ha
agregado a los archivos de cmdlet. En las actualizaciones de los archivos de cmdlet
se incluye el siguiente cambio:

Nuevos conjuntos de parámetros


Parámetros nuevos
Metadatos de parámetros seleccionados
Información actualizada del tipo de entrada y salida

Para obtener más información, vea Update-MarkdownHelpModule.

Edición de los archivos Markdown nuevos o


actualizados
PlatyPS documenta la sintaxis de los conjuntos de parámetros y cada uno de los
parámetros. No puede crear descripciones ni proporcionar ejemplos. Las áreas
específicas en las que se necesita contenido se encuentran entre llaves. Por ejemplo: {{
Fill in the Description }}
Debe agregar un resumen, una descripción del cmdlet, descripciones para cada
parámetro y, al menos, un ejemplo.

Para obtener información detallada sobre la escritura de contenido de PowerShell,


consulte los siguientes artículos:

Guía de estilo de PowerShell


Edición de los artículos de referencia

7 Nota

PlatyPS tiene un esquema específico que se usa para la referencia de cmdlet. Ese
esquema solo permite determinados bloques Markdown en secciones específicas
del documento. Si coloca el contenido en la ubicación incorrecta, se produce un
error en el paso de compilación de PlatyPS. Para obtener más información, consulte
la documentación del esquema en el repositorio de PlatyPS. Para obtener un
ejemplo completo de la referencia de cmdlets bien formada, vea Get-Item.

Después de proporcionar el contenido necesario para cada uno de los cmdlets, debe
actualizar la página de aterrizaje del módulo. Compruebe que el módulo tiene los
valores Module Guid y Download Help Link correctos en los metadatos de YAML del
archivo de <module-name>.md . Agregue los metadatos que faltan.

Además, es posible que observe que en algunos cmdlets puede faltar el elemento
Synopsis (descripción breve). El siguiente comando actualiza la página de aterrizaje del
módulo con el texto de descripción de Synopsis. Abra la página de aterrizaje del
módulo para comprobar las descripciones.

PowerShell

Update-MarkdownHelpModule -Path <full path output folder> -RefreshModulePage

Ahora que ha escrito todo el contenido, puede crear los archivos de ayuda de MAML
que se muestran mediante Get-Help en la consola de PowerShell.

Creación de los archivos de ayuda externos


En este paso se crean los archivos de ayuda de MAML que se muestran mediante Get-
Help en la consola de PowerShell.

Ejecute el siguiente comando para compilar los archivos MAML:

PowerShell

New-ExternalHelp -Path <folder with MDs> -OutputPath <output help folder>

New-ExternalHelp convierte todos los archivos Markdown de cmdlet en uno (o varios)

archivos MAML. Los archivos about se convierten en archivos de texto sin formato con
el formato de nombre about_topic_name.help.txt . El contenido Markdown debe
cumplir el requisito del esquema PlatyPS. New-ExternalHelp se cierra con errores cuando
el contenido no sigue el esquema. Debe modificar los archivos para corregir las
infracciones del esquema.

U Precaución

PlatyPS realiza un trabajo deficiente al convertir los archivos about_*.md en texto


sin formato. Debe usar un Markdown muy simple para obtener resultados
aceptables. Puede que quiera mantener los archivos en el formato
about_topic_name.help.txt con texto sin formato, en lugar de permitir que PlatyPS

los convierta.
Una vez completado este paso, verá los archivos *-help.xml y about_*.help.txt en la
carpeta de salida de destino.

Para obtener más información, vea New-ExternalHelp

Prueba de los archivos de ayuda compilados


Puede comprobar el contenido con el cmdlet Get-HelpPreview:

PowerShell

Get-HelpPreview -Path "<ModuleName>-Help.xml"

El cmdlet lee el archivo MAML compilado y genera el contenido en el mismo formato


que se recibiría de Get-Help . Esto le permite inspeccionar los resultados para
comprobar que los archivos Markdown se compilan correctamente y generar los
resultados deseados. Si encuentra un error, vuelva a editar los archivos Markdown y
vuelva a compilar el MAML.

Ahora está a punto para publicar los archivos de ayuda.

Publicación de la ayuda
Ahora que ha compilado los archivos Markdown en los archivos de ayuda de
PowerShell, está a punto para poner los archivos a disposición de los usuarios. Hay dos
opciones para proporcionar ayuda en la consola de PowerShell.

Empaquetado de los archivos de ayuda con el módulo


Creación de un paquete de ayuda actualizable que los usuarios instalen con el
cmdlet de Update-Help

Empaquetado de ayuda con el módulo


Los archivos de ayuda se pueden empaquetar con el módulo. Consulte Escritura de la
ayuda para los módulos para obtener más información sobre la estructura de carpetas.
Debe incluir la lista de archivos de ayuda en el valor de la clave FileList en el manifiesto
del módulo.

Creación de un paquete de ayuda actualizable


En un nivel alto, los pasos para crear la ayuda actualizable incluyen lo siguiente:
1. Búsqueda de un sitio de Internet para hospedar los archivos de ayuda
2. Adición de una clave de HelpInfoURI al manifiesto del módulo
3. Creación de un archivo HelpInfo XML
4. Creación de archivos CAB
5. Carga de los archivos

Para obtener más información, vea Creación de la Ayuda actualizable: paso a paso.

PlatyPS le ayuda con algunos de estos pasos.

HelpInfoURI es una dirección URL que apunta a la ubicación donde se hospedan los
archivos de ayuda en Internet. Este valor se configura en el manifiesto del módulo.
Update-Help lee el manifiesto del módulo para obtener esta dirección URL y descargar

el contenido de la ayuda actualizable. Esta dirección URL solo debe apuntar a la


ubicación de la carpeta, no a los archivos individuales. Update-Help construye los
nombres de archivo que se van a descargar basándose en otra información del
manifiesto del módulo y del archivo HelpInfo XML.

) Importante

HelpInfoURI debe terminar con un carácter de barra diagonal ( / ). Sin ese carácter,
Update-Help no puede construir las rutas de acceso de archivo correctas para

descargar el contenido. Además, la mayoría de los servicios de archivo basados en


HTTP distinguen mayúsculas de minúsculas. Es importante que los metadatos del
módulo del archivo XML HelpInfo contengan el caso de letra adecuado.

El cmdlet New-ExternalHelp crea el archivo HelpInfo XML en la carpeta de salida. El


archivo HelpInfo XML se crea mediante metadatos de YAML contenidos en los archivos
Markdown del módulo ( ModuleName.md ).

El cmdlet New-ExternalHelpCab crea archivos ZIP y CAB que contienen los archivos
MAML y about_*.help.txt que compiló. Los archivos CAB son compatibles con todas
las versiones de PowerShell. PowerShell 6 y versiones posteriores pueden usar archivos
ZIP.

PowerShell

$helpCabParameters = @{
CabFilesFolder = $MamlOutputFolder
LandingPagePath = $LandingPage
OutputFolder = $CabOutputFolder
}
New-ExternalHelpCab @helpCabParameters

Después de crear los archivos ZIP y CAB, cargue los archivos ZIP, CAB y HelpInfo XML en
su servidor de archivos HTTP. Coloque los archivos en la ubicación indicada por
HelpInfoURI.

Para obtener más información, vea New-ExternalHelpCab.

Otras opciones de publicación


Markdown es un formato versátil que es fácil de transformar a otros formatos para su
publicación. Con una herramienta como Pandoc , puede convertir los archivos
Markdown de ayuda en muchos formatos de documento diferentes, como texto sin
formato, HTML, PDF y formatos de documentos de Office.

Además, los cmdlets ConvertFrom-Markdown y Show-Markdown en PowerShell 6 y


versiones posteriores se pueden usar para convertir Markdown en HTML o para crear
una presentación multicolor en la consola de PowerShell.

Problemas conocidos
PlatyPS es muy sensible al esquema para la estructura de los archivos Markdown que
crea y compila. Es muy fácil escribir Markdown válido que infringe este esquema. Para
obtener más información, consulte la guía de estilo de PowerShell y los artículos de
referencia de edición.

6 Collaborate with us on
PowerShell feedback
GitHub
These PowerShell modules are open
The source for this content can source projects. Select a link to
be found on GitHub, where you provide feedback:
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback
Especificación del lenguaje de Windows
PowerShell, versión 3.0
Artículo • 11/03/2022

La Especificación del lenguaje de Windows PowerShell, versión 3.0 se publicó en


diciembre de 2012 y está basada en PowerShell 3.0. El documento de la especificación
está disponible como un documento de Microsoft Word del Centro de descarga de
Microsoft, en la siguiente página: https://www.microsoft.com/download/details.aspx?
id=36389

Ese documento de Word se ha convertido para una presentación aquí en


docs.microsoft.com. Durante la conversión, se han aplicado una serie de cambios
editoriales para dar cabida al formato de la plataforma de Docs. Se han corregido
algunos errores tipográficos y errores leves.

) Importante

Es posible que el contenido de esta documentación no refleje el estado actual de


PowerShell en su versión actual. No está previsto actualizar esta documentación
para reflejar el estado actual. Esta documentación se presenta como referencia
histórica.

1. Introducción
PowerShell es un shell de línea de comandos y un lenguaje de scripting, diseñado
especialmente para administradores de sistemas.

El funcionamiento de la mayoría de los shells consiste en ejecutar un comando o una


utilidad en un proceso nuevo y, después, presentar al usuario los resultados en forma de
texto. Estos shells también tienen comandos que se integran en el shell y se ejecutan en
el proceso del shell. Dado que hay varios comandos integrados, se han creado muchas
utilidades para complementarlos. PowerShell es muy distinto. En lugar de procesar
texto, el shell procesa objetos. PowerShell también incluye un gran conjunto de
comandos integrados; cada uno tiene una interfaz coherente y pueden funcionar con
comandos escritos por el usuario.

Un objeto es una entidad de datos que tiene propiedades (o sea, características) y


métodos (es decir, acciones que se pueden llevar a cabo en el objeto). Todos los objetos
del mismo tipo tienen el mismo conjunto base de propiedades y métodos, pero cada
instancia de un objeto puede tener distintos valores de propiedad.

Una ventaja importante del uso de objetos es que resulta mucho más fácil canalizar
comandos, es decir, escribir la salida de un comando en otro comando como entrada.
(En un entorno tradicional de línea de comandos, la salida de texto de un comando
debe manipularse para cumplir el formato de entrada de otro comando).

PowerShell incluye un idioma de scripting muy rico que es compatible con


construcciones para bucles, condiciones, controles de flujo y asignación de variables.
Este lenguaje tiene características sintácticas y palabras clave parecidas a las que se usan
en el lenguaje de programación C# (§C.).

Hay cuatro tipos de comandos en PowerShell: scripts; funciones y métodos; cmdlets y


comandos nativos.

Un archivo de comandos se denomina script. Por convención, un script tiene una


extensión de nombre de archivo de .ps1. El nivel superior de un programa de
PowerShell es un script que, a su vez, puede invocar otros comandos.

PowerShell admite la programación modular a través de procedimientos con


nombre. Un procedimiento escrito en PowerShell se denomina función, mientras
que un procedimiento externo que se ha configurado como disponible mediante
el entorno de ejecución (y que normalmente se escribe en algún otro lenguaje) se
denomina método.

Un cmdlet (que se pronuncia "command-let") es una herramienta sencilla de línea


de comandos de una sola tarea. Aunque un cmdlet se puede usar por sí solo, la
capacidad total de los cmdlets se alcanza cuando se usan en combinación para
realizar tareas complejas.

Un comando nativo es un comando que se integra en el entorno del host.

Cada vez que el entorno de ejecución de PowerShell inicia la ejecución, comienza lo que
se denomina una sesión. A continuación, los comandos se ejecutan en el contexto de
esa sesión.

Esta especificación define el lenguaje de PowerShell, los cmdlets integrados y el uso de


objetos a través de la canalización.

A diferencia de la mayoría de los shells, que aceptan y devuelven texto, Windows


PowerShell se basa en .NET Framework Common Language Runtime (CLR) y .NET
Framework, y acepta y devuelve objetos de .NET Framework.
2. Estructura léxica
Artículo • 09/03/2022

2.1 Gramáticas
Esta especificación muestra la sintaxis del lenguaje de PowerShell mediante dos
gramáticas. La gramática léxica (§B.1) muestra cómo se combinan los caracteres Unicode
para formar terminadores de línea, comentarios, espacios en blanco y tokens. La
gramática sintáctica (§B.2) muestra cómo se combinan los tokens resultantes de la
gramática léxica para formar scripts de PowerShell.

Para mayor comodidad, se replican fragmentos de estas gramáticas en los lugares


adecuados a lo largo de esta especificación.

Cualquier uso de los caracteres "a" hasta la "z" en las gramáticas no distingue entre
mayúsculas y minúsculas. Esto significa que se ignora el uso de mayúsculas y minúsculas
en las variables, alias, nombres de función, palabras clave, instrucciones y operadores.
Sin embargo, en esta especificación, estos nombres se escriben en minúsculas, excepto
algunas variables automáticas y de preferencia.

2.2 Análisis léxico

2.2.1 Scripts
Sintaxis:

 Sugerencia

La notación ~opt~ en las definiciones de sintaxis indica que la entidad léxica es


opcional en la sintaxis.

Syntax

input:
input-elements~opt~ signature-block~opt~

input-elements:
input-element
input-elements input-element

input-element:
whitespace
comment
token

signature-block:
signature-begin signature signature-end

signature-begin:
new-line-character # SIG # Begin signature block new-line-character

signature:
base64 encoded signature blob in multiple single-line-comments

signature-end:
new-line-character # SIG # End signature block new-line-character

Descripción:

El flujo de origen de entrada a un traductor de PowerShell es el valor input de un script,


que contiene una secuencia de caracteres Unicode. El procesamiento léxico de esta
secuencia implica la reducción de esos caracteres a una secuencia de tokens, que se
convierten en la entrada del análisis sintáctico.

Un script es un grupo de comandos de PowerShell que se almacena en un archivo de


script. El script en sí no tiene nombre y lo toma del archivo de origen. El final de ese
archivo indica el final del script.

Un script puede contener opcionalmente una firma digital. No se requiere un entorno


host para procesar cualquier texto que siga a una firma ni nada similar a esta. Esta
especificación no cubre la creación ni el uso de firmas digitales.

2.2.2 Terminadores de línea


Sintaxis:

Syntax

new-line-character:
Carriage return character (U+000D)
Line feed character (U+000A)
Carriage return character (U+000D) followed by line feed character
(U+000A)

new-lines:
new-line-character
new-lines new-line-character

Descripción:
La presencia de instancias de new-line-character en la secuencia de origen de entrada la
divide en líneas que se pueden usar para, por ejemplo, la generación de informes de
errores y la detección del final de un comentario de una sola línea.

Un terminador de línea puede tratarse como un espacio en blanco (§2.2.4).

2.2.3 Comentarios
Sintaxis:

Syntax

comment:
single-line-comment
requires-comment
delimited-comment

single-line-comment:
# input-characters~opt~

input-characters:
input-character
input-characters input-character

input-character:
Any Unicode character except a new-line-character

requires-comment:
#requires whitespace command-arguments

dash:
- (U+002D)
EnDash character (U+2013)
EmDash character (U+2014)
Horizontal bar character (U+2015)

dashdash:
dash dash

delimited-comment:
< # delimited-comment-text~opt~ hashes >

delimited-comment-text:
delimited-comment-section
delimited-comment-text delimited-comment-section

delimited-comment-section:
>
hashes~opt~ not-greater-than-or-hash

hashes:
#
hashes #

not-greater-than-or-hash:
Any Unicode character except > or #

Descripción:

Se pueden usar comentarios para realizar anotaciones en el código fuente.

Una instancia de single-line-comment comienza con el carácter # y termina con new-


line-character.

Una instancia de delimited-comment comienza con el par de caracteres <# y termina


con el par de caracteres #> . Puede aparecer como parte de una línea de origen, como
una línea de origen completa o bien abarcar un número cualquiera de líneas de origen.

Un comentario se trata como un espacio en blanco.

Las producciones anteriores implican que:

Los comentarios no se anidan.


Las secuencias de caracteres <# y #> no tienen ningún significado especial en un
comentario de una sola línea.
El carácter # no tiene ningún significado especial en un comentario delimitado.

La gramática léxica implica que no se pueden realizar comentarios dentro de los tokens.

(Vea §A para obtener información sobre cómo crear archivos de script que contengan
comentarios con valores especiales que se usen para generar documentación a partir de
esos archivos).

Un valor requires-comment especifica los criterios que deben cumplirse para que pueda
ejecutarse el script que lo contiene. El criterio principal es la versión de PowerShell que
se usa para ejecutar el script. El requisito de versión mínima se especifica de la manera
siguiente:

#requires -Version N[.n]

Donde N es la versión principal (requerida) y n es la versión secundaria (opcional).

Un elemento requires-comment puede estar presente en cualquier archivo de script; sin


embargo, no puede estar dentro de una función o cmdlet. Debe ser el primer elemento
de una línea de origen. Un script puede contener varias instancias de requires-comment.

Una secuencia de caracteres solo se reconoce como comentario si la secuencia


comienza por # o <# . Por ejemplo, hello#there se considera como un token único,
mientras que hello #there se considera como el token hello seguido de un comentario
de una sola línea. Además del espacio en blanco siguiente, la secuencia de inicio del
comentario también puede ir precedida de cualquier carácter de terminación de una
expresión o de una instrucción (como ) , } , ] , ' , " o ; ).

Un elemento requires-comment no puede estar presente dentro de un complemento.

Una instancia de requires-comment puede aparecer de cuatro formas más:

Syntax

#requires --Assembly AssemblyId


#requires --Module ModuleName
#requires --PsSnapIn PsSnapIn [ -Version *N* [.n] ]
#requires --ShellId ShellId

2.2.4 Espacio en blanco


Sintaxis:

Syntax

whitespace:
Any character with Unicode class Zs, Zl, or Zp
Horizontal tab character (U+0009)
Vertical tab character (U+000B)
Form feed character (U+000C)
` (The backtick character U+0060) followed by new-line-character

Descripción:

El espacio en blanco consta de una secuencia cualquiera de uno o más caracteres de


espacio en blanco.

Salvo por el hecho de que el espacio en blanco pueda actuar como separador de los
tokens, este se ignora.

A diferencia de algunos lenguajes populares, PowerShell no considera que los caracteres


terminadores de línea (§2.2.2) sean espacios en blanco. Sin embargo, un terminador de
línea puede tratarse como espacio en blanco si va precedido inmediatamente por un
carácter de tilde aguda, ` (U+0060). Esto es necesario cuando el contenido de una línea
está completo sintácticamente, pero la línea siguiente contiene tokens destinados a
asociarse a la línea anterior. Por ejemplo,

PowerShell
$number = 10 # assigns 10 to $number; nothing is written to the pipeline
+ 20 # writes 20 to the pipeline
- 50 # writes -50 to the pipeline
$number # writes $number's value, 10, to the pipeline

En este ejemplo, la tilde aguda indica que la línea de origen continúa. La expresión
siguiente es equivalente a $number = 10 + 20 - 50 .

PowerShell

$number = 10 `
+ 20 `
- 50
$number # writes $number's value to the pipeline
-20

2.3 Tokens
Sintaxis:

Syntax

token:
keyword
variable
command
command-parameter
command-argument-token
integer-literal
real-literal
string-literal
type-literal
operator-or-punctuator

Descripción:

Un token es el elemento léxico más pequeño en el lenguaje de PowerShell.

Los tokens se pueden separar por instancias de new-lines, comentarios, espacios en


blanco o cualquier combinación de estos.

2.3.1 Palabras clave


Sintaxis:
Syntax

keyword: one of
begin break catch class
continue data define do
dynamicparam else elseif end
exit filter finally for
foreach from function if
in inlinescript parallel param
process return switch throw
trap try until using
var while workflow

Descripción:

Una palabra clave es una secuencia de caracteres que tiene un significado especial
cuando se usa en un lugar dependiente del contexto. Este suele ser con frecuencia el
primer token de una instrucción; sin embargo, hay otras ubicaciones, como se indica en
la gramática. (Un token que parece una palabra clave, pero que no se usa en un
contexto de palabra clave, es un nombre de comando o un argumento de comando).

Las palabras clave class , define , from , using y var están reservadas para uso futuro.

7 Nota

Nota del editor: las palabras clave class y using se introdujeron en PowerShell 5.0.
Vea about_Classes y about_Using.

2.3.2 Variables
Sintaxis:

Syntax

variable:
$$
$?
$^
$ variable-scope~opt~ variable-characters
@ variable-scope~opt~ variable-characters
braced-variable

braced-variable:
${ variable-scope~opt~ braced-variable-characters }

variable-scope:
global:
local:
private:
script:
using:
workflow:
variable-namespace

variable-namespace:
variable-characters :

variable-characters:
variable-character
variable-characters variable-character

variable-character:
A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nd
_ (The underscore character U+005F)
?

braced-variable-characters:
braced-variable-character
braced-variable-characters braced-variable-character

braced-variable-character:
Any Unicode character except
} (The closing curly brace character U+007D)
` (The backtick character U+0060)
escaped-character

escaped-character:
` (The backtick character U+0060) followed by any Unicode character

Descripción:

Las variables se analizan en detalle en la sección (§5). Las variable $? se analiza en


§2.3.2.2. Los ámbitos se analizan en la sección §3.5.

Las variables $$ y $^ se reservan para su uso en un entorno interactivo, que está fuera
del ámbito de esta especificación.

Hay dos formas de escribir un nombre de variable: como nombre de variable entre
llaves, que comienza por $ , seguido de un conjunto delimitado por llaves de uno o
varios caracteres prácticamente arbitrarios; o bien como nombre de variable ordinario,
que también comienza por $ , seguido de un conjunto de uno o varios caracteres de un
conjunto más restrictivo de lo que permite un nombre de variable entre llaves. Cada
nombre de variable ordinario se puede expresar con un nombre de variable entre llaves
correspondiente.

PowerShell
$totalCost
$Maximum_Count_26

$végösszeg # Hungarian
$итог # Russian
$総計 # Japanese (Kanji)

${Maximum_Count_26}
${Name with`twhite space and `{punctuation`}}
${E:\\File.txt}

No hay límite de longitud para un nombre de variable, todos los caracteres de este son
significativos y no distingue mayúsculas de minúsculas.

Hay varios tipos distintos de variables: definidas por el usuario (§2.3.2.1), automáticas
(§2.3.2.2) y de preferencia (§2.3.2.3). Todas pueden coexistir en el mismo ámbito (§3.5).

Tenga en cuenta la definición de función y las llamadas siguientes:

PowerShell

function Get-Power ([long]$base, [int]$exponent) { ... }

Get-Power 5 3 # $base is 5, $exponent is 3


Get-Power -exponent 3 -base 5 # " " "

Cada argumento se pasa por posición o nombre, de uno en uno. Sin embargo, un
conjunto de argumentos puede pasarse como grupo con expansión a argumentos
individuales que el entorno de ejecución se encarga de controlar. Esta expansión
automática de argumentos se conoce como expansión. Por ejemplo,

PowerShell

$values = 5,3 # put arguments into an array


Get-Power @values

$hash = @{ exponent = 3; base = 5 } # put arguments into a Hashtable


Get-Power @hash

function Get-Power2 { Get-Power @args } # arguments are in an array

Get-Power2 --exponent 3 --base 5 # named arguments splatted named in


@args
Get-Power2 5 3 # position arguments splatted positionally in @args

Se consigue al usar @ en lugar de $ como primer carácter de la variable que se pasa.


Esta notación solo se puede usar en un argumento para un comando.
Los nombres se particionan en varios espacios de nombres, cada uno de los cuales se
almacena en una unidad virtual (§3.1). Por ejemplo, las variables se almacenan en
Variable: , las variables de entorno se almacenan en Env: , las funciones se almacenan

en Function: y los alias en Alias: . Puede accederse a todos estos nombres como
variables mediante la producción variable-namespace en variable-scope. Por ejemplo,

PowerShell

function F { "Hello from F" }


$Function:F # invokes function F

Set-Alias A F
$Alias:A # invokes function F via A

$Count = 10
$Variable:Count # accesses variable Count
$Env:Path # accesses environment variable Path

Cualquier uso de un nombre de variable con un espacio de nombres Variable: explícito


equivale al uso de ese mismo nombre de variable sin esa calificación. Por ejemplo, $v y
$Variable:v son intercambiables.

Además de definirse en el lenguaje, las variables también pueden definirse mediante el


cmdlet New-Variable.

2.3.2.1 Variables definidas por el usuario


Cualquier nombre de variable que la gramática permita, pero que las variables
automáticas o de preferencia no usen, está disponible para las variables definidas por el
usuario.

Las variables definidas por el usuario se crean y administran mediante un script definido
por el usuario.

2.3.2.2 Variables automáticas

Las variables automáticas almacenan información de estado sobre el entorno de


PowerShell. Sus valores pueden leerse en un script escrito por el usuario, pero no
pueden escribirse.

7 Nota
La tabla que se encontraba originalmente en este documento se quitó para reducir
la duplicación. Consulte el tema sobre variables automáticassi quiere ver la lista
completa de variables automáticas.

2.3.2.3 Variables de preferencia


Las variables de preferencia almacenan las preferencias del usuario para la sesión. El
entorno de ejecución de PowerShell las crea y las inicializa. Sus valores se pueden leer y
escribir en un script escrito por el usuario.

7 Nota

La tabla que se encontraba originalmente en este documento se quitó para reducir


la duplicación. Consulte el tema sobre variables de preferenciasi quiere ver la lista
completa de variables de preferencia.

2.3.3 Comandos
Sintaxis:

Syntax

generic-token:
generic-token-parts

generic-token-parts:
generic-token-part
generic-token-parts generic-token-part

generic-token-part:
expandable-string-literal
verbatim-here-string-literal
variable
generic-token-char

generic-token-char:
Any Unicode character except
{ } ( ) ; , | & $
` (The backtick character U+0060)
double-quote-character
single-quote-character
whitespace
new-line-character
escaped-character
generic-token-with-subexpr-start:
generic-token-parts $(

2.3.4 Parámetros
Sintaxis:

Syntax

command-parameter:
dash first-parameter-char parameter-chars colon~opt~

first-parameter-char:
A Unicode character of classes Lu, Ll, Lt, Lm, or Lo
_ (The underscore character U+005F)
?

parameter-chars:
parameter-char
parameter-chars parameter-char

parameter-char:
Any Unicode character except
{ } ( ) ; , \| & . [
colon
whitespace
new-line-character

colon:
: (The colon character U+003A)

verbatim-command-argument-chars:
verbatim-command-argument-part
verbatim-command-argument-chars verbatim-command-argument-part

verbatim-command-argument-part:
verbatim-command-string
& non-ampersand-character
Any Unicode character except
|
new-line-character

non-ampersand-character:
Any Unicode character except &

verbatim-command-string:
double-quote-character non-double-quote-chars
double-quote-character

non-double-quote-chars:
non-double-quote-char
non-double-quote-chars non-double-quote-char
non-double-quote-char:
Any Unicode character except
double-quote-character

Descripción:

Cuando se invoca un comando, se le puede pasar información a través de uno o varios


argumentos a cuyos valores se accede desde el comando, a través de un conjunto de
parámetros correspondientes. El proceso de hacer coincidir parámetros con argumentos
se denomina enlace de parámetros.

Hay tres tipos de argumentos:

Parámetro switch ($8.10.5): tiene el formato command-parameter, donde first-


parameter-char y parameter-chars juntos conforman el nombre del modificador,
que corresponde al nombre de un parámetro (sin - inicial) en el comando que se
invoca. Si los dos puntos finales se omiten, la presencia de este argumento indica
que el parámetro correspondiente se establece en $true . Si los dos puntos finales
están presentes, el argumento inmediatamente a continuación debe designar un
valor de tipo booleano y el parámetro correspondiente se establece en ese valor.
Por ejemplo, las invocaciones siguientes son equivalentes:

PowerShell

Set-MyProcess -Strict
Set-MyProcess -Strict: $true

Parámetro con argumento ($8.10.2): tiene el formato command-parameter, donde


first-parameter-char y parameter-chars juntos conforman el nombre del parámetro,
que corresponde al nombre de un parámetro (sin - inicial) en el comando que se
invoca. No debe haber dos puntos finales. El argumento inmediatamente a
continuación designa un valor asociado. Por ejemplo, dado un comando Get-
Power , con los parámetros $base y $exponent , las invocaciones siguientes son

equivalentes:

PowerShell

Get-Power -base 5 -exponent 3


Get-Power -exponent 3 -base 5

Argumento posicional (§8.10.2): los argumentos y sus parámetros


correspondientes dentro de los comandos tienen posiciones; el primero de ellos
tiene la posición cero. El argumento en la posición 0 se enlaza al parámetro en la
posición 0, el argumento en la posición 1 se enlaza al parámetro en la posición 1 y
así sucesivamente. Por ejemplo, dado un comando Get-Power , con los parámetros
$base y $exponent en las posiciones 0 y 1 respectivamente, el comando se invoca
de la forma siguiente:

PowerShell

Get-Power 5 3

Consulte la sección §8.2 para obtener detalles sobre los parámetros especiales -- y --% .

Cuando se invoca un comando, puede abreviarse un nombre de parámetro; se puede


usar cualquier parte inicial distintiva del nombre completo, siempre que no sea ambigua
respecto a los nombres del resto de parámetros que acepta el mismo comando.

Para obtener información acerca del enlace de parámetros, consulte §8.14.

2.3.5 Literales
Sintaxis:

Syntax

literal:
integer-literal
real-literal
string-literal

2.3.5.1 Literales numéricos

Hay dos tipos de literales numéricos: entero (§2.3.5.1.1) y real (§2.3.5.1.2). Ambos pueden
tener sufijos multiplicadores ($2.3.5.1.3).

2.3.5.1.1 Literales enteros

Sintaxis:

Syntax

integer-literal:
decimal-integer-literal
hexadecimal-integer-literal
decimal-integer-literal:
decimal-digits numeric-type-suffix~opt~ numeric-multiplier~opt~

decimal-digits:
decimal-digit
decimal-digit decimal-digits

decimal-digit: one of
0 1 2 3 4 5 6 7 8 9

numeric-type-suffix:
long-type-suffix
decimal-type-suffix

hexadecimal-integer-literal:
0x hexadecimal-digits long-type-suffix~opt~
numeric-multiplier~opt~

hexadecimal-digits:
hexadecimal-digit
hexadecimal-digit decimal-digits

hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9 a b c d e f

long-type-suffix:
l

numeric-multiplier: one of
kb mb gb tb pb

Descripción:

El tipo de un literal entero viene determinado por su valor, la presencia o ausencia de


long-type-suffix y la presencia de un elemento numeric-multiplier (§2.3.5.1.3).

Para un literal entero sin long-type-suffix

Si su valor puede representarse mediante el tipo int (§4.2.3), ese es su tipo.


En caso contrario, si su valor puede representarse mediante el tipo long (§4.2.3),
ese es su tipo.
En caso contrario, si su valor puede representarse mediante el tipo decimal
(§2.3.5.1.2), ese es su tipo.
En caso contrario, se representa mediante el tipo double (§2.3.5.1.2).

Para un literal entero con long-type-suffix

Si su valor puede representarse mediante el tipo long (§4.2.3), ese es su tipo.


En caso contrario, ese literal tiene un formato incorrecto.
En la representación de dos complementos de valores enteros, hay un valor negativo
más respecto a los positivos. Para el tipo int, ese valor adicional es -2147483648. Para el
tipo long, es -9223372036854775808. Aunque el token 2147483648 se trataría
normalmente como literal de tipo long, si va precedido inmediatamente por el operador
- unario, el operador y el literal se tratan como un literal de tipo int que tiene el valor
más pequeño. Del mismo modo, aunque el token 9223372036854775808 se trataría
normalmente como un literal real de tipo decimal, si va precedido inmediatamente por
el operador - unario, el operador y el literal se tratan como un literal de tipo long que
tiene el valor más pequeño.

Algunos ejemplos de literales enteros son 123 (int), 123L (long) y 200000000000 (long).

No existe un literal entero de tipo byte.

2.3.5.1.2 Literales reales

Sintaxis:

Syntax

real-literal:
decimal-digits . decimal-digits exponent-part~opt~ decimal-type-
suffix~opt~ numeric-multiplier~opt~
. decimal-digits exponent-part~opt~ decimal-type-suffix~opt~ numeric-
multiplier~opt~
decimal-digits exponent-part decimal-type-suffix~opt~ numeric-
multiplier~opt~

exponent-part:
e sign~opt~ decimal-digits

sign: one of
+
dash

decimal-type-suffix:
d
l

numeric-multiplier: one of
kb mb gb tb pb

dash:
- (U+002D)
EnDash character (U+2013)
EmDash character (U+2014)
Horizontal bar character (U+2015)
Descripción:

Un literal real puede contener un elemento numeric-multiplier (§2.3.5.1.3).

Hay dos tipos de literales reales: doble y decimal. Se indican por la ausencia o la
presencia, respectivamente, de decimal-type-suffix. (No existe un literal real flotante).

Un literal real doble tiene el tipo double ($4.2.4.1). Un literal real decimal tiene el tipo
decimal (§4.2.4.2). Los ceros finales en la parte de fracción de un literal real decimal son
significativos.

Si el valor del elemento decimal-digits de exponent-part en un literal real doble es


inferior al mínimo admitido, el valor de ese literal real doble es 0. Si el valor del
elemento decimal-digits de exponent-part en un literal real decimal es inferior al mínimo
admitido, ese literal tiene un formato incorrecto. Si el valor del elemento decimal-digits
de exponent-part en un literal real doble o decimal es superior al máximo admitido, ese
literal tiene un formato incorrecto.

Algunos ejemplos de literales reales dobles son 1,; 1,23; ,45e35; 32,e+12 y 123,456E-231.

Algunos ejemplos de literales reales decimales son 1d (con la escala 0); 1,20d (con la
escala 2); 1,23450e1d (es decir, 12,3450, con la escala 4); 1,2345e3d (es decir, 1234,5, con
la escala 1); 1,2345e-1d (es decir, 0,12345, con la escala 5) y 1,2345e-3d (es decir,
0,0012345, con la escala 7).

7 Nota

Dado que un literal real doble no necesita tener una parte fraccional o una parte
exponente, se requieren los paréntesis de agrupación en (123).M para asegurarse
de que la propiedad o el método M se selecciona para el objeto entero cuyo valor
es 123. Sin esos paréntesis, el literal real tendría un formato incorrecto.

7 Nota

Aunque PowerShell no proporciona literales para los valores infinitos y NaN,


pueden obtenerse equivalentes similares a literales reales dobles de las
propiedades estáticas de solo lectura PositiveInfinity, NegativeInfinity y NaN de los
tipos float y double (§4.2.4.1).

La gramática permite que un elemento que empiece como literal real doble tenga un
sufijo de tipo l o L . Este token es en realidad un literal entero cuyo valor se representa
mediante el tipo long.
7 Nota

Esta característica se ha conservado por compatibilidad con las versiones anteriores


de PowerShell. Sin embargo, no se recomienda a los programadores usar literales
enteros de este tipo, ya que pueden ocultar fácilmente el valor real del literal. Por
ejemplo, 1,2L tiene el valor 1; 1,2345e1L tiene el valor 12 y 1,2345e-5L tiene el valor
0, de los cuales ninguno es evidente de inmediato.

2.3.5.1.3 Sufijos de multiplicador

Sintaxis:

Syntax

numeric-multiplier: *one of*


kb mb gb tb pb

Descripción:

Para mayor comodidad, los literales enteros y reales pueden contener un elemento
numeric-multiplier, que indica un conjunto de potencias de 10 usadas habitualmente. El
elemento numeric-multiplier puede escribirse en cualquier combinación de letras
mayúsculas o minúsculas.

Multiplicador Significado Ejemplo

kb kilobyte (1024) 1kb ≡ 1024

mb megabyte (1024 x 1024) 1,30Dmb ≡ 1363148,80

gb gigabyte (1024 x 1024 x 1024) 0x10Gb ≡ 17179869184

tb terabyte (1024 x 1024 x 1024 x 1024) 1,4e23tb ≡ 1,5393162788864E+35

pb petabyte (1024 x 1024 x 1024 x 1024 x 1024) 0x12Lpb ≡ 20266198323167232

2.3.5.2 Literales de cadena

Sintaxis:

Syntax

string-literal:
expandable-string-literal
expandable-here-string-literal
verbatim-string-literal
verbatim-here-string-literal

expandable-string-literal:
double-quote-character expandable-string-characters~opt~ dollars~opt~
double-quote-character

double-quote-character:
" (U+0022)
Left double quotation mark (U+201C)
Right double quotation mark (U+201D)
Double low-9 quotation mark (U+201E)

expandable-string-characters:
expandable-string-part
expandable-string-characters
expandable-string-part

expandable-string-part:
Any Unicode character except
$
double-quote-character
` (The backtick character U+0060)
braced-variable
$ Any Unicode character except
(
{
double-quote-character
` (The backtick character U+0060)*
$ escaped-character
escaped-character
double-quote-character double-quote-character

dollars:
$
dollars $

expandable-here-string-literal:
@ double-quote-character whitespace~opt~ new-line-character
expandable-here-string-characters~opt~ new-line-character double-
quote-character @

expandable-here-string-characters:
expandable-here-string-part
expandable-here-string-characters expandable-here-string-part

expandable-here-string-part:
Any Unicode character except
$
new-line-character
braced-variable
$ Any Unicode character except
(
new-line-character
$ new-line-character Any Unicode character except double-quote-char
$ new-line-character double-quote-char Any Unicode character except @
new-line-character Any Unicode character except double-quote-char
new-line-character double-quote-char Any Unicode character except @

expandable-string-with-subexpr-start:
double-quote-character expandable-string-chars~opt~ $(

expandable-string-with-subexpr-end:
double-quote-char

expandable-here-string-with-subexpr-start:
@ double-quote-character whitespace~opt~ new-line-character
expandable-here-string-chars~opt~ $(

expandable-here-string-with-subexpr-end:
new-line-character double-quote-character @

verbatim-string-literal:
single-quote-character verbatim-string-characters~opt~ single-quote-char

single-quote-character:
' (U+0027)
Left single quotation mark (U+2018)
Right single quotation mark (U+2019)
Single low-9 quotation mark (U+201A)
Single high-reversed-9 quotation mark (U+201B)

verbatim-string-characters:
verbatim-string-part
verbatim-string-characters verbatim-string-part

verbatim-string-part:
*Any Unicode character except* single-quote-character
single-quote-character single-quote-character

verbatim-here-string-literal:
@ single-quote-character whitespace~opt~ new-line-character
verbatim-here-string-characters~opt~ new-line-character
single-quote-character *@*

verbatim-*here-string-characters:
verbatim-here-string-part
verbatim-here-string-characters verbatim-here-string-part

verbatim-here-string-part:
Any Unicode character except* new-line-character
new-line-character Any Unicode character except single-quote-character
new-line-character single-quote-character Any Unicode character except
@

Descripción:
Hay cuatro tipos de literales de cadena:

verbatim-string-literal (una sola línea y comillas simples), que es una secuencia de


cero o más caracteres delimitada por un par de elementos single-quote-character.
Algunos ejemplos son '' y 'rojo'.

expandable-string-literal (una sola línea y comillas dobles), que es una secuencia


de cero o más caracteres delimitada por un par de elementos double-quote-
character. Algunos ejemplos son "" y "rojo".

verbatim-here-string-literal (multilínea y comillas simples), que es una secuencia de


cero o más caracteres delimitada por los pares de caracteres @single-quote-
character y single-quote-character@ respectivamente,incluidos en dos o más líneas
de origen. Algunos ejemplos son:

PowerShell

@'
'@

@'
line 1
'@

@'
line 1
line 2
'@

expandable-here-string-literal (multilínea y comillas dobles), que es una secuencia


de cero o más caracteres delimitada por los pares de caracteres @double-quote-
character y double-quote-character@ respectivamente, incluidos en dos o más
líneas de origen. Algunos ejemplos son:

PowerShell

@"
"@

@"
line 1
"@

@"
line 1
line 2
"@
En lo que respecta a los elementos verbatim-here-string-literal y expandable-here-string-
literal, excepto el espacio en blanco (que se ignora), no puede seguirlos ningún carácter
en la misma línea de origen que el par de caracteres delimitadores de apertura y ningún
carácter puede precederlos en la misma línea de origen que el par de caracteres
delimitadores de cierre.

El cuerpo de un elemento verbatim-here-string-literal o expandable-here-string-literal


comienza al principio de la primera línea de origen después del delimitador de apertura
y termina al final de la última línea de origen que precede al delimitador de cierre. El
cuerpo puede estar vacío. El terminador de línea de la última línea de origen que
precede al delimitador de cierre no forma parte del cuerpo del literal.

Un literal de cualquiera de estas variantes tiene el tipo string (§4.3.1).

El carácter que se usa para delimitar un elemento verbatim-string-literal o expandable-


string-literal puede incluirse en este tipo de literal de cadena al escribir ese carácter dos
veces, de forma sucesiva. Por ejemplo, 'What''s the time?' y "I said, ""Hello""." . Sin
embargo, un elemento single-quote-character no tiene ningún significado especial
dentro de expandable-string-literal y un elemento double-quote-character no tiene
ningún significado especial dentro de verbatim-string-literal.

Los elementos expandable-string-literal y expandable-here-string-literal pueden


contener instancias de escaped-character (§2.3.7). Por ejemplo, cuando se escribe el
literal de cadena siguiente en la canalización, el resultado es el siguiente:

PowerShell

"column1`tcolumn2`nsecond line, `"Hello`", ```Q`5`!"

Output

column1<horizontal-tab>column2<new-line>
second line, "Hello", `Q5!

Si un elemento expandable-string-literal o expandable-here-string-literal contiene el


nombre de una variable, a menos que ese nombre esté precedido de forma inmediata
por un carácter de escape, se reemplaza por la representación de cadena del valor de
esa variable (§6.7). Esto se conoce como sustitución de variables.

7 Nota

Si el nombre de la variable forma parte de alguna expresión más grande, solo se


reemplaza el nombre de la variable. Por ejemplo, si $a es una matriz que contiene
los elementos 100 y 200, ">$a.Length<" da como resultado >100 200.Length< ,
mientras que ">$($a.Length)<" da como resultado >2< . Consulte la expansión de
la subexpresión a continuación.

Por ejemplo, el código fuente

PowerShell

$count = 10
"The value of `$count is $count"

da como resultado expandable-string-literal

Output

The value of $count is 10.

Tenga en cuenta lo siguiente.

PowerShell

$a = "red","blue"
"`$a[0] is $a[0], `$a[0] is $($a[0])" # second [0] is taken literally

El resultado es

Output

$a[0] is red blue[0], $a[0] is red

Los elementos expandable-string-literal y expandable-here-string-literal también


admiten un tipo de sustitución denominada expansión de subexpresiones, con el que el
texto con formato $( ... ) se trata como subexpresión (§7.1.6). Este texto se reemplaza
por la representación de cadena del valor de esa expresión (§6.8). Todo espacio en
blanco que se use para separar los tokens dentro de la lista de instrucciones de la
subexpresión se omite en la construcción de la cadena de resultados.

Los ejemplos,

PowerShell

$count = 10
"$count + 5 is $($count + 5)"
"$count + 5 is `$($count + 5)"
"$count + 5 is `$(`$count + 5)"

dan como resultado los literales de cadena expansibles (expandable-string-literal)


siguientes:

Output

10 + 5 is 15
10 + 5 is $(10 + 5)
10 + 5 is $($count + 5)

El origen siguiente,

PowerShell

$i = 5; $j = 10; $k = 15
"`$i, `$j, and `$k have the values $( $i; $j; $k )"

dan como resultado el elemento expandable-string-literal siguiente:

Output

$i, $j, and $k have the values 5 10 15

Estas cuatro líneas podrían haberse escrito de forma más concisa como se muestra a
continuación:

PowerShell

"`$i, `$j, and `$k have the values $(($i = 5); ($j = 10); ($k = 15))"

En el ejemplo siguiente,

PowerShell

"First 10 squares: $(for ($i = 1; $i -le 10; ++$i) { "$i $($i*$i) " })"

el elemento expandable-string-literal resultante es el siguiente:

Output

First 10 squares: 1 1 2 4 3 9 4 16 5 25 6 36 7 49 8 64 9 81 10 100


Tal y como se muestra, una subexpresión puede contener literales de cadena que tengan
tanto sustitución de variables como expansión de subexpresiones. Tenga en cuenta
también que no es necesario aplicar caracteres de escape a los delimitadores del
elemento expandable-string-literal interno; el hecho de que se encuentren dentro de
una subexpresión significa que no pueden ser terminadores para el elemento
expandable-string-literal externo.

Cada vez que se usa ese literal, se evalúa un elemento expandable-string-literal o


expandable-here-string-literal que contiene una sustitución de variables o una expansión
de subexpresiones; por ejemplo,

PowerShell

$a = 10
$s1 = "`$a = $($a; ++$a)"
"`$s1 = >$s1<"
$s2 = "`$a = $($a; ++$a)"
"`$s2 = >$s2<"
$s2 = $s1
"`$s2 = >$s2<"

da como resultado los elementos expandable-string-literal siguientes:

Output

$s1 = >$a = 10<


$s2 = >$a = 11<
$s2 = >$a = 10<

El contenido de un elemento verbatim-here-string-literal se interpreta textualmente,


incluidos los espacios en blanco iniciales o finales dentro del cuerpo. De esta forma, no
es necesario duplicar los elementos single-quote-character insertados y no hay ninguna
sustitución o expansión. Por ejemplo,

PowerShell

$lit = @'
That's it!
2 * 3 = $(2*3)
'@

que da como resultado el literal

Output
That's it!
2 * 3 = $(2*3)

El contenido de un elemento expandable-here-string-literal está sujeto a la sustitución y


expansión, pero cualquier espacio en blanco inicial o final dentro del cuerpo pero fuera
de cualquier subexpresión se interpreta textualmente y no es necesario duplicar los
elementos double-quote-character insertados. Por ejemplo,

PowerShell

$lit = @"
That's it!
2 * 3 = $(2*3)
"@

que da como resultado el literal siguiente al expandirse:

PowerShell

That's it!
2 * 3 = 6

Tanto para los elementos verbatim-here-string-literal como para expandable-here-string-


literal, cada terminador de línea dentro del cuerpo se representa en el literal resultante
de forma definida por la implementación. Por ejemplo, en:

PowerShell

$lit = @"
abc
xyz
"@

la segunda línea del cuerpo tiene dos espacios iniciales y las líneas primera y segunda
del cuerpo tienen terminadores de línea; sin embargo, el terminador de la segunda línea
del cuerpo no forma parte de ese cuerpo. El literal resultante es equivalente a
"abc<implementation-defined character sequence>xyz" .

7 Nota

Para mejorar la legibilidad del código fuente, los literales de cadena largos pueden
dividirse en varias líneas de origen sin necesidad de insertar terminadores de línea.
Para ello, se escribe cada parte como un literal independiente y se concatenan las
partes con el operador + (§7.7.2). Este operador permite que sus operandos
designen cualquiera de los cuatro tipos de literal de cadena.

7 Nota

Aunque no existe un literal de carácter en sí, puede lograrse el mismo efecto si se


accede al primer carácter de una cadena de un carácter, como se muestra a
continuación: [char]"A" o "A"[0] .

Para ambos elementos verbatim-here-string-literal y expandable-here-string-literal, cada


terminador de línea dentro del cuerpo se representa tal y como se proporcionó
exactamente.

2.3.5.3 Literal NULL

Consulte la variable automática $null (§2.3.2.2).

2.3.5.4 Literales booleanos

Consulte las variables automática $false y $true (§2.3.2.2).

2.3.5.5 Literales de matriz

PowerShell permite escribir expresiones de tipo de matriz (§9) mediante el operador de


coma unario (§7.2.1), array-expression (§7.1.7), el operador de coma binario (§7.3) y el
operador de intervalo (§7.4).

2.3.5.6 Literales hash


PowerShell permite escribir expresiones de tipo Hashtable (§10) mediante una expresión
hash-literal-expression (§7.1.9)

2.3.5.7 Nombres de tipo

Sintaxis:

Syntax

type-name:
type-identifier
type-name . type-identifier

type-identifier:
type-characters

type-characters:
type-character
type-characters type-character

type-character:
A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nd
_ (The underscore character U+005F)

array-type-name:
type-name [

generic-type-name:
type-name [

2.3.6 Operadores y signos de puntuación


Sintaxis:

Syntax

operator-or-punctuator: one of
{ } [ ] ( ) @( @{ $( ;
&& || & | , ++ .. :: .
! * / % + - --
-and -band -bnot -bor
-bxor -not -or -xor
assignment-operator
merging-redirection-operator
file-redirection-operator
comparison-operator
format-operator

assignment-operator: one of
= -= += *= /= %=

file-redirection-operator: one of
> >> 2> 2>> 3> 3>> 4> 4>>
5> 5>> 6> 6>> *> *>> <

merging-redirection-operator: one of
*>&1 2>&1 3>&1 4>&1 5>&1 6>&1
*>&2 1>&2 3>&2 4>&2 5>&2 6>&2

comparison-operator: *one of
-as -ccontains -ceq
-cge -cgt -cle
-clike -clt -cmatch
-cne -cnotcontains -cnotlike
-cnotmatch -contains -creplace
-csplit -eq -ge
-gt -icontains -ieq
-ige -igt -ile
-ilike -ilt -imatch
-in -ine -inotcontains
-inotlike -inotmatch -ireplace
-is -isnot -isplit
-join -le -like
-lt -match -ne
-notcontains -notin -notlike
-notmatch -replace -shl*
-shr -split

format-operator:
-f

Descripción:

&& y || están reservados para su uso futuro.

7 Nota

Nota del editor: los operadores de la cadena de canalización && y || se


introdujeron en PowerShell 7. Consulte about_Pipeline_Chain_Operators.

El nombre que sigue al guion en un operador se reserva solo para ese fin en un contexto
de operador.

Un operador que comienza con un guion no debe tener ningún espacio en blanco entre
ese guion y el token que lo sigue.

2.3.7 Caracteres de escape


Sintaxis:

Syntax

escaped-character:
` (The backtick character U+0060) followed by any Unicode character

Descripción:

Un carácter de escape es una forma de asignar una interpretación especial a un carácter


al proporcionarle un carácter de tilde aguda de prefijo (U+0060). En la tabla siguiente se
muestra el significado de cada carácter de escape:

Carácter Significado
de escape

`a Alerta (U+0007)

`b Retroceso (U+0008)

`f Avance de página (U+000C)

`n Nueva línea (U+000A)

`r Retorno de carro (U+000D)

`t Tabulación horizontal (U+0009)

`v Tabulación vertical (U+0009)

`' Comillas simples (U+0027)

`" Comillas dobles (U+0022)

`` Tilde aguda (U+0060)

`0 NUL (U+0000)

`x Si x es un carácter distinto de los que se muestran anteriormente, el carácter de


tilde aguda se omite y x se interpreta literalmente.

Lo que implica la entrada final en la tabla anterior es que los espacios, que de otro
modo separarían los tokens, pueden formar parte de un token en su lugar. Por ejemplo,
un nombre de archivo que contiene un espacio puede escribirse como Test` Data.txt
(además de como 'Test Data.txt' o "Test Data.txt" ).
3. Conceptos básicos
Artículo • 16/03/2022

3.1 Proveedores y unidades


Un proveedor permite el acceso a datos y componentes que de otro modo no serían
fácilmente accesibles en la línea de comandos. Los datos se presentan en un formato
coherente que se parece a una unidad del sistema de archivos.

Los datos que expone un proveedor aparecen en una unidad y se accede a ellos
mediante una ruta de acceso, igual que con una unidad de disco. Los cmdlets integrados
para cada proveedor administran los datos en la unidad del proveedor.

PowerShell incluye el conjunto siguiente de proveedores integrados para acceder a los


distintos tipos de almacenes de datos:

Proveedor Nombre de la unidad Descripción Ref.

Alias Alias: Alias de PowerShell Sección 3.1.1

Entorno Env: Variables de entorno Sección 3.1.2

FileSystem A:, B:, C:, ... Unidades de disco, directorios y archivos Sección 3.1.3

Función Función: Funciones de PowerShell Sección 3.1.4

Variable Variable: Variables de PowerShell Sección 3.1.5

Windows PowerShell:

Proveedor Nombre de la unidad Descripción

Certificado Cert: Certificados x509 para las firmas


digitales

Registro HKLM: (HKEY_LOCAL_MACHINE), HKCU: Registro de Windows


(HKEY_CURRENT_USER)

WSMan WSMan: Información de configuración de


WS-Management

Los cmdlets siguientes se encargan de los proveedores y unidades:

Get-PSProvider: obtiene información sobre uno o varios proveedores.


Get-PSDrive: obtiene información sobre una o varias unidades.
El tipo de un objeto que representa un proveedor se describe en la sección 4.5.1. El tipo
de un objeto que representa una unidad se describe en la sección 4.5.2.

3.1.1 Alias
Un alias es un nombre alternativo para un comando. Un comando puede tener varios
alias, y el nombre original y todos sus alias se pueden usar indistintamente. Un alias se
puede reasignar. Un alias es un elemento (sección 3.3).

Un alias se puede asignar a otro alias. pero el nuevo alias no es un alias del comando
original.

El alias del proveedor es un espacio de nombres plano que contiene solo objetos que
representan los alias. Las variables no tienen elementos secundarios.

Algunos alias están integrados en PowerShell.

Los cmdlets siguientes se encargan de los alias:

New-Alias: crea un alias.


Set-Alias: crea o cambia uno o varios alias.
Get-Alias: obtiene información sobre uno o varios alias.
Export-Alias: exporta uno o varios alias a un archivo

Cuando se crea un alias para un comando mediante New-Alias , los parámetros de ese
comando no se pueden incluir en ese alias. Pero la asignación directa a una variable en
el espacio de nombres Alias: permite incluir parámetros.

7 Nota

Aun así, es una cuestión sencilla crear una función que no haga nada más que
contener la invocación de ese comando con todos los parámetros deseados y
asignar un alias a esa función.

El tipo de un objeto que representa un enumerador se describe en la sección 4.5.4.

Los objetos de alias se almacenan en la unidad Alias: (sección 3.1).

3.1.2 Variables de entorno


El proveedor del entorno de PowerShell permite recuperar, agregar, cambiar, borrar y
eliminar variables de entorno del sistema operativo.
El proveedor Entorno es un espacio de nombres plano que solo contiene objetos que
representan las variables de entorno. Las variables no tienen elementos secundarios.

El nombre de una variable de entorno no puede incluir el signo igual ( = ).

Los cambios realizados en las variables de entorno afectan únicamente a la sesión


actual.

Una variable de entorno es un elemento (sección 3.3).

El tipo de un objeto que representa una variable de entorno se describe en la


sección 4.5.6.

Los objetos de variable de entorno se almacenan en la unidad Env: (sección 3.1).

3.1.3 Sistema de archivos


El proveedor del sistema de archivos de PowerShell permite crear, abrir, cambiar y
eliminar directorios y archivos.

El proveedor del sistema de archivos es un espacio de nombres jerárquico que contiene


objetos que representan el sistema de archivos subyacente.

Los archivos se almacenan en unidades con nombres como A:, B:, C:, y así sucesivamente
(sección 3.1). Se accede a los directorios y archivos mediante la notación de la ruta de
acceso (sección 3.4).

Un directorio o archivo es un elemento (sección 3.3).

3.1.4 Funciones
El proveedor de funciones de PowerShell permite recuperar, agregar, cambiar, borrar y
eliminar las funciones (sección 8.10) y los filtros (sección 8.10.1).

El proveedor Función es un espacio de nombres plano que solo contiene los objetos de
función y filtro. Las funciones y los filtros no tienen elementos secundarios.

Los cambios en las funciones solo afectan a la sesión actual.

Una función es un elemento (sección 3.3).

El tipo de un objeto que representa una función se describe en la sección 4.5.10. El tipo
de un objeto que representa un filtro se describe en la sección 4.5.11.

Los objetos de función se almacenan en la unidad Function: (sección 3.1).


3.1.5 Variables
Las variables se pueden definir y manipular directamente en el lenguaje de PowerShell.

El proveedor Variable es un espacio de nombres plano que contiene solo objetos que
representan las variables. Las variables no tienen elementos secundarios.

Los cmdlets siguientes también se encargan de las variables:

New-Variable: crea una variable.


Set-Variable: crea o cambia las características de una o varias variables.
Get-Variable: obtiene información sobre una o varias variables.
Clear-Variable: elimina el valor de una o varias variables.
Remove-Variable: elimina una o varias variables.

Como una variable es un elemento (sección 3.3), se puede manipular mediante la


mayoría de los cmdlets relacionados con elementos.

El tipo de un objeto que representa una variable se describe en la sección 4.5.3.

Los objetos de variable se almacenan en la unidad Variable: (sección 3.1).

3.2 Ubicaciones de trabajo


La ubicación de trabajo actual es la ubicación predeterminada a la que apuntan los
comandos. Esta es la ubicación que se usa si no se proporciona una ruta de acceso
explícita (sección 3.4) cuando se invoca un comando. Esta ubicación incluye la unidad
actual.

Un host de PowerShell puede tener varias unidades, en cuyo caso, cada unidad tendrá
su propia ubicación actual.

Cuando se especifica un nombre de unidad sin un directorio, la ubicación actual de esa


unidad está implícita.

La ubicación de trabajo actual se puede guardar en una pila y, después, establecerse en


una nueva ubicación. Más adelante, esa ubicación guardada se puede restaurar desde
esa pila y convertirla en la ubicación de trabajo actual. Hay dos tipos de pilas de
ubicación: la pila de ubicación de trabajo predeterminada, y cero o más pilas de ubicación
de trabajo con nombre definidas por el usuario. Cuando se inicia una sesión, la pila de
ubicación de trabajo predeterminada también es la pila de ubicación de trabajo actual.
Pero cualquier pila de ubicación de trabajo con nombre se puede convertir en la pila de
ubicación de trabajo actual.
Los cmdlets siguientes se encargan de las ubicaciones:

Set-Location: establece la ubicación de trabajo actual.


Get-Location: determina la ubicación de trabajo actual de las unidades
especificadas o las ubicaciones de trabajo de las pilas especificadas.
Push-Location: guarda la ubicación de trabajo actual en la parte superior de una
pila de ubicaciones especificada.
Pop-Location: restaura la ubicación de trabajo actual de la parte superior de una
pila de ubicaciones especificada.

Los tipos de objeto que representan una ubicación de trabajo y una pila de ubicaciones
de trabajo se describen en la sección 4.5.5.

3.3 Elementos
Un elemento es un alias (sección 3.1.1), una variable (sección 3.1.5), una función
(sección 3.1.4), una variable de entorno (sección 3.1.2), o un archivo o directorio en un
sistema de archivos (sección 3.1.3).

Los cmdlets siguientes se encargan de los elementos:

New-Item: crea un elemento.


Set-Item: cambia el valor de uno o varios elementos.
Get-Item: obtiene el elemento en la ubicación especificada.
Get-ChildItem: obtiene los elementos secundarios y los elementos en la ubicación
especificada.
Copy-Item: copia uno o varios elementos de una ubicación a otra.
Move-Item: mueve uno o varios elementos de una ubicación a otra.
Rename-Item: cambia el nombre de un elemento.
Invoke-Item: realiza la acción predeterminada en uno o varios elementos.
Clear-Item: elimina el contenido de uno o varios elementos, pero no los elimina.
Remove-Item: elimina los elementos especificados.

Los cmdlets siguientes se encargan del contenido de los elementos:

Get-Content: obtiene el contenido del elemento.


Add-Content: agrega contenido a los elementos especificados.
Set-Content: escribe o reemplaza el contenido de un elemento.
Clear-Content: elimina el contenido de un elemento.

El tipo de un objeto que representa un directorio se describe en la sección 4.5.17. El tipo


de un objeto que representa un archivo se describe en la sección 4.5.18.
3.4 Nombres de ruta de acceso
Todos los elementos de un almacén de datos accesibles mediante un proveedor de
PowerShell se pueden identificar de forma exclusiva por sus nombres de ruta de acceso.
Un nombre de ruta de acceso es una combinación del nombre del elemento, el
contenedor y los subcontenedores en los que se encuentra el elemento, y la unidad de
PowerShell por medio de la cual se accede a los contenedores.

Los nombres de ruta de acceso se dividen en uno de dos tipos: completa y relativa. Un
nombre de ruta de acceso completa consta de todos los elementos que componen una
ruta de acceso. La sintaxis siguiente muestra los elementos de un nombre de ruta de
acceso completo:

 Sugerencia

La notación ~opt~ en las definiciones de sintaxis indica que la entidad léxica es


opcional en la sintaxis.

Syntax

path:
provider~opt~ drive~opt~ containers~opt~ item

provider:
module~opt~ provider ::

module:
module-name \

drive:
drive-name :

containers:
container \
containers container \

El nombre de módulo hace referencia al módulo primario.

El proveedor hace referencia al proveedor de PowerShell por medio del cual se accede al
almacén de datos.

La unidad hace referencia a la unidad de PowerShell que es compatible con un


proveedor de PowerShell determinado.
Un contenedor puede incluir otros contenedores, que a su vez pueden incluir otros
contenedores, y así sucesivamente, con el contenedor final que contiene un elemento.
Los contenedores deben especificarse en el orden jerárquico en el que existen en el
almacén de datos.

Este es un ejemplo de un nombre de ruta de acceso:

E:\Accounting\InvoiceSystem\Production\MasterAccount\MasterFile.dat

Si el elemento final de una ruta de acceso contiene otros elementos, es un elemento


contenedor; de lo contrario, es un elemento hoja.

En algunos casos, no se necesita un nombre de ruta de acceso completa; basta con


proporcionar un nombre de ruta de acceso relativa. Un nombre de ruta de acceso
relativa se basa en la ubicación de trabajo actual. PowerShell permite identificar un
elemento en función de su ubicación en relación con la ubicación de trabajo actual. Un
nombre de ruta de acceso relativa implica el uso de algunos caracteres especiales. En la
tabla siguiente se describe cada uno de estos caracteres y se proporcionan ejemplos de
nombres de ruta de acceso relativa y nombres de ruta de acceso completa. Los ejemplos
de la tabla se basan en el directorio de trabajo actual que se establece en C:\Windows:

Símbolo Descripción Ruta de acceso Ruta de acceso


relativa completa

. Ubicación de trabajo actual .\System C:\Windows\System

.. Elemento primario de la ubicación de ..\Program Files C:\Program Files


trabajo actual

\ Raíz de la unidad de la ubicación de \Program Files C:\Program Files


trabajo actual

None Sin caracteres especiales System C:\Windows\System

Para usar un nombre de ruta de acceso en un comando, escriba ese nombre como un
nombre de ruta de acceso completa o relativa.

Los cmdlets siguientes se encargan de las rutas de acceso:

Convert-Path: convierte una ruta de acceso de PowerShell en una ruta de acceso


de proveedor de PowerShell.
Join-Path: combina una ruta de acceso y una ruta de acceso secundaria en una
única ruta de acceso.
Resolve-Path: resuelve los caracteres comodín de una ruta de acceso
Split-Path: devuelve la parte especificada de una ruta de acceso.
Test-Path: determina si los elementos de una ruta de acceso existen o si una ruta
de acceso tiene el formato correcto.

Algunos cmdlets (como Add-Content y Copy-Item ) usan filtros de archivo. Un filtro de


archivo es un mecanismo para especificar los criterios a fin de seleccionar entre un
conjunto de rutas de acceso.

El tipo de objeto que representa una ruta de acceso resuelta se describe en la


sección 4.5.5. Las rutas de acceso a menudo se manipulan como cadenas.

3.5 Ámbitos

3.5.1 Introducción
Un nombre puede indicar una variable, una función, un alias, una variable de entorno o
una unidad. El mismo nombre puede indicar elementos diferentes en distintos lugares
de un script. Para cada elemento diferente que indica un nombre, ese nombre solo es
visible en la región del texto de script que se conoce como su ámbito. Los distintos
elementos que se indican con el mismo nombre tienen ámbitos diferentes o están en
espacios de nombres diferentes.

Los ámbitos se pueden anidar. En este caso, un ámbito externo se conoce como ámbito
primario y los ámbitos anidados son ámbitos secundarios de ese ámbito primario. El
ámbito de un nombre es el ámbito en el que este y todos los ámbitos secundarios se
definen, a menos que se convierta en privado. Dentro de un ámbito secundario, un
nombre que se define ahí oculta los elementos definidos con el mismo nombre en los
ámbitos primarios.

A menos que se utilice la notación de origen de puntos (sección 3.5.5), cada uno de los
elementos siguientes crea un ámbito:

Un archivo de script
Un bloque de script
Una función o filtro

Considere el ejemplo siguiente:

PowerShell

# start of script
$x = 2; $y = 3
Get-Power $x $y

#function defined in script


function Get-Power([int]$x, [int]$y)
{
if ($y -gt 0) { return $x * (Get-Power $x (--$y)) }

else { return 1 }
}
# end of script

El ámbito de las variables $x y $y creadas en el script es el cuerpo de ese script,


incluida la función definida en él. La función Get-Power define dos parámetros con esos
mismos nombres. Como cada función tiene su propio ámbito, estas variables son
diferentes de las definidas en el ámbito primario y las ocultan del ámbito primario. El
ámbito de la función está anidado dentro del ámbito del script.

Tenga en cuenta que la función se llama a sí misma de forma recursiva. Cada vez que lo
hace crea otro ámbito anidado, cada uno con sus propias variables $x y $y .

Este es un ejemplo más complejo, que también muestra ámbitos anidados y


reutilización de nombres:

PowerShell

# start of script scope


$x = 2 # top-level script-scope $x created
# $x is 2
F1 # create nested scope with call to function F1
# $x is 2
F3 # create nested scope with call to function F3
# $x is 2

function F1 { # start of function scope


# $x is 2
$x = $true # function-scope $x created
# $x is $true

& { # create nested scope with script block


# $x is $true
$x = 12.345 # scriptblock-scope $x created
# $x is 12.345
} # end of scriptblock scope, local $x goes away

# $x is $true
F2 # create nested scope with call to function F2
# $x is $true
} # end of function scope, local $x goes away

function F2 { # start of function scope


# $x is $true
$x = "red" # function-scope $x created
# $x is "red"
} # end of function scope, local $x goes away

function F3 { # start of function scope


# $x is 2
if ($x -gt 0) {
# $x is 2
$x = "green"
# $x is "green"
} # end of block, but not end of any scope
# $x is still "green"
} # end of function scope, local $x goes away
# end of script scope

3.5.2 Nombres y números de ámbito


PowerShell admite los ámbitos siguientes:

Global: este es el ámbito de nivel superior. Todas las variables automáticas y de


preferencia se definen en este ámbito. El ámbito global es el ámbito primario de
todos los demás ámbitos y el resto de ámbitos son ámbitos secundarios del
ámbito global.

Local: este es el ámbito actual en cualquier punto de ejecución de un script, bloque


de script o función. Cualquier ámbito puede ser el ámbito local.

Script: este ámbito existe para cada archivo de script que se ejecuta. El ámbito del
script es el ámbito primario de todos los ámbitos creados desde dentro de él. Un
bloque de script no tiene su propio ámbito de script; en lugar de eso, su ámbito de
script es el del archivo de script antecesor más cercano. Aunque no existe nada
parecido a un ámbito de módulo, el ámbito de script proporciona el equivalente a
esto.

Los nombres se pueden declarar privados, en cuyo caso no son visibles fuera de su
ámbito primario, ni siquiera para los ámbitos secundarios. El concepto de privado no es
un ámbito independiente; es un alias para el ámbito local con la añadidura de ocultar el
nombre si se usa como una ubicación grabable.

Un número puede hacer referencia a los ámbitos, que describe la posición relativa de un
ámbito a otro. El ámbito 0 denota el ámbito local, el ámbito 1 denota un ámbito
antecesor de 1 generación, el ámbito 2 indica un ámbito antecesor de 2 generaciones, y
así sucesivamente. (Los cmdlets que manipulan variables usan números de ámbito).

3.5.3 Ámbito de nombre de variable


Tal como se muestra en la producción siguiente, se puede especificar un nombre de
variable con cualquiera de los seis ámbitos diferentes:

Syntax

variable-scope:
global:
local:
private:
script:
using:
workflow:
variable-namespace

El ámbito es opcional. En la tabla siguiente se muestra el significado de cada uno en


todos los contextos posibles. También muestra el ámbito cuando no se especifica
ninguno explícitamente:

Modificador En un archivo de script En un bloque de script En una función


de ámbito

global Ámbito global Ámbito global Ámbito global

script Ámbito del archivo de Ámbito del archivo de Ámbito del archivo de
script antecesor más script antecesor más script antecesor más
cercano o Global si no cercano o Global si no cercano o Global si no
hay ningún archivo de hay ningún archivo de hay ningún archivo de
script antecesor más script antecesor más script antecesor más
cercano cercano cercano

private Ámbito global/de Ámbito local Ámbito local


script/local

local Ámbito global/de Ámbito local Ámbito local


script/local

using Definido por la Definido por la Definido por la


implementación implementación implementación

flujo de Definido por la Definido por la Definido por la


trabajo implementación implementación implementación

None Ámbito global/de Ámbito local Ámbito local


script/local

También se puede especificar información de ámbito de variable al usar la familia de


cmdlets que se enumeran en la (sección 3.1.5). En concreto, consulte el parámetro
Scope , y los parámetros Option Private y Option AllScope para obtener más

información.

El ámbito using se usa para acceder a las variables definidas en otro ámbito mientras se
ejecutan scripts mediante cmdlets como Start-Job , Invoke-Command o en una
instrucción inlinescript. Por ejemplo:

PowerShell

$a = 42
Invoke-Command --ComputerName RemoteServer { $using:a } # returns 42
workflow foo
{
$b = "Hello"
inlinescript { $using:b }
}
foo # returns "Hello"

El flujo de trabajo de ámbito se usa con una instrucción paralela o una instrucción de
secuencia para acceder a una variable definida en el flujo de trabajo.

3.5.4 Ámbito de nombre de función


Un nombre de función también puede tener uno de los cuatro ámbitos diferentes y la
visibilidad de ese nombre es la misma que para las variables (sección 3.5.3).

3.5.5 Notación de origen de puntos


Cuando se ejecuta un archivo de script, un bloque de script o una función desde otro
archivo de script, bloque de script o función, el archivo de script ejecutado crea un
ámbito anidado. Por ejemplo,

PowerShell

Script1.ps1
& "Script1.ps1"
& { ... }
FunctionA

Pero cuando se usa la notación de origen de puntos, no se crea ningún ámbito antes de
ejecutar el comando, por lo que las incorporaciones o cambios que habría realizado en
su propio ámbito local se realizan en el ámbito actual. Por ejemplo,

PowerShell
. Script2.ps1
. "Script2.ps1"
. { ... }
. FunctionA

3.5.6 Módulos
Al igual que un archivo de script de nivel superior está en la raíz de un árbol jerárquico
de ámbito anidado, también lo está cada módulo (sección 3.14). Pero de manera
predeterminada, solo los nombres que exporta un módulo están disponibles por
nombre desde el contexto de importación. El parámetro Global del cmdlet Import-
Module permite que los nombres exportados tengan mayor visibilidad.

3.6 Propiedades ReadOnly y Constant


Las variables y alias las describen objetos que contienen varias propiedades. Estas
propiedades se establecen y manipulan mediante dos familias de cmdlets
(secciones 3.1.5 y 3.1.1). Una de estas propiedades es Options, que se puede establecer
en ReadOnly o Constant (mediante el parámetro Option). Se puede quitar una variable o
alias marcado como ReadOnly y sus propiedades pueden cambiar siempre que se
especifique el parámetro Force. Pero una variable o alias marcado como Constant no se
puede quitar ni cambiar sus propiedades.

3.7 Sobrecargas de métodos y resolución de


llamadas

3.7.1 Introducción
Tal como se indica en la sección 1, un procedimiento externo que pone a disposición el
entorno de ejecución (y que se escribe en un lenguaje distinto de PowerShell) se
denomina método.

El nombre de un método junto con el número y los tipos de sus parámetros se


denominan colectivamente firma de ese método. (Tenga en cuenta que la firma no
incluye el tipo de valor devuelto del método). El entorno de ejecución puede permitir
que un tipo tenga varios métodos con el mismo nombre siempre que cada uno tenga
una firma diferente. Cuando se definen varias versiones de algún método, se dice que
ese método está sobrecargado. Por ejemplo, el tipo Math (sección 4.3.8) contiene un
conjunto de métodos denominado Abs , que calcula el valor absoluto de un número
especificado, donde el número especificado puede tener un tipo de entre una serie de
ellos. Los métodos de ese conjunto tienen las firmas siguientes:

PowerShell

Abs(decimal)
Abs(float)
Abs(double)
Abs(int)
Abs(long)
Abs(SByte)
Abs(Int16)

En este caso, todos los métodos tienen el mismo número de argumentos; sus firmas
solo difieren por el tipo de argumento.

Otro ejemplo implica el tipo Array (sección 4.3.2), que contiene un conjunto de métodos
denominado Copy que copia un intervalo de elementos de una matriz a otra,
empezando por el principio de cada matriz (de manera predeterminada) o en algún
elemento designado. Los métodos de ese conjunto tienen las firmas siguientes:

PowerShell

Copy(Array, Array, int)


Copy(Array, Array, long)
Copy(Array, int, Array, int, int)
Copy(Array, long, Array, long, long)

En este caso, las firmas difieren por tipo de argumento y, en algunos casos, también por
número de argumento.

En la mayoría de las llamadas a métodos sobrecargados, el número y el tipo de los


argumentos pasados coinciden exactamente con una de las sobrecargas y el método
seleccionado es obvio. Pero si ese no es el caso, debe haber una manera de resolver a
qué versión sobrecargada se debe llamar, si la hubiera. Por ejemplo,

PowerShell

[Math]::Abs([byte]10) # no overload takes type byte


[Array]::Copy($source, 3, $dest, 5L, 4) # both int and long indexes

Otros ejemplos incluyen la cadena de tipo (es decir, System.String), que tiene
numerosos métodos sobrecargados.
Aunque PowerShell tiene reglas para resolver llamadas a métodos que no coinciden
exactamente con una firma sobrecargada, PowerShell no proporciona una manera de
definir métodos sobrecargados.

7 Nota

Nota del editor: PowerShell 5.0 agregó la capacidad de definir clases basadas en
scripts. Estas clases pueden contener métodos sobrecargados.

3.7.2 Resolución de sobrecarga del método


Dada una llamada de método (sección 7.1.3) con una lista de expresiones de argumento
y un conjunto de métodos candidatos (es decir, los métodos a los que se podría llamar),
el mecanismo para seleccionar el mejor método se denomina resolución de sobrecarga.

Dado el conjunto de métodos candidatos aplicables (sección 3.7.3), se selecciona el


mejor método de ese conjunto. Si el conjunto contiene solo un método, ese método es
el mejor. De lo contrario, el mejor método es el que es mejor que todos los demás
métodos con respecto a la lista de argumentos dada mediante las reglas que se
muestran en la sección 3.7.4. Si no hay exactamente un método que sea mejor que
todos los demás, la invocación del método es ambigua y se notifica un error.

El mejor método debe ser accesible en el contexto en el que se llama. Por ejemplo, un
script de PowerShell no puede llamar a un método privado o protegido.

El mejor método para una llamada a un método estático debe ser un método estático y,
del mismo modo, el mejor método para una llamada a un método de instancia debe ser
un método de instancia.

3.7.3 Método aplicable


Se dice que un método es aplicable con respecto a una lista de argumentos A cuando se
cumple una de las siguientes condiciones:

El número de argumentos de A es idéntico al número de parámetros que el


método acepta.
El método tiene M parámetros obligatorios y N parámetros opcionales, y el
número de argumentos de A es mayor o igual que M, pero menor que N.
El método acepta un número variable de argumentos y el número de argumentos
de A es mayor que el número de parámetros que acepta el método.
Además de tener un número adecuado de argumentos, cada argumento de A debe
coincidir con el modo de paso de parámetros del argumento, y el tipo de argumento
debe coincidir con el tipo de parámetro, o bien debe haber una conversión del tipo de
argumento al tipo de parámetro.

Si el tipo de argumento es ref (sección 4.3.6), el parámetro correspondiente también


debe ser ref y el tipo de argumento con fines de conversión es el tipo de la propiedad
Value del argumento ref.

Si el tipo de argumento es ref , el parámetro correspondiente podría ser en out lugar


de ref .

Si el método acepta un número variable de argumentos, el método puede ser aplicable


en formato normal o formato expandido. Si el número de argumentos de A es idéntico al
número de parámetros que acepta el método y el último parámetro es una matriz, el
formulario depende de la clasificación de una de las dos conversiones posibles:

Clasificación de la conversión del tipo del último argumento de A al tipo de matriz


para el último parámetro.
Clasificación de la conversión del tipo del último argumento de A al tipo de
elemento del tipo de matriz para el último parámetro.

Si la primera conversión (al tipo de matriz) es mejor que la segunda conversión (al tipo
de elemento de la matriz), el método se aplica en formato normal; de lo contrario, se
aplica en formato expandido.

Si hay más argumentos que parámetros, el método solo se puede aplicar en formato
expandido. Para que sea aplicable en formato expandido, el último parámetro debe
tener el tipo de matriz. El método se reemplaza por un método equivalente que tiene el
último parámetro reemplazado por parámetros suficientes a fin de tener en cuenta cada
argumento no coincidente en A. Cada tipo de parámetro adicional es el tipo de
elemento del tipo de matriz para el último parámetro del método original. Las reglas
anteriores para un método aplicable se aplican a este nuevo método y a la lista de
argumentos A.

3.7.4 Mejor método


Dada una lista de argumentos A con un conjunto de expresiones de argumento { E~1~,
E~2~, ..., E~N~ } , y dos métodos de aplicación M~P~ y M~Q~ con los tipos de

parámetro { P~1~, P~2~, ..., P~N~ } y { Q~1~, Q~2~, ..., Q~N~ } , M~P~ se define
como un método mejor que M~Q~ si la clasificación acumulativa de conversiones para
M~P~ es mejor que para M~Q~ .
La clasificación acumulativa de conversiones se calcula de la siguiente manera. Cada
conversión tiene un valor diferente en función del número de parámetros, con la
conversión de E~1~ con valor N, E~2~ con valor N-1, hasta E~N~ con valor 1. Si la
conversión de E~X~ a P~X~ es mejor que la de E~X~ a Q~X~ , M~P~ acumula N-X+1; de lo
contrario, M~Q~ acumula N-X+1. Si M~P~ y M~Q~ tienen el mismo valor, se usan las
siguientes reglas de separación, aplicadas en orden:

La clasificación acumulativa de conversiones entre tipos de parámetros (omitiendo


los tipos de argumentos) se calcula de forma similar a la clasificación anterior, por
lo que P~1~ se compara con Q~1~ , P~2~ con Q~2~ , ... y P~N~ con Q~N~ . La
comparación se omite si el argumento era $null o si los tipos de parámetro no
son tipos numéricos. La comparación también se omite si la conversión de
argumentos E~X~ pierde información cuando se convierte en P~X~ , pero no pierde
información cuando se convierte en Q~X~ , o viceversa. Si se comparan los tipos de
conversión de parámetros, si la conversión de P~X~ a Q~X~ es mejor que de Q~X~ a
P~X~ , M~P~ acumula N-X+1; de lo contrario, M~Q~ acumula N-X+1. Esta regla de

separación está pensada para preferir el método más específico (es decir, el método
con parámetros que tienen los tipos de datos más pequeños) si no se pierde
información en las conversiones, o para preferir el método más general (es decir, el
método que incluya parámetros con los tipos de datos más grandes) si las
conversiones tienen como resultado la pérdida de información.
Si ambos métodos usan su formato expandido, el método con más parámetros es
el mejor método.
Si un método usa el formato expandido y el otro usa el formato normal, el método
que usa el formato normal es el mejor método.

3.7.5 Mejor conversión


El texto siguiente marcado como este es específico de Windows PowerShell.

Las conversiones se clasifican de la siguiente manera, de menor a mayor:

T~1~[] a T~2~[] , donde no existe ninguna conversión asignable entre T~1~ y

T~2~ .

T a string, donde T es cualquier tipo.


T~1~ a T~2~ , donde T~1~ o T~2~ definen una conversión personalizada de una

manera definida por la implementación.


T~1~ a T~2~ , donde T~1~ implementa IConvertible.

T~1~ a T~2~ , donde T~1~ o T~2~ implementan el método T~2~ op_Implicit(T1) .


T~1~ a T~2~ , donde T~1~ o T~2~ implementan el método T~2~ op_Explicit(T1) .
T~1~ a T~2~ , donde T~2~ implementa un constructor que toma un único

argumento de tipo T~1~ .


Cualquiera de las siguientes conversiones:
string a T , donde T implementa un método estático T Parse(string) o T
Parse(string, IFormatProvider) .

T~1~ a T~2~ , donde T~2~ es cualquier enumeración y T~1~ es una cadena o

una colección de objetos que se pueden convertir en cadena.


T a PSObject, donde T es cualquier tipo.

Cualquiera de las siguientes conversiones: Language


T a bool, donde T es cualquier tipo numérico.
cadena a T , donde T es regex , wmisearcher , wmi , wmiclass , adsi ,
adsisearcher o type .
T a bool

T~1~ a Nullable[T~2~] , donde existe una conversión de T~1~ a T~2~ .


T a void.

T~1~[] a T~2~[] , donde existe una conversión asignable entre T~1~ y T~2~ .

T~1~ a T~2~[] , donde T~1~ es una colección.


IDictionary a Hashtable

T a ref
T a xml

scriptblock a delegate
T~1~ a T~2~ , donde T~1~ es un tipo entero y T~2~ es una enumeración.

$null a T , donde T es cualquier tipo de valor.

$null a T , donde T es cualquier tipo de referencia.


Cualquiera de las conversiones siguientes:

byte a T , donde T es SByte .

UInt16 a T , donde T es SByte , byte o Int16 .

Int16 a T , donde T es SByte o byte .

UInt32 a T , donde T es SByte , byte , Int16 , UInt16 o int .

int a T , donde T es SByte , byte , Int16 o UInt16 .

UInt64 a T , donde T es SByte , byte , Int16 , UInt16 , int , UInt32 o long .

long a T , donde T es SByte , byte , Int16 , UInt16 , int o UInt32 .

float a T , donde T es cualquier tipo entero o decimal .


double a T , donde T es cualquier tipo entero o decimal .

decimal a T , donde T es cualquier tipo entero.


Cualquiera de las conversiones siguientes:
SByte a T , donde T es byte , uint6 , UInt32 o UInt64 .
Int16 a T , donde T es UInt16 , UInt32 o UInt64 .

int a T , donde T es UInt32 o UInt64 .

long a UInt64
decimal a T , donde T es float o double .

Cualquiera de las conversiones siguientes:


T a string , donde T es cualquier tipo numérico.

T a char , donde T es cualquier tipo numérico.

string a T , donde T es cualquier tipo numérico.


Cualquiera de las siguientes conversiones se considera una conversión asignable:
byte a T , donde T es Int16 , UInt16 , int , UInt32 , long , UInt64 , single ,
double o decimal .

SByte a T , donde T es Int16 , UInt16 , int , UInt32 , long , UInt64 , single ,

double o decimal .
UInt16 a T , donde T es int , UInt32 , long , o UInt64 , single , double o

decimal .
Int16 a T , donde T es int , UInt32 , long , o UInt64 , single , double o decimal .

UInt32 a T , donde T es long , o UInt64 , single , double o decimal .


int a T , donde T es long , UInt64 , single , double o decimal .

single a double

T~1~ a T~2~ , donde T~2~ es una clase base o interfaz de T~1~ . Esta conversión se
considera asignable.
string a char[]
T a T : esta conversión se considera asignable.

Para cada conversión del formato T~1~ a T~2~[] , donde T~1~ no es una matriz y no se
aplica ninguna otra conversión, si hay una conversión de T~1~ a T~2~ , la clasificación de
la conversión es peor que la conversión de T~1~ a T~2~ , pero mejor que cualquier
conversión clasificada menor que la conversión de T~1~ a T~2~ .

3.8 Búsqueda de nombres


Es posible tener comandos de diferentes tipos que tengan el mismo nombre. El orden
en el que se realiza la búsqueda de nombres en este caso es alias, función, cmdlet y
comando externo.
3.9 Búsqueda de nombres de tipo
En la sección 7.1.10 se incluye la instrucción: "Un elemento literal de tipo se representa
en una implementación mediante algún tipo subyacente no especificado. Como
resultado, un nombre de tipo es un sinónimo de su tipo subyacente". Entre los ejemplos
de tipos se incluyen int , double , long[] y Hashtable .

Los nombres de tipo coinciden de la siguiente manera: compare un nombre de tipo


determinado con la lista de aceleradores de tipos integrados, como int, long y double. Si
se encuentra una coincidencia, ese es el tipo. De lo contrario, asuma que el nombre de
tipo está completo y vea si existe este tipo en el sistema host. Si se encuentra una
coincidencia, ese es el tipo. De lo contrario, agregue el prefijo de espacio de nombres
System. . Si se encuentra una coincidencia, ese es el tipo. De lo contrario, el nombre de
tipo es un error. Este algoritmo se aplica para cada argumento de tipo para tipos
genéricos. Pero no es necesario especificar la aridad (el número de argumentos u
operandos que toma una función u operador).

3.10 Administración de memoria automática


Varios operadores y cmdlets tienen como resultado la asignación de memoria para
objetos de tipo de referencia, como cadenas y matrices. El sistema en tiempo de
ejecución de PowerShell administra la asignación y la liberación de esta memoria. Es
decir, PowerShell proporciona recolección de elementos no utilizados automática.

3.11 Orden de ejecución


Un efecto secundario es un cambio en el estado del entorno de ejecución de un
comando. Un cambio en el valor de una variable (mediante los operadores de
asignación o los operadores de incremento y decremento previos y posteriores) es un
efecto secundario, al igual que un cambio en el contenido de un archivo.

A menos que se especifique lo contrario, las instrucciones se ejecutan en orden léxico.

Excepto como se especifica para algunos operadores, no se especifican el orden de


evaluación de los términos de una expresión ni el orden en que tienen lugar los efectos
secundarios.

Una expresión que invoca un comando implica la expresión que designa el comando, y
cero o más expresiones que designan los argumentos cuyos valores se van a pasar a ese
comando. No se especifica el orden en que estas expresiones se evalúan entre sí.
3.12 Control de errores
Cuando se produce un error en un comando, esto se considera un error y la información
sobre ese error se registra en un registro de error, cuyo tipo no se especifica
(sección 4.5.15), pero este tipo admite subíndices.

Un error se divide en una de estas dos categorías. Si finaliza la operación (un error de
terminación) o si no la finaliza (un error de no terminación). Con un error de terminación,
el error se registra y la operación se detiene. Con un error de no terminación, el error se
registra y la operación continúa.

Los errores de no terminación se escriben en la secuencia de errores. Aunque esa


información se puede redirigir a un archivo, los objetos de error se convierten primero
en cadenas y la información importante de esos objetos no se capturaría, lo que
dificulta el diagnóstico, si no es que resulta imposible. En su lugar, se puede redirigir el
texto del error (sección 7.12) y el objeto del error se puede guardar en una variable,
como en $Error1 = command 2>&1 .

La variable automática $Error contiene una colección de registros de error que


representan los errores recientes y el error más reciente está en $Error[0] . Esta
colección se mantiene en un búfer de forma que los registros antiguos se descartan a
medida que se agregan otros nuevos. La variable automática $MaximumErrorCount
controla el número de registros que se pueden almacenar.

$Error contiene todos los errores de todos los comandos combinados en una

colección. Para recopilar los errores de un comando específico, use el parámetro común
ErrorVariable, que permite especificar una variable definida por el usuario para contener
la colección.

3.13 Canalizaciones
Una canalización es una serie de uno o varios comandos que separa el operador de
canalización | (U+007C). Cada comando recibe la entrada de su predecesor y escribe la
salida en su sucesor. A menos que la salida al final de la canalización se descarte o se
redirija a un archivo, se envía al entorno de host, que puede optar por escribirla en la
salida estándar. Los comandos de una canalización también pueden recibir entradas de
argumentos. Por ejemplo, considere el uso siguiente de los comandos Get-ChildItem ,
Sort-Object y Process-File , que crean una lista de nombres de archivo en un directorio
del sistema de archivos determinado, ordenan un conjunto de registros de texto y
realizan algún procesamiento en un registro de texto, respectivamente:
PowerShell

Get-ChildItem
Get-ChildItem e:*.txt | Sort-Object -CaseSensitive | Process-File
>results.txt

En el primer caso, Get-ChildItem crea una colección de nombres de los archivos en el


directorio actual o predeterminado. Esa colección se envía al entorno de host, el cual ‒
de manera predeterminada‒ escribe el valor de cada elemento en la salida estándar.

En el segundo caso, Get-ChildItem crea una colección de nombres de los archivos en el


directorio especificado, utilizando el argumento e:*.txt . Esa colección se escribe en el
comando Sort-Object , el cual ‒de manera predeterminada‒ las ordena en orden
ascendente, con distinción entre mayúsculas y minúsculas (en virtud del argumento
CaseSensitive). Después, la colección resultante se escribe en el comando Process-File ,
que realiza algún procesamiento (desconocido). Posteriormente, la salida de ese
comando se redirige al archivo results.txt .

Si un comando escribe un único objeto, su sucesor recibe ese objeto y, después, finaliza
después de escribir sus propios objetos a su sucesor. Pero si un comando escribe varios
objetos, se entregan de uno en uno al comando sucesor, que se ejecuta una vez por
objeto. Este comportamiento se denomina streaming. En el procesamiento de
secuencias, los objetos se escriben a lo largo de la canalización en cuanto están
disponibles, no cuando se ha generado toda la colección.

Al procesar una colección, se puede escribir un comando de forma que pueda realizar
un procesamiento especial antes del elemento inicial y después del elemento final.

3.14 Módulos
Un módulo es una unidad independiente y reutilizable que permite particionar,
organizar y abstraer el código de PowerShell. Un módulo puede contener comandos
(como cmdlets y funciones) y elementos (como variables y alias) que se pueden usar
como una sola unidad.

Una vez creado un módulo, debe importarse en una sesión antes de que se puedan usar
los comandos y elementos que incluye. Una vez importado, los comandos y los
elementos se comportan como si estuvieran definidos localmente. Un módulo se
importa explícitamente con el comando Import-Module . Un módulo también se puede
importar automáticamente tal como se determina de una manera definida por la
implementación.
El tipo de un objeto que representa un módulo se describe en la sección 4.5.12.

Los módulos se analizan en detalle en la sección 11.

3.15 Expresiones comodín


Una expresión comodín puede contener cero o más de los elementos siguientes:

Elemento Descripción

Carácter Coincide con ese carácter.


distinto
de *, ? o [

* Coincide con cero o más caracteres. Para que coincida con un carácter *, use [*].

? Devuelve cualquier carácter. Para que coincida con un carácter ?, use [?].

[set] Coincide con cualquier carácter del conjunto, que no puede estar vacío.

Si set comienza por ], ese corchete derecho se considera parte de set y el siguiente
corchete derecho finaliza el conjunto. De lo contrario, el primer corchete derecho
finaliza el conjunto.

Si set comienza o termina con -, el guion menos se considera parte de set. De lo


contrario, indica un intervalo de puntos de código Unicode consecutivos con los
caracteres a ambos lados del guion menos como delimitadores de intervalo
inclusivos. Por ejemplo, A-Z indica las 26 letras mayúsculas en inglés y 0-9 indica los
10 dígitos decimales.

7 Nota

Puede encontrar más información en Especificaciones básicas de The Open Group:


Coincidencia de patrones, IEEE Std 1003.1, edición de 2004 . Pero en PowerShell,
el carácter de escape es una tilde aguda, no una barra diagonal inversa.

3.16 Expresiones regulares


Una expresión regular puede contener cero o más de los elementos siguientes:

Elemento Descripción
Elemento Descripción

Carácter Coincide con ese carácter.


distinto
de ., [, ^,
*, $ o \

. Devuelve cualquier carácter. Para que coincida con un carácter ., use \..

[set] El formato [set] coincide con cualquier carácter del conjunto. El formato [^set] no
[^set] coincide con ningún carácter del conjunto. set no puede estar vacío.

Si set comienza por ] o ^], ese corchete derecho se considera parte de set y el
siguiente corchete derecho finaliza el conjunto. De lo contrario, el primer corchete
derecho finaliza el conjunto.

Si set comienza por - o ^-, o termina con -, el guion menos se considera parte de set.
De lo contrario, indica un intervalo de puntos de código Unicode consecutivos con
los caracteres a ambos lados del guion menos como delimitadores de intervalo
inclusivos. Por ejemplo, A-Z indica las 26 letras mayúsculas en inglés y 0-9 indica los
10 dígitos decimales.

* Coincide con cero o más repeticiones del elemento anterior.

+ Coincide con una o varias repeticiones del elemento anterior.

? Coincide con cero o una repetición del elemento anterior.

^ Coincide con el inicio de la cadena. Para que coincida con un carácter ^, use \^.

$ Coincide con el final de la cadena. Para que coincida con un carácter $, use $.

\c Aplica el escape al carácter c, por lo que no se reconoce como un elemento de


expresión regular.

7 Nota

Puede encontrar más información en Especificaciones básicas de The Open Group:


Expresiones regulares, IEEE Std 1003.1, edición de 2004 .

Windows PowerShell: las clases de caracteres disponibles en las expresiones regulares


de Microsoft .NET Framework se admiten, tal como se muestra a continuación:

Elemento Descripción

\p{name} Coincide con cualquier carácter de la clase de caracteres con nombre especificada
por name. Los nombres admitidos son grupos Unicode e intervalos de bloques, como
Ll, Nd, Z, IsGreek e IsBoxDrawing.
Elemento Descripción

\P{name} Coincide con el texto no incluido en los grupos e intervalos de bloques especificados
en name.

\w Coincide con cualquier carácter de una palabra. Equivalente a las categorías de


caracteres Unicode [\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}] . Si se especifica un
comportamiento conforme a ECMAScript con la opción ECMAScript, \w es
equivalente a [a-zA-Z_0-9] .

\W Coincide con cualquier carácter que no pertenezca a una palabra. Equivalente a las
categorías Unicode [\^\p{Ll}\p{Lu}\p{Lt}\p{Lo}\p{Nd}\p{Pc}] .

\s Coincide con cualquier carácter de espacio en blanco. Equivalente a las categorías de


caracteres Unicode [\f\n\r\t\v\x85\p{Z}] .

\S Coincide con cualquier carácter que no sea un espacio en blanco. Equivalente a las
categorías de caracteres Unicode [\^\f\n\r\t\v\x85\p{Z}] .

\d Coincide con cualquier dígito decimal. Equivalente a \p{Nd} para Unicode y [0-9]
para el comportamiento que no es Unicode.

\D Coincide con cualquier valor que no es un dígito. Equivalente a \P{Nd} para Unicode
y [\^0-9] para el comportamiento que no es Unicode.

Los cuantificadores disponibles en las expresiones regulares de Microsoft .NET


Framework se admiten, tal como se muestra a continuación:

Elemento Descripción

* Especifica cero o más coincidencias; por ejemplo, \w* o (abc)*. . Equivalente a {0,} .

+ Coincide con las instancias repetidas de los caracteres anteriores.

? Especifica cero o una coincidencia; por ejemplo, \w? o (abc)? . Equivalente a {0,1} .

{n} Especifica exactamente n coincidencias; por ejemplo, (pizza){2} .

{n,} Especifica al menos n coincidencias; por ejemplo, (abc){2,} .

{n,m} Especifica al menos n coincidencias, pero m como máximo.


4. Tipos
Artículo • 09/03/2022

En PowerShell, cada valor tiene un tipo, y los tipos se incluyen en una de las dos
categorías principales: tipos de valor y tipos de referencia. Considere el tipo int , que
es un ejemplo típico de los tipos de valor. Un valor de tipo int es completamente
independiente; todos los bits necesarios para representar ese valor se almacenan en ese
valor y cada patrón de bits de ese valor representa un valor válido para su tipo. Ahora,
considere el tipo de matriz int[] , que es un ejemplo típico de los tipos de referencia.
Un llamado valor de tipo matriz puede contener una referencia a un objeto que
contiene realmente los elementos de la matriz, o bien la referencia nula cuyo valor es
$null . La distinción importante entre las dos categorías de tipos se muestra mejor en

las diferencias en su semántica durante la asignación. Por ejemplo,

PowerShell

$i = 100 # $i designates an int value 100


$j = $i # $j designates an int value 100, which is a copy

$a = 10,20,30 # $a designates an object[], Length 3, value 10,20,30


$b = $a # $b designates exactly the same array as does $a, not a copy
$a[1] = 50 # element 1 (which has a value type) is changed from 20 to 50
$b[1] # $b refers to the same array as $a, so $b[1] is 50

Como podemos ver, la asignación de un valor de tipo de referencia implica una copia
superficial; es decir, una copia de la referencia al objeto en lugar de su valor real. Por el
contrario, una copia en profundidad requiere también crear una copia del objeto.

Un tipo numérico es uno que permite la representación de valores enteros o


fraccionarios y que admite realizar operaciones aritméticas con esos valores. El conjunto
de tipos numéricos incluye los tipos de número enteros (§4.2.3) y números reales
(§4.2.4),pero no los tipos bool (§4.2.1) ni char (§4.2.2). Una implementación puede
proporcionar otros tipos numéricos (como bytes con signo, enteros sin signo y enteros
de otros tamaños).

Una colección es un grupo de uno o varios elementos relacionados que no pueden


tener el mismo tipo. Algunos ejemplos de tipos de colección son las matrices, pilas,
colas, listas y tablas hash. Un programa puede enumerar (o iterar) los elementos de una
colección, obteniendo acceso a cada elemento de uno en uno. Las formas habituales de
hacerlo son con la instrucción foreach (§8.4.4) y el cmdlet ForEach-Object. El tipo de un
objeto que representa un enumerador se describe en §4.5.16.
En este capítulo, hay tablas que muestran los miembros accesibles para un tipo
determinado. En el caso de los métodos, Type se escribe con este formato:
returnType/argumentTypeList. Si la lista de tipos de argumentos es demasiado larga para
caber en esa columna, se mostrará en la columna Purpose en su lugar.

Otros tipos de enteros son SByte , Int16 , UInt16 , UInt32 y UInt64 , todos en el espacio
de nombres System.

Muchas clases de colección se definen como parte de los espacios de nombres


System.Collections o System.Collections.Generic. La mayoría de las clases de colección
implementa las interfaces ICollection , IComparer , IEnumerable , IList , IDictionary y
IDictionaryEnumerator y sus equivalentes genéricos.

4.1 Tipos especiales

4.1.1 El tipo void


No se puede crear una instancia de este tipo. Proporciona un medio para descartar un
valor de manera explícita mediante el operador de conversión (§7.2.9).

4.1.2 El tipo NULL


El tipo NULL tiene una instancia, la variable automática $null (§2.3.2.2), también conocida
como valor NULL. Este valor proporciona un medio para expresar la "nada" en contextos
de referencia. Las características de este tipo no se especifican.

4.1.3 El tipo de objeto


Todos los tipos de PowerShell, excepto el tipo NULL (§4.1.2), derivan directa o
indirectamente del tipo object, por lo que el objeto es el tipo base definitivo de todos
los tipos que no son NULL. Una variable restringida (§5.3) al tipo object no está
realmente restringida en absoluto, porque puede contener un valor de cualquier tipo.

4.2 Tipos de valor

4.2.1 Booleano
El tipo booleano es bool . Solo hay dos valores de este tipo, False y True, representados
por las variables automáticas $false y $true , respectivamente (§2.3.2.2).
En PowerShell, bool se asigna a System.Boolean .

4.2.2 Carácter
Un valor de carácter tiene el tipo char, que es capaz de almacenar cualquier punto de
código Unicode de 16 bits codificado mediante UTF-16.

El tipo char tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

MaxValue Propiedad estática char El mayor valor posible de tipo char


(solo lectura)

MinValue Propiedad estática char El menor valor posible de tipo char


(solo lectura)

IsControl Método estático bool/char Comprueba si el carácter es un carácter de


control

IsDigit Método estático bool/char Comprueba si el carácter es un dígito


decimal

IsLetter Método estático bool/char Comprueba si el carácter es una letra del


alfabeto

IsLetterOrDigit Método estático bool/char Comprueba si el carácter es un dígito


decimal o una letra del alfabeto

IsLower Método estático bool/char Comprueba si el carácter es una letra del


alfabeto en minúscula

IsPunctuation Método estático bool/char Comprueba si el carácter es un signo de


puntuación

IsUpper Método estático bool/char Comprueba si el carácter es una letra del


alfabeto en mayúscula

IsWhiteSpace Método estático bool/char Comprueba si el carácter es un carácter de


espacio en blanco

ToLower Método estático char/string Convierte el carácter en minúscula

ToUpper Método estático char/string Convierte el carácter en mayúscula

Windows PowerShell: char se asigna a System.Char.

4.2.3 Entero
Hay dos tipos de entero con signo y ambos usan la representación del complemento a
dos para los valores negativos:

El tipo int , que usa 32 bits, lo que le da un intervalo de -2147483648 a


+2147483647 (incluido).
El tipo long , que usa 64 bits, lo que le da un intervalo de -9223372036854775808
a +9223372036854775807 (incluido).

El tipo int tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

MaxValue Propiedad estática (solo lectura) int El mayor valor posible de tipo int

MinValue Propiedad estática (solo lectura) int El menor valor posible de tipo int

El tipo long tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

MaxValue Propiedad estática (solo lectura) long El mayor valor posible de tipo long

MinValue Propiedad estática (solo lectura) long El menor valor posible de tipo long

Hay un tipo entero sin signo:

El tipo byte , que usa 8 bits, lo que le da un intervalo de 0 a 255 (incluido).

El tipo byte tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

MaxValue Propiedad estática (solo lectura) byte El mayor valor posible de tipo byte

MinValue Propiedad estática (solo lectura) byte El menor valor posible de tipo byte

En PowerShell, byte , int y long se asignan a System.Byte , System.Int32 y


System.Int64 , respectivamente.

4.2.4 Número real

4.2.4.1 float y double


Hay dos tipos reales (o de punto flotante):
El tipo float usa la representación de precisión sencilla IEEE de 32 bits.
El tipo double usa la representación de precisión doble IEEE de 64 bits.

Un tercer nombre de tipo, single , es sinónimo del tipo float ; se usa float a lo largo
de esta especificación.

Si bien el tamaño y la representación de los tipos float y double los define esta
especificación, una implementación puede usar la precisión extendida para obtener
resultados intermedios.

El tipo float tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

MaxValue Propiedad estática (solo FLOAT El mayor valor posible de tipo float
lectura)

MinValue Propiedad estática (solo FLOAT El menor valor posible de tipo float
lectura)

NaN Propiedad estática (solo FLOAT El valor de constante Not-a-Number


lectura)

NegativeInfinity Propiedad estática (solo FLOAT El valor de constante de infinitivo


lectura) negativo

PositiveInfinity Propiedad estática (solo FLOAT El valor de constante de infinitivo


lectura) positivo

El tipo double tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

MaxValue Propiedad estática (solo double El mayor valor posible de tipo double
lectura)

MinValue Propiedad estática (solo double El menor valor posible de tipo double
lectura)

NaN Propiedad estática (solo double El valor de constante Not-a-Number


lectura)

NegativeInfinity Propiedad estática (solo double El valor de constante de infinitivo


lectura) negativo

PositiveInfinity Propiedad estática (solo double El valor de constante de infinitivo


lectura) positivo
En PowerShell, float y double se asignan a System.Single y System.Double ,
respectivamente.

4.2.4.2 decimal

El tipo decimal usa una representación de 128 bits. Como mínimo, debe admitir una
escala s de tal modo que 0 <= s <= al menos 28, y un intervalo de valores de
-79228162514264337593543950335 a 79228162514264337593543950335. La
representación real de decimal la define la implementación.

El tipo decimal tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

MaxValue Propiedad estática (solo lectura) Decimal El mayor valor posible de tipo decimal

MinValue Propiedad estática (solo lectura) Decimal El menor valor posible de tipo decimal

7 Nota

Los números reales decimales tienen una característica denominada escala, que
representa la cantidad de dígitos a la derecha del separador decimal. Por ejemplo, el
valor 2,340 tiene una escala de 3 donde los ceros finales son significativos. Cuando
se agregan o restan dos números reales decimales, la escala del resultado es la
mayor de las dos escalas. Por ejemplo, 1,0 + 2,000 es 3,000, mientras que 5,0 - 2,00
es 3,00. Cuando se multiplican dos números reales decimales, la escala del resultado
es la suma de las dos escalas. Por ejemplo, 1,0 * 2,000 es 2,0000. Cuando se dividen
dos números reales decimales, la escala del resultado es la escala del primero
menos la escala del segundo. Por ejemplo, 4,00000/2,000 es 2,00. Sin embargo, una
escala no puede ser menor que la necesaria para conservar el resultado correcto.
Por ejemplo, 3,000/2,000, 3,00/2,000, 3,0/2,000 y 3/2 son todos 1,5.

En PowerShell, decimal se asigna a System.Decimal . La representación de decimal es la


siguiente:

Cuando se considera como una matriz de cuatro valores int , contiene estos
elementos:
El índice 0 (bits 0 a 31) contiene los 32 bits de orden inferior del coeficiente del
decimal.
El índice 1 (bits 32 a 63) contiene los 32 bits del medio del coeficiente del
decimal.
El índice 2 (bits 64 a 95) contiene los 32 bits de orden superior del coeficiente
del decimal.
El índice 3 (bits 96 a 127) contiene el bit de signo y la escala como se muestra a
continuación:
Los bits 0 a 15 son cero
Los bits 16 a 23 contienen la escala como un valor 0 a 28
Los bits 24 a 30 son cero
El bit 31 es el signo (0 para positivo, 1 para negativo)

4.2.5 El tipo switch


Este tipo se usa para restringir el tipo de un parámetro en un comando (§8.10.5). Si un
argumento con el nombre de parámetro correspondiente está presente, la prueba del
parámetro genera $true; de lo contrario, genera $false .

En PowerShell, switch se asigna a System.Management.Automation.SwitchParameter .

4.2.6 Tipos de enumeración


Un tipo de enumeración define un conjunto de constantes con nombre que representan
todos los valores posibles que se pueden asignar a un objeto de ese tipo de
enumeración. En algunos casos, el conjunto de valores es tal que solo se puede
representar un valor a la vez. En otros casos, el conjunto de valores corresponde a dos
potencias de dos distintas, y mediante el uso del operador -bor (§7.8.5),se pueden
codificar varios valores en el mismo objeto.

El entorno de PowerShell proporciona una serie de tipos de enumeración, tal como se


describe en las secciones siguientes.

4.2.6.1 Tipo Action-Preference


Este tipo definido por la implementación tiene estos miembros accesibles con valores
que se excluyen mutuamente:

Miembro Variante de Propósito


miembro

Continuar Constante de El runtime de PowerShell continuará realizando el


enumeración procesamiento y notificará al usuario que se produjo una
acción.
Miembro Variante de Propósito
miembro

Consultar Constante de El runtime de PowerShell detendrá el procesamiento y


enumeración preguntará al usuario cómo debe continuar.

SilentlyContinue Constante de El runtime de PowerShell continuará realizando el


enumeración procesamiento sin notificar al usuario que se produjo una
acción.

Stop Constante de El runtime de PowerShell detendrá el procesamiento cuando


enumeración se produzca una acción.

En PowerShell, este tipo es System.Management.Automation.ActionPreference .

4.2.6.2 Tipo Confirm-Impact


Este tipo definido por la implementación tiene estos miembros accesibles con valores
que se excluyen mutuamente:

Miembro Variante de Propósito


miembro

Alto Constante de La acción realizada tiene un riesgo alto de perder datos, como
enumeración volver a formatear un disco duro.

Bajo Constante de La acción realizada tiene un riesgo bajo de perder datos.


enumeración

Media Constante de La acción realizada tiene un riesgo medio de perder datos.


enumeración

None Constante de No confirme ninguna acción (suprima todas las solicitudes de


enumeración confirmación).

En PowerShell, este tipo es System.Management.Automation.ConfirmImpact .

4.2.6.3 Tipo File-Attributes

Este tipo definido por la implementación tiene estos miembros accesibles, que se
pueden combinar:

Miembro Variante de Propósito


miembro
Miembro Variante de Propósito
miembro

Archivo Constante Estado de archivo del archivo. Las aplicaciones usan este
de atributo para marcar los archivos para crear una copia de
enumeración seguridad o quitarlos.

Compressed Constante El archivo está comprimido.


de
enumeración

Dispositivo Reservado para uso futuro.

Directorio Constante El archivo es un directorio.


de
enumeración

Cifrado Constante El archivo o directorio está cifrado. Para un archivo, esto


de significa que todos los datos del archivo están cifrados.
enumeración Para un directorio, esto significa que el cifrado viene
predeterminado para todos los archivos y directorios recién
creados.

Hidden Constante El archivo está oculto y, por lo tanto, no se incluye en un


de listado de directorios ordinario.
enumeración

Normal Constante El archivo es normal y no tiene ningún otro atributo


de establecido. Este atributo solo es válido si se usa por sí solo.
enumeración

NotContentIndexed Constante El servicio de Index Server de contenido del sistema


de operativo no indizará el archivo.
enumeración

Sin conexión Constante El archivo no tiene conexión. Los datos del archivo no están
de disponibles de forma inmediata.
enumeración

ReadOnly Constante El archivo es de solo lectura.


de
enumeración

ReparsePoint Constante El archivo contiene un punto de reanálisis; es decir, un


de bloque de datos definidos por el usuario asociado a un
enumeración archivo o a un directorio.

SparseFile Constante El archivo es un archivo disperso. Los archivos dispersos


de suelen ser archivos grandes en los que la mayoría de los
enumeración datos son ceros.
Miembro Variante de Propósito
miembro

Sistema Constante El archivo es un archivo de sistema. El archivo forma parte


de del sistema operativo o lo utiliza exclusivamente el sistema
enumeración operativo.

Temporales Constante El archivo es temporal. Los sistemas de archivos intentan


de conservar en memoria todos los datos para que el acceso
enumeración sea más rápido, en lugar de vaciar los datos para
devolverlos al almacenamiento masivo. La aplicación
debería eliminar los archivos temporales tan pronto dejan
de ser necesarios.

En PowerShell, este tipo es System.IO.FileAttributes con el atributo FlagsAttribute.

4.2.6.4 Tipo Regular-Expression-Option

Este tipo definido por la implementación tiene estos miembros accesibles, que se
pueden combinar:

Miembro Variante de miembro Propósito

IgnoreCase Constante de Especifica que la coincidencia no distingue mayúsculas de


enumeración minúsculas.

None Constante de Especifica que no hay opciones establecidas.


enumeración

Una implementación puede proporcionar otros valores.

En PowerShell, este tipo es System.Text.RegularExpressions.RegexOptions con el


atributo FlagsAttribute . Se definen estos valores adicionales: Compiled ,
CultureInvariant , ECMAScript , ExplicitCapture , IgnorePatternWhitespace , Multiline ,
RightToLeft , Singleline .

4.3 Tipos de referencia

4.3.1 Cadenas
Un valor de cadena tiene un tipo string y es una secuencia inmutable de cero o más
caracteres de tipo char, donde cada uno contiene un punto de código Unicode de
16 bits codificado mediante UTF-16.
El tipo string tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

Length Propiedad de int (solo Obtiene el número de caracteres de la cadena


instancia lectura)

ToLower Método de cadena Crea una cadena que contiene el equivalente en


instancia minúsculas

ToUpper Método de cadena Crea una cadena que contiene el equivalente en


instancia mayúsculas

En PowerShell, string se asigna a System.String .

4.3.2 Matrices
Todos los tipos de matriz derivan del tipo Array . Este tipo tiene estos miembros
accesibles:

Miembro Variante Tipo Propósito


de
miembro

Length Propiedad int Cantidad de elementos en la matriz


de
instancia
(solo
lectura)

Rango Propiedad int Cantidad de dimensiones en la matriz


de
instancia
(solo
lectura)
Miembro Variante Tipo Propósito
de
miembro

Copiar Método void/ver Copia un intervalo de elementos de una matriz a otra. Hay
estático la cuatro versiones, donde source es la matriz de origen,
columna destination es la matriz de destino, count es la cantidad de
Purpose elementos que se van a copiar, y sourceIndex y
destinationIndex son las ubicaciones iniciales en sus matrices
respectivas:

Copy(source, destination, int count)


Copy(source, destination, long count)
Copy(source, sourceIndex, destination, destinationIndex, int
count)
Copy(source, sourceIndex, destination, destinationIndex, long
count)

GetLength Método int/none Cantidad de elementos en una dimensión determinada


de
instancia GetLength(int dimension)
(solo
lectura)

Para más detalles sobre las matrices, consulte §9.

En PowerShell, Array se asigna a System.Array .

4.3.3 Tablas hash


El tipo Hashtable tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

Recuento Propiedad de int Obtiene el número de pares clave-valor


instancia de la tabla hash

Claves Propiedad de Definido por la Obtiene una colección de todas las


instancia implementación claves

Valores Propiedad de Definido por la Obtiene una colección de todos los


instancia implementación valores

Quitar Método de void/none Quita el par clave-valor designado


instancia

Para más detalles sobre las tablas hash, consulte §10.


En PowerShell, Hashtable se asigna a System.Collections.Hashtable . Los elementos
Hashtable se almacenan en un objeto de tipo DictionaryEntry y las colecciones
devueltas por claves y valores tienen el tipo ICollection .

4.3.4 El tipo xml


El tipo xml implementa el nivel 1 principal de Document Object Model (DOM) de W3C y
el nivel 2 de DOM principal. DOM es una representación de árbol en memoria (caché)
de un documento XML y permite navegar y editar este documento. Este tipo admite el
operador de subíndice [] (§7.1.4.4).

En PowerShell, xml se asigna a System.Xml.XmlDocument .

4.3.5 El tipo regex


El tipo regex proporciona maquinaria para admitir el procesamiento de expresiones
regulares. Se usa para restringir el tipo de un parámetro (§5.3) cuyo argumento
correspondiente podría contener una expresión regular.

En PowerShell, regex se asigna a System.Text.RegularExpressions.Regex .

4.3.6 El tipo ref


Por lo general, los argumentos se pasan a los comandos por valor. En el caso de que un
argumento tenga algún tipo de valor, se pasa una copia del valor. En el caso de que un
argumento tenga algún tipo de referencia, se pasa una copia de la referencia.

El tipo ref proporciona maquinaria para permitir que los argumentos se pasen a los
comandos por referencia, de manera que los comandos pueden modificar el valor del
argumento. El tipo ref tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

Valor Propiedad de instancia Tipo del valor al que se Obtiene o establece el valor al
(lectura y escritura) hace referencia que se hace referencia

Tenga en cuenta la llamada y la definición de función siguientes:

PowerShell

function Doubler {
param ([ref]$x) # parameter received by reference
$x.Value *= 2.0 # note that 2.0 has type double
}

$number = 8 # designates a value of type int, value 8


Doubler([ref]$number) # argument received by reference
$number # designates a value of type double, value 8.0

Tenga en cuenta el caso en el que $number tiene restricciones por tipo:

PowerShell

[int]$number = 8 # designates a value of type int, value 8


Doubler([ref]$number) # argument received by reference
$number # designates a value of type int, value 8

Tal como se muestra, tanto el argumento como su parámetro correspondiente se deben


declarar ref .

En PowerShell, ref se asigna a System.Management.Automation.PSReference .

4.3.7 El tipo scriptblock


El tipo scriptblock representa un bloque precompilado de texto de script (§7.1.8) que
se puede usar como una sola unidad. Tiene estos miembros accesibles:

Miembro Variante Tipo Propósito


de
miembro

Atributos Propiedad Colección de Obtiene los atributos del bloque de script


de atributos
instancia
(solo
lectura)

Archivo Propiedad cadena Obtiene el nombre del archivo en el que se


de define el bloque de script
instancia
(solo
lectura)

Módulo Propiedad Definido por la Obtiene información sobre el módulo en el


de implementación que se define el bloque de script
instancia ([§4.5.12]
(solo [§4.5.12])
lectura)
Miembro Variante Tipo Propósito
de
miembro

GetNewClosure Método scriptblock Recupera un bloque de script que está


de /none enlazado a un módulo. Las variables locales
instancia que se encuentran en el contexto del autor de
la llamada se copiarán en el módulo.

Invocar Método Colección de Invoca el bloque de script con los argumentos


de object/object[] especificados y devuelve los resultados
instancia

InvokeReturnAsIs Método object/object[] Invoca el bloque de script con los argumentos


de especificados y devuelve cualquier objeto
instancia generado

Crear Método scriptblock Crea un objeto scriptblock que contiene el


estático /string script especificado.

En PowerShell, scriptblock se asigna a System.Management.Automation.ScriptBlock .


Invoke devuelve una colección de PsObject .

4.3.8 El tipo math


El tipo math proporciona acceso a algunas constantes y métodos que resultan útiles en
cálculos matemáticos. Tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

E Propiedad double Base logarítmica natural


estática
(solo lectura)

PI Propiedad double Relación entre la longitud de la circunferencia de


estática un círculo y su diámetro
(solo lectura)

Abs Método numeric/numeric Valor absoluto (el tipo de valor devuelto es el


estático mismo que el tipo del argumento pasado)

Acos Método double / double Ángulo cuyo coseno es el número especificado


estático

Asin Método double / double Ángulo cuyo seno es el número especificado


estático
Miembro Variante de Tipo Propósito
miembro

Atan Método double / double Ángulo cuya tangente es el número especificado


estático

Atan2 Método double / double Ángulo cuya tangente es el cociente de dos


estático y, double x números especificados x e y

Ceiling Método decimal / Número entero más pequeño mayor o igual que
estático decimal el número especificado

double / double

Cos Método double / double Coseno del ángulo especificado


estático

Cosh Método double / double Coseno hiperbólico del ángulo especificado


estático

Exp Método double / double e elevado a la potencia especificada


estático

Floor Método decimal / Valor entero más grande menor o igual que el
estático decimal número especificado

double / double

Log Método double / double Logaritmo de número mediante base e o base


estático number base

double / double
number, double
base

Log10 Método double / double Algoritmo en base 10 de un número especificado


estático

Max Método numeric/numeric El mayor de dos números especificados (el tipo de


estático valor devuelto es el mismo que el tipo de los
argumentos pasados)

Min Método numeric/numeric, El menor de dos números especificados (el tipo


estático numeric de valor devuelto es el mismo que el tipo de los
argumentos pasados)

Pow Método double / double Número especificado x elevado a la potencia


estático x, double y especificada y

Seno Método double / double Seno del ángulo especificado


estático
Miembro Variante de Tipo Propósito
miembro

Sinh Método double / double Seno hiperbólico del ángulo especificado


estático

Sqrt Método double / double Raíz cuadrada de un número especificado


estático

Tan Método double / double Tangente del ángulo especificado


estático

Tanh Método double / double Tangente hiperbólica del ángulo especificado


estático

En PowerShell, Math se asigna a System.Math .

4.3.9 El tipo ordered


El tipo ordered es un pseudotipo que solo se usa para las conversiones.

4.3.10 El tipo pscustomobject


El tipo pscustomobject es un pseudotipo que solo se usa para las conversiones.

4.4 Tipos genéricos


Varios lenguajes de programación y entornos proporcionan tipos que se pueden
especializar. Muchos se estos tipos se conocen como tipos de contenedor, porque sus
instancias pueden contener objetos de otro tipo. Considere un tipo llamado Stack que
puede representar una pila de valores que se puede insertar y sacar. Por lo general, el
usuario de una pila quiere almacenar solo un tipo de objeto en esa pila. Sin embargo, si
el lenguaje o el entorno no admite la especialización de tipos, se deben implementar
variantes distintas del tipo Stack aunque todas realicen la misma tarea, solo con
elementos de tipo distintos.

La especialización de tipos permite implementar un tipo genérico de forma que se


pueda restringir a la administración de algún subconjunto de tipos cuando se usa. Por
ejemplo,

Un tipo de pila genérico especializado para contener cadenas se podría escribir


como Stack[string] .
Un tipo de diccionario genérico especializado para contener claves int con valores
de cadena asociados se podría escribir como Dictionary[int,string] .
Una pila de pila de cadenas se podría escribir como Stack[Stack[string]] .

Si bien PowerShell no define ningún tipo genérico integrado, puede usar estos tipos si
los proporciona el entorno de host. Consulte la sintaxis en §7.1.10.

El nombre completo del tipo Stack[string] sugerido anteriormente es


System.Collections.Generic.Stack[string] . El nombre completo del tipo
Dictionary[int,string] sugerido anteriormente es

System.Collections.Generic.Dictionary[int,string] .

4.5 Tipos anónimos


En algunas circunstancias, una implementación de PowerShell crea objetos de algún tipo
y esos objetos tienen miembros accesibles para el script. Sin embargo, no es necesario
especificar el nombre real de esos tipos, siempre y cuando los miembros accesibles se
especifiquen lo suficiente para que se puedan usar. Es decir, los scripts pueden guardar
objetos de esos tipos y acceder a sus miembros sin conocer realmente los nombres de
esos tipos. Estos tipos se especifican en las subsecciones siguientes.

4.5.1 Tipo de descripción de proveedor


Este tipo encapsula el estado de un proveedor. Tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

Unidades Propiedad de instancia Definido por la Colección de objetos de


(solo lectura) implementación (§4.5.2) descripción de unidad

Name Propiedad de instancia cadena Nombre del proveedor


(solo lectura)

En PowerShell, este tipo es System.Management.Automation.ProviderInfo .

4.5.2 Tipo de descripción de unidad


Este tipo encapsula el estado de una unidad. Tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito


Miembro Variante de miembro Tipo Propósito

CurrentLocation Propiedad de instancia (lectura cadena La ubicación de trabajo actual


y escritura) (§3.1.4) de la unidad

Description Propiedad de instancia (lectura cadena Descripción de la unidad


y escritura)

Name Propiedad de instancia (solo cadena Nombre de la unidad


lectura)

Root Propiedad de instancia (solo cadena Nombre de la unidad


lectura)

En PowerShell, este tipo es System.Management.Automation.PSDriveInfo .

4.5.3 Tipo de descripción de variable


Este tipo encapsula el estado de una variable. Tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

Atributos Propiedad de Definido por la Colección de atributos


instancia (solo implementación
lectura)

Description Propiedad de cadena Descripción asignada a la variable a través de


instancia los cmdlets New-Variable o Set-Variable
(lectura y
escritura)

Módulo Propiedad de Definido por la Módulo desde el que se exportó esta variable
instancia (solo implementación
lectura) (§4.5.12)

ModuleName Propiedad de cadena Módulo en el que se definió esta variable


instancia (solo
lectura)

Name Propiedad de cadena Nombre asignado a la variable cuando se


instancia (solo creó en el lenguaje de PowerShell o a través
lectura) de los cmdlets New-Variable y Set-Variable

Opciones Propiedad de cadena Opciones asignadas a la variable a través de


instancia los cmdlets New-Variable y Set-Variable
(lectura y
escritura)
Miembro Variante de Tipo Propósito
miembro

Valor Propiedad de objeto Valor asignado a la variable cuando se asignó


instancia en el lenguaje de PowerShell o a través de los
(lectura y cmdlets New-Variable y Set-Variable
escritura)

En PowerShell, este tipo es System.Management.Automation.PSVariable .

Windows PowerShell: el tipo de la colección de atributos es


System.Management.Automation.PSVariableAttributeCollection.

4.5.4 Tipo de descripción de alias


Este tipo encapsula el estado de un alias. Tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

CommandType Propiedad de Definido por la Debe coincidir con "Alias"


instancia (solo implementación
lectura)

Definición Propiedad de cadena Comando o alias al que se asignó el


instancia (solo alias a través de los cmdlets New-
lectura) Alias o Set-Alias

Description Propiedad de cadena Descripción asignada al alias a


instancia través de los cmdlets New-Alias o
(lectura y Set-Alias
escritura)

Módulo Propiedad de Definido por la Módulo desde el que se exportó


instancia (solo implementación este alias
lectura) (§4.5.12)

ModuleName Propiedad de cadena Módulo en el que se definió este


instancia (solo alias
lectura)

Name Propiedad de cadena Nombre asignado al alias cuando


instancia (solo se creó a través de los cmdlets New-
lectura) Alias o Set-Alias
Miembro Variante de Tipo Propósito
miembro

Opciones Propiedad de cadena Opciones asignadas al alias a través


instancia de los cmdlets New-Alias o Set-
(lectura y Alias
escritura)

OutputType Propiedad de Colección Especifica los tipos de los valores


instancia (solo definida por la que genera el comando al que hace
lectura) implementación referencia el alias

Parámetros Propiedad de Colección Los parámetros del comando.


instancia (solo definida por la
lectura) implementación

ParameterSets Propiedad de Colección Información sobre los conjuntos de


instancia (solo definida por la parámetros asociados con el
lectura) implementación comando

ReferencedCommand Propiedad de Definido por la Información sobre el comando al


instancia (solo implementación que hace referencia inmediata este
lectura) alias

ResolvedCommand Propiedad de Definido por la Información sobre el comando para


instancia (solo implementación el que finalmente se resuelve el
lectura) alias

En PowerShell, este tipo es System.Management.Automation.AliasInfo .

4.5.5 Tipo de descripción de ubicación de trabajo


Este tipo encapsula el estado de una ubicación de trabajo. Tiene estos miembros
accesibles:

Miembro Variante de miembro Tipo Propósito

Unidad Propiedad de instancia Definido por la Objeto de descripción de


(solo lectura) implementación (§4.5.2) unidad

Ruta de Propiedad de instancia cadena Ubicación de trabajo


acceso (solo lectura)

Proveedor Propiedad de instancia Definido por la Proveedor


(solo lectura) implementación (§4.5.1)

ProviderPath Propiedad de instancia cadena Ruta de acceso actual


(solo lectura) del proveedor
Una pila de ubicaciones de trabajo es una colección de objetos de ubicación de trabajo,
tal como se describió anteriormente.

En PowerShell, una ubicación de trabajo actual se representa mediante un objeto de


tipo System.Management.Automation.PathInfo . Una pila de ubicaciones de trabajo se
representa mediante un objeto de tipo System.Management.Automation.PathInfoStack ,
que es una colección de objetos PathInfo .

4.5.6 Tipo de descripción de variable de entorno


Este tipo encapsula el estado de una variable de entorno. Tiene estos miembros
accesibles:

Miembro Variante de miembro Tipo Propósito

Name Propiedad de instancia (lectura y cadena Nombre de la variable de


escritura) entorno

Valor Propiedad de instancia (lectura y cadena Valor de la variable de entorno


escritura)

En PowerShell, este tipo es System.Collections.DictionaryEntry . El nombre de la


variable es la clave del diccionario. El valor de la variable de entorno es el valor del
diccionario. Name es un AliasProperty que equivale a Key.

4.5.7 Tipo de descripción de aplicación


Este tipo encapsula el estado de una aplicación. Tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

CommandType Propiedad de Definido por la Debe coincidir con "Application"


instancia (solo implementación
lectura)

Definición Propiedad de cadena Descripción de la aplicación


instancia (solo
lectura)

Extensión Propiedad de cadena Extensión del archivo de aplicación


instancia (lectura y
escritura)
Miembro Variante de Tipo Propósito
miembro

Módulo Propiedad de Definido por la Módulo que define este comando


instancia (solo implementación
lectura) (§4.5.12)

ModuleName Propiedad de cadena Nombre del módulo que define el


instancia (solo comando
lectura)

Name Propiedad de cadena El nombre del comando.


instancia (solo
lectura)

OutputType Propiedad de Colección definida Especifica los tipos de los valores


instancia (solo por la que genera el comando
lectura) implementación

Parámetros Propiedad de Colección definida Los parámetros del comando.


instancia (solo por la
lectura) implementación

ParameterSets Propiedad de Colección definida Información sobre los conjuntos de


instancia (solo por la parámetros asociados con el
lectura) implementación comando

Ruta de acceso Propiedad de cadena Obtiene la ruta de acceso del


instancia (solo archivo de aplicación
lectura)

En PowerShell, este tipo es System.Management.Automation.ApplicationInfo .

4.5.8 Tipo de descripción de cmdlet


Este tipo encapsula el estado de un cmdlet. Tiene estos miembros accesibles:

Miembro Variante Tipo Propósito


de
miembro

CommandType Propiedad Definido por la Debe coincidir con "Cmdlet"


de implementación
instancia
(solo
lectura)
Miembro Variante Tipo Propósito
de
miembro

DefaultParameterSet Propiedad Definido por la Conjunto de parámetros predeterminado


de implementación que se usa si PowerShell no puede
instancia determinar qué conjunto de parámetros
(solo usar en función de los argumentos
lectura) proporcionados

Definición Propiedad cadena Descripción del cmdlet


de
instancia
(solo
lectura)

HelpFile Propiedad cadena Ruta de acceso al archivo de Ayuda del


de cmdlet
instancia
(lectura y
escritura)

ImplementingType Propiedad Definido por la Tipo que implementa el cmdlet


de implementación
instancia
(lectura y
escritura)

Módulo Propiedad Definido por la Módulo que define este cmdlet


de implementación
instancia (§4.5.12)
(solo
lectura)

ModuleName Propiedad cadena Nombre del módulo que define el cmdlet


de
instancia
(solo
lectura)

Name Propiedad cadena Nombre del cmdlet


de
instancia
(solo
lectura)
Miembro Variante Tipo Propósito
de
miembro

Nombre Propiedad cadena Nombre de sustantivo del cmdlet


de
instancia
(solo
lectura)

OutputType Propiedad Colección Especifica los tipos de los valores que


de definida por la genera el cmdlet
instancia implementación
(solo
lectura)

Parámetros Propiedad Colección Parámetros del cmdlet


de definida por la
instancia implementación
(solo
lectura)

ParameterSets Propiedad Colección Información sobre los conjuntos de


de definida por la parámetros asociados con el cmdlet
instancia implementación
(solo
lectura)

Verbo Propiedad cadena Nombre de verbo del cmdlet


de
instancia
(solo
lectura)

PSSnapIn Propiedad Definido por la Windows PowerShell: información sobre el


de implementación complemento de Windows PowerShell que
instancia se usa para registrar el cmdlet.
(solo
lectura)

En PowerShell, este tipo es System.Management.Automation.CmdletInfo .

4.5.9 Tipo de descripción de script externo


Este tipo encapsula el estado de un script externo (que PowerShell puede ejecutar
directamente, pero que no está integrado). Tiene estos miembros accesibles:
Miembro Variante de Tipo Propósito
miembro

CommandType Propiedad de Definido por la Debe coincidir con "ExternalScript"


instancia (solo implementación
lectura)

Definición Propiedad de cadena Definición del script


instancia (solo
lectura)

Módulo Propiedad de Definido por la Módulo que define este script


instancia (solo implementación
lectura) (§4.5.12)

ModuleName Propiedad de cadena Nombre del módulo que define el


instancia (solo script
lectura)

Name Propiedad de cadena El nombre de la secuencia de


instancia (solo comandos.
lectura)

OriginalEncoding Propiedad de Definido por la Codificación original utilizada para


instancia (solo implementación convertir los caracteres del script en
lectura) bytes

OutputType Propiedad de Colección definida Especifica los tipos de los valores


instancia (solo por la que genera el script
lectura) implementación

Parámetros Propiedad de Colección definida Parámetros del script


instancia (solo por la
lectura) implementación

ParameterSets Propiedad de Colección definida Información sobre los conjuntos de


instancia (solo por la parámetros asociados con el script
lectura) implementación

Ruta de acceso Propiedad de cadena Ruta de acceso al archivo de script


instancia (solo
lectura)

Bloque de script Propiedad de scriptblock Script externo


instancia (solo
lectura)

ScriptContents Propiedad de cadena Contenido original del script.


instancia (solo
lectura)
En PowerShell, este tipo es System.Management.Automation.ExternalScriptInfo .

4.5.10 Tipo de descripción de función


Este tipo encapsula el estado de una función. Tiene estos miembros accesibles:

Miembro Variante Tipo Propósito


de
miembro

CmdletBinding Propiedad bool Indica si la función usa el mismo enlace de


de parámetros que usan los cmdlets
instancia compilados (consulte §12.3.5)
(solo
lectura)

CommandType Propiedad Definido por la Se puede comparar en términos de


de implementación igualdad con "Function" o "Filter" para ver
instancia cuál de estos representa este objeto
(solo
lectura)

DefaultParameterSet Propiedad cadena Especifica el conjunto de parámetros que


de se va a usar si no se puede determinar a
instancia partir de los argumentos (consulte §12.3.5)
(solo
lectura)

Definición Propiedad cadena Versión de cadena de ScriptBlock


de
instancia
(solo
lectura)

Description Propiedad cadena La descripción de la función.


de
instancia
(lectura y
escritura)

Módulo Propiedad Definido por la Módulo desde el que se exportó esta


de implementación función
instancia (§4.5.12)
(solo
lectura)
Miembro Variante Tipo Propósito
de
miembro

ModuleName Propiedad cadena Módulo en el que se definió esta función


de
instancia
(solo
lectura)

Name Propiedad cadena El nombre de la función


de
instancia
(solo
lectura)

Opciones Propiedad Definido por la Opciones de ámbito de la función (§3.5.4)


de implementación
instancia
(lectura y
escritura)

OutputType Propiedad Colección Especifica los tipos de valores generados,


de definida por la en orden (consulte §12.3.6)
instancia implementación
(solo
lectura)

Parámetros Propiedad Colección Especifica los nombres de parámetro, en


de definida por la orden. Si la función actúa como un cmdlet
instancia implementación (consulte CmdletBinding más arriba), los
(solo parámetros comunes se incluyen al final de
lectura) la colección

ParameterSets Propiedad Colección Información sobre los conjuntos de


de definida por la parámetros asociados con el comando
instancia implementación Para cada parámetro, el resultado muestra
(solo el nombre y el tipo del parámetro e indica
lectura) si el parámetro es obligatorio, por posición
o parámetro de modificador. Si la función
actúa como un cmdlet (consulte
CmdletBinding más arriba), los parámetros
comunes se incluyen al final de la
colección

Bloque de script Propiedad scriptblock Cuerpo de la función


de (§4.3.6)
instancia
(solo
lectura)
En PowerShell, este tipo es System.Management.Automation.FunctionInfo .

CommandType tiene el tipo System.Management.Automation.CommandTypes .


Options tiene el tipo System.Management.Automation.ScopedItemOptions .

OutputType tiene el tipo


System.Collections.ObjectModel.ReadOnlyCollection``1[[System.Management.Automa

tion.PSTypeName,System.Management.Automation]] .

Parameters tiene el tipo


System.Collections.Generic.Dictionary``2[[System.String,mscorlib],

[System.Management.Automation.ParameterMetadata,System.Management.Automation]] .
ParameterSets tiene el tipo

System.Collections.ObjectModel.ReadOnlyCollection``1[[System.Management.Automa

tion.CommandParameterSetInfo,System.Management.Automation]] .
La visibilidad tiene el tipo
System.Management.Automation.SessionStateEntryVisibility .
PowerShell también tiene una propiedad denominada Visibility.

4.5.11 Tipo de descripción de filtro


Este tipo encapsula el estado de un filtro. Tiene el mismo conjunto de miembros
accesibles que el tipo de descripción de función (§4.5.10).

En PowerShell, este tipo es System.Management.Automation.FilterInfo . Tiene el mismo


conjunto de propiedades que System.Management.Automation.FunctionInfo (§4.5.11).

4.5.12 Tipo de descripción de módulo


Este tipo encapsula el estado de un módulo. Tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

Description Propiedad de instancia cadena Descripción del módulo


(lectura y escritura) (establecida por el manifiesto)

ModuleType Propiedad de instancia Definido por la Tipo del módulo (Manifest, Script
(solo lectura) implementación o Binary)

Name Propiedad de instancia cadena Nombre del módulo


(solo lectura)

Ruta de Propiedad de instancia cadena Ruta de acceso del módulo


acceso (solo lectura)
En PowerShell, este tipo es System.Management.Automation.PSModuleInfo . El tipo de
ModuleType es System.Management.Automation.ModuleType .

4.5.13 Tipo de descripción de objeto personalizado


Este tipo encapsula el estado de un objeto personalizado. No tiene miembros
accesibles.

En PowerShell, este tipo es System.Management.Automation.PSCustomObject . Los cmdlets


Import-Module y New-Object pueden generar un objeto de este tipo.

4.5.14 Tipo de descripción de comando


La variable automática $PsCmdlet es un objeto que representa el cmdlet o la función
que está en ejecución. El tipo de este objeto está definido por la implementación y tiene
estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

ParameterSetName Propiedad de cadena Nombre del conjunto de


instancia (solo parámetros actual (consulte
lectura) ParameterSetName)

ShouldContinue Método de instancia Sobrecargado Solicita al usuario la confirmación


de una operación
/bool

ShouldProcess Método de instancia Sobrecargado Solicita la confirmación del usuario


antes de realizar una operación
/bool

En PowerShell, este tipo es System.Management.Automation.PSScriptCmdlet.

4.5.15 Tipo de descripción de registro de error


La variable automática $Error contiene una colección de registros de error que
representan los errores recientes (§3.12). Si bien el tipo de esta colección no está
especificado, admite la suscripción para obtener acceso a registros de error individuales.

En PowerShell, el tipo de colección es System.Collections.ArrayList . El tipo de un


registro de error individual de la colección es
System.Management.Automation.ErrorRecord . Este tipo tiene las propiedades públicas
siguientes:
CategoryInfo: obtiene información sobre la categoría del error.
ErrorDetails: obtiene y establece información de error más detallada, como un
mensaje de error de reemplazo.
Exception: obtiene la excepción asociada con este registro de error.
FullyQualifiedErrorId: obtiene el identificador de error completo correspondiente a
este registro de error.
InvocationInfo: obtiene información sobre el comando que se invocó cuando se
produjo el error.
PipelineIterationInfo: obtiene el estado de la canalización cuando se creó este
registro de error.
TargetObject: obtiene el objeto que se estaba procesando cuando se produjo el
error.

4.5.16 Tipo de descripción de enumerador


Diversas variables son enumeradores para las colecciones (§4). La variable automática
$foreach es el enumerador creado para cualquier instrucción foreach . La variable
automática $input es el enumerado para una colección que se entrega a una función
desde la canalización. La variable automática $switch es el enumerado creado para
cualquier instrucción switch .

El tipo de un enumerador está definido por la implementación y tiene estos miembros


accesibles:

Miembro Variante Tipo Propósito


de
miembro

Current Propiedad objeto Obtiene el elemento actual de la colección. Si el


de enumerador actualmente no está posicionado en un
instancia elemento de la colección, el comportamiento está
(solo definido por la implementación.
lectura)

MoveNext Método None/bool Desplaza el enumerador al siguiente elemento de la


de colección. Devuelve $true si el enumerador avanzó
instancia correctamente al elemento siguiente; devuelve $false si el
enumerador alcanzó el final de la colección.

En PowerShell, estos miembros se definen en la interfaz System.IEnumerator , que se


implementa mediante los tipos que aparecen identificados a continuación. Si el
enumerador actualmente no está posicionado en un elemento de la colección, se
genera una excepción de tipo InvalidOperationException . Para $foreach , este tipo es
System.Array+SZArrayEnumerator . Para $input , este tipo es

System.Collections.ArrayList+ArrayListEnumeratorSimple . Para $switch , este tipo es


System.Array+SZArrayEnumerator .

4.5.17 Tipo de descripción de directorio


El cmdlet New-Item puede crear elementos de variantes distintas, incluidos directorios
FileSystem. El tipo de un objeto de descripción de directorio está definido por la
implementación y tiene estos miembros accesibles:

Miembro Variante de Tipo Propósito


miembro

Atributos Propiedad de Definido por la Obtiene o establece uno o varios de


instancia (lectura y implementación los atributos del objeto de directorio
escritura) (§4.2.6.3)

CreationTime Propiedad de Definido por la Obtiene y establece la hora de


instancia (lectura y implementación creación del objeto de directorio
escritura) (§4.5.19)

Extensión Propiedad de cadena Obtiene la parte de extensión del


instancia (solo nombre del directorio
lectura)

FullName Propiedad de cadena Obtiene la ruta de acceso completa


instancia (solo del directorio.
lectura)

Hora de Propiedad de Definido por la Obtiene o establece la hora a la que


última instancia (lectura y implementación se escribió por última vez en el
escritura escritura) (§4.5.19) directorio

Name Propiedad de cadena Obtiene el nombre del directorio.


instancia (solo
lectura)

En PowerShell, este tipo es System.IO.DirectoryInfo . El tipo de la propiedad Attributes


es System.IO.FileAttributes .

4.5.18 Tipo de descripción de archivo


El cmdlet New-Item puede crear elementos de variantes distintas, incluidos archivos
FileSystem. El tipo de un objeto de descripción de archivo está definido por la
implementación y tiene estos miembros accesibles:
Miembro Variante de Tipo Propósito
miembro

Atributos Propiedad de Definido por la Obtiene o establece uno o varios de los


instancia implementación atributos del objeto de archivo
(lectura y (§4.2.6.3)
escritura)

BaseName Propiedad de cadena Obtiene el nombre del archivo, sin incluir la


instancia (solo extensión
lectura)

CreationTime Propiedad de Definido por la Obtiene y establece la hora de creación del


instancia implementación objeto de archivo
(lectura y (§4.5.19)
escritura)

Extensión Propiedad de cadena Obtiene la parte de extensión del nombre


instancia (solo del archivo
lectura)

FullName Propiedad de cadena Obtiene la ruta de acceso completa del


instancia (solo archivo
lectura)

Hora de Propiedad de Definido por la Obtiene o establece la hora a la que se


última instancia implementación escribió por última vez en el archivo
escritura (lectura y (§4.5.19)
escritura)

Length Propiedad de long Obtiene el tamaño del archivo, en bytes.


instancia (solo
lectura)

Name Propiedad de cadena Obtiene el nombre del archivo.


instancia (solo
lectura)

VersionInfo Propiedad de Definido por la Windows PowerShell: esta ScriptProperty


instancia (solo implementación devuelve un elemento
lectura) System.Diagnostics.FileVersionInfo para el
archivo.

En PowerShell, este tipo es System.IO.FileInfo .

4.5.19 Tipo de descripción Date-Time


El tipo de un objeto de descripción date-time está definido por la implementación y
tiene estos miembros accesibles:
Miembro Variante de Tipo Propósito
miembro

Día Propiedad de int Obtiene el componente correspondiente al día del mes


instancia (solo representado por esta instancia
lectura)

Hora Propiedad de int Obtiene el componente correspondiente a la hora de la


instancia (solo fecha representada por esta instancia.
lectura)

Minuto Propiedad de int Obtiene el componente correspondiente a los minutos


instancia (solo de la fecha representada por esta instancia.
lectura)

Month Propiedad de int Obtiene el componente correspondiente al mes de la


(Mes) instancia (solo fecha representada por esta instancia.
lectura)

Segundo Propiedad de int Obtiene el componente correspondiente a los


instancia (solo segundos de la fecha representada por esta instancia.
lectura)

Year Propiedad de int Obtiene el componente correspondiente al año de la


instancia (solo fecha representada por esta instancia.
lectura)

El cmdlet Get-Date puede crear un objeto de este tipo.

En PowerShell, este tipo es System.DateTime .

4.5.20 Tipo de descripción Group-Info


El tipo de un objeto de descripción group-info está definido por la implementación y
tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

Recuento Propiedad de instancia int Obtiene la cantidad de


(solo lectura) elementos del grupo

Grupo Propiedad de instancia Colección definida por la Obtiene los elementos del
(solo lectura) implementación grupo

Name Propiedad de instancia cadena Obtiene el nombre del grupo.


(solo lectura)

Valores Propiedad de instancia Colección definida por la Obtiene los valores de los
(solo lectura) implementación elementos del grupo
El cmdlet Group-Object puede crear un objeto de este tipo.

En PowerShell, este tipo es Microsoft.PowerShell.Commands.GroupInfo .

4.5.21 Tipo de descripción Generic-Measure-Info


El tipo de un objeto de descripción generic-measure-info está definido por la
implementación y tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

Media Propiedad de instancia double Obtiene el promedio de los valores de las


(solo lectura) propiedades que se miden

Recuento Propiedad de instancia int Obtiene la cantidad de objetos con las


(solo lectura) propiedades especificadas

Máxima Propiedad de instancia double Obtiene el valor máximo de las propiedades


(solo lectura) especificadas

Mínima Propiedad de instancia double Obtiene el valor mínimo de las propiedades


(solo lectura) especificadas

Propiedad Propiedad de instancia cadena Obtiene la propiedad que se va a medir


(solo lectura)

Sum Propiedad de instancia double Obtiene la suma de los valores de las


(solo lectura) propiedades especificadas

El cmdlet Measure-Object puede crear un objeto de este tipo.

En PowerShell, este tipo es Microsoft.PowerShell.Commands.GenericMeasureInfo .

4.5.22 Tipo de descripción Text-Measure-Info


El tipo de un objeto de descripción text-info está definido por la implementación y tiene
estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

Characters Propiedad de instancia (solo int Obtiene la cantidad de caracteres del


lectura) objeto de destino

Líneas Propiedad de instancia (solo int Obtiene la cantidad de líneas del objeto de
lectura) destino
Miembro Variante de miembro Tipo Propósito

Propiedad Propiedad de instancia (solo cadena Obtiene la propiedad que se va a medir


lectura)

Words Propiedad de instancia (solo int Obtiene la cantidad de palabras del objeto
lectura) de destino

El cmdlet Measure-Object puede crear un objeto de este tipo.

En PowerShell, este tipo es Microsoft.PowerShell.Commands.TextMeasureInfo .

4.5.23 Tipo de credencial


Luego se puede usar un objeto de credencial en varias operaciones de seguridad. El tipo
de un objeto de credencial está definido por la implementación y tiene estos miembros
accesibles:

Miembro Variante de miembro Tipo Propósito

Contraseña Propiedad de instancia (solo Definido por la Obtiene la contraseña


lectura) implementación

UserName Propiedad de instancia (solo cadena Obtiene el nombre de


lectura) usuario

El cmdlet Get-Credential puede crear un objeto de este tipo.

En PowerShell, este tipo es System.Management.Automation.PSCredential .

4.5.24 Tipo de designador de método


El tipo de un designador de método está definido por la implementación y tiene estos
miembros accesibles:

Miembro Variante Tipo Propósito


de
miembro

Invocar Método objeto/número Toma un número variable de argumentos y llama


de variable y tipo indirectamente al método al que hace referencia el
instancia designador de método primario, pasando los
argumentos.

Un objeto de este tipo se puede crear mediante invocation-expression (§7.1.3).


En PowerShell, este tipo es System.Management.Automation.PSMethod.

4.5.25 Tipo de definición de miembro


Este tipo encapsula la definición de un miembro. Tiene estos miembros accesibles:

Miembro Variante de miembro Tipo Propósito

Definición Propiedad de instancia cadena Obtiene la definición del


(solo lectura) miembro

MemberType Propiedad de instancia Definido por la Obtiene el tipo de PowerShell


(solo lectura) implementación del miembro

Name Propiedad de instancia cadena Obtiene el nombre del


(solo lectura) miembro.

TypeName Propiedad de instancia cadena Obtiene el nombre de tipo


(solo lectura) del miembro

En PowerShell, este tipo es Microsoft.PowerShell.Commands.MemberDefinition .

4.6 Extensión y adaptación de tipos


Una implementación de PowerShell incluye una familia de tipos principales (que se
documentan en este capítulo), donde cada uno contiene su propio conjunto de
miembros base. Esos miembros pueden ser métodos o propiedades, y pueden ser
miembros de instancia o estáticos. Por ejemplo, los miembros base del tipo string
(§4.3.1) corresponden a la propiedad de instancia Length y los métodos de instancia
ToLower y ToUpper.

Cuando se crea un objeto, contiene todas las propiedades de instancia del tipo de ese
objeto y se puede llamar a los métodos de instancia de ese tipo en ese objeto. Un
objeto se puede personalizar mediante la incorporación de miembros de instancia en
tiempo de ejecución. El resultado se denomina objeto personalizado. Los miembros
agregados a una instancia solo existen durante la vida útil de esa instancia. Otras
instancias del mismo tipo básico no se ven afectadas.

El conjunto de miembros base de un tipo se puede aumentar mediante la incorporación


de estas variantes de miembros:

Miembros adaptados, a través del sistema de tipo extendido (ETS), cuyos detalles en
su mayoría no están especificados.
Miembros extendidos, a través del Add-Member.
En PowerShell, también se pueden agregar miembros extendidos a través de archivos
types.ps1xml . En conjunto, los miembros adaptados y extendidos se denominan
miembros sintéticos.

El sistema de tipo extendido agrega los miembros siguientes a todos los objetos de
PowerShell: psbase, psadapted, psextended y pstypenames. Para más información
sobre estos miembros, consulte los parámetros Force y View en el cmdlet Get-Member.

Un miembro de instancia puede ocultar un miembro extendido o adaptado con el


mismo nombre y un miembro extendido puede ocultar un miembro adaptado. En tales
casos, los conjuntos de miembros psadapted y psextended se pueden usar para
acceder a esos miembros ocultos.

Si un archivo types.ps1xml especifica un miembro denominado Supports,


obj.psextended proporciona acceso solo a ese miembro y no a un miembro que se haya
agregado a través de Add-Member .

Hay tres maneras de crear un objeto personalizado con un miembro M nuevo:

1. Se puede usar este enfoque para agregar uno o varios miembros NoteProperty.

PowerShell

$x = New-Object PsObject -Property @{M = 123}`

2. Se puede usar este enfoque para agregar miembros NoteProperty o ScriptMethod.

PowerShell

$x = New-Module -AsCustomObject {$M = 123 ; Export-ModuleMember --


Variable M}`

3. Este enfoque se puede usar para agregar cualquier variante de miembro.

PowerShell

$x = New-Object PsObject
Add-Member -InputObject $x -Name M -MemberType NoteProperty -Value 123

PsObject es el tipo base de todos los tipos de PowerShell.


5. Variables
Artículo • 16/03/2022

Una variable representa una ubicación de almacenamiento para un valor y ese valor
tiene un tipo. Los lenguajes de programación de procedimientos tradicionales son de
tipos estáticos; Es decir, el tipo en tiempo de ejecución de una variable es con el que se
declaró en tiempo de compilación. Los lenguajes orientados a objetos agregan la idea
de herencia, que permite que el tipo en tiempo de ejecución de una variable sea con el
que se declaró en tiempo de compilación o con algún tipo derivado de ese tipo. Al ser
un lenguaje con tipos dinámicos, las variables de PowerShell no tienen tipos por sí solos.
De hecho, las variables no están definidas; simplemente se convierten cuando se les
asigna un valor por primera vez. Y aunque una variable puede estar restringida
(sección 5.3) para que contenga un valor de un tipo determinado, la información de tipo
de una asignación no siempre se puede comprobar estáticamente.

En momentos diferentes, una variable puede asociarse a valores de tipos diferentes


mediante la asignación (sección 7.11) o el uso de los operadores ++ y ‑‑ (sección 7.1.5,
sección 7.2.6). Cuando se cambia el valor asociado a una variable, el tipo de ese valor
puede cambiar. Por ejemplo,

PowerShell

$i = "abc" # $i holds a value of type string


$i = 2147483647 # $i holds a value of type int
++$i # $i now holds a value of type double because
# 2147483648 is too big to fit in type int

Cualquier uso de una variable que no se haya creado da como resultado el valor $null.
Para ver si se ha definido una variable, use el cmdlet Test-Path.

5.1 Ubicación grabable


Una ubicación grabable es una expresión que designa un recurso al que un comando
tiene acceso de lectura y escritura. Una ubicación grabable puede ser una variable
(sección 5), un elemento de matriz (sección 9), un valor asociado en una tabla hash a la
que se accede mediante un subíndice (sección 10), una propiedad (sección 7.1.2) o un
almacenamiento que administra un proveedor (sección 3.1).

5.2 Categorías de variable


PowerShell define las siguientes categorías de variables: variables estáticas, variables de
instancia, elementos de matriz, pares clave-valor de tabla hash, parámetros, variables
normales y variables en unidades de proveedor. Las subsecciones siguientes describen
cada una de estas categorías.

En el ejemplo siguiente:

PowerShell

function F ($p1, $p2) {


$radius = 2.45
$circumference = 2 * ([Math]::PI) * $radius

$date = Get-Date -Date "2010-2-1 10:12:14 pm"


$month = $date.Month

$values = 10, 55, 93, 102


$value = $values[2]

$h1 = @{ FirstName = "James"; LastName = "Anderson" }


$h1.FirstName = "Smith"

$Alias:A = "Help"
$Env:MyPath = "e:\Temp"
${E:output.txt} = 123
$function:F = { "Hello there" }
$Variable:v = 10
}

[Math::PI] es una variable estática.


$date.Month es una variable de instancia.

$values[2] es un elemento de matriz.


$h1.FirstName es una clave Hashtable cuyo valor correspondiente es

$h1['FirstName']`.
$p1 y $p2 son parámetros
$radius , $circumference , $date , $month , $values , $value y $h1 son variables

normales.
$Alias:A , $Env:MyPath , ${E:output.txt} y $function:F son variables en las

unidades de proveedor correspondientes.


$Variable:v es una variable normal escrita con su unidad de proveedor completa.

5.2.1 Variables estáticas


Un miembro de datos de un objeto que pertenece al tipo del objeto en lugar de a esa
instancia concreta del tipo se denomina variable estática. Vea las secciones 4.2.3, 4.2.4.1
y 4.3.8 para ver algunos ejemplos.

PowerShell no proporciona ninguna manera de crear tipos que contengan variables


estáticas, pero el entorno de host puede proporcionar objetos de estos tipos.

El entorno de host y el sistema de recolección de elementos no utilizados administran la


memoria para crear y eliminar objetos que contienen variables estáticas.

Para obtener información sobre el acceso a una variable estática, vea la sección 7.1.2.

Un miembro de datos estático puede ser un campo o una propiedad.

5.2.2 Variables de instancia


Un miembro de datos de un objeto que pertenece a una instancia concreta del tipo del
objeto en lugar de a ese mismo tipo se denomina variable de instancia. Vea las
secciones 4.3.1, 4.3.2 y 4.3.3 para ver algunos ejemplos.

Un entorno de host de PowerShell podría proporcionar una manera de crear tipos que
contengan variables de instancia o de agregar nuevas variables de instancia a los tipos
existentes.

El entorno de host y el sistema de recolección de elementos no utilizados administran la


memoria para crear y eliminar objetos que contienen variables estáticas.

Para obtener información sobre el acceso a una variable de instancia, vea la


sección 7.1.2.

Un miembro de datos de instancia puede ser un campo o una propiedad.

5.2.3 Elementos de matriz


Una matriz se puede crear mediante un operador de coma unario (sección 7.2.1), una
subexpresión (sección 7.1.6), una expresión de matriz (sección 7.1.7), un operador de
coma binario (sección 7.3), un operador de rango (sección 7.4) o un cmdlet New-Object.

El entorno de host y el sistema de recolección de elementos no utilizados administran la


memoria para crear y eliminar matrices.

Las matrices y los elementos de matriz se describen en la sección 9.

5.2.4 Pares clave-valor de tablas hash


Una tabla hash se crea mediante un literal hash (sección 2.3.5.6) o el cmdlet New-Object.
Se puede agregar un nuevo par clave-valor mediante el operador [] (sección 7.1.4.3).

El entorno de host y el sistema de recolección de elementos no utilizados administran la


memoria para crear y eliminar tablas hash.

Las tablas hash se describen en la sección 10.

5.2.5 Parámetros
Un parámetro se crea cuando se invoca su comando primario y se inicializa con el valor
del argumento proporcionado en la invocación o por el entorno de host. Un parámetro
deja de existir cuando finaliza su comando primario.

Los parámetros se describen en la sección 8.10.

5.2.6 Variables normales


Una variable normal se define mediante una expresión de asignación (sección 7.11) o
una instrucción foreach (sección 8.4.4). Algunas variables normales las predefine el
entorno de host, mientras que otras son transitorias; van y vienen según sea necesario
en tiempo de ejecución.

La duración de una variable normal es esa parte de la ejecución del programa durante la
cual se garantiza que el almacenamiento se reservará para ella. Esta duración comienza
en la entrada en el ámbito al que está asociado y finaliza no antes del final de la
ejecución de ese ámbito. Si el ámbito primario se introduce de forma recursiva o
iterativa, se crea una instancia de la variable local cada vez.

El almacenamiento al que hace referencia una variable normal se reclama


independientemente de la duración de esa variable.

Una variable normal se puede denominar explícitamente con un prefijo de espacio de


nombres Variable: (sección 5.2.7).

5.2.7 Variables en unidades de proveedor


El concepto de proveedores y unidades se introduce en la sección 3.1, y cada proveedor
puede proporcionar sus propias unidades de espacio de nombres. Esto permite tener
acceso a los recursos de esas unidades como si fueran variables normales
(sección 5.2.6). De hecho, una variable normal se almacena en la unidad del proveedor
del sistema de archivos Variable: (sección 3.1.5) y se puede acceder a ella por su nombre
normal o su nombre de espacio de nombres completo.

Algunos tipos de variables de espacio de nombres están restringidos implícitamente


(sección 5.3).

5.3 Variables restringidas


De manera predeterminada, una variable puede designar un valor de cualquier tipo.
Pero una variable puede estar restringida a designar valores de un tipo determinado
especificando ese tipo como literal de tipo antes de su nombre en una asignación o un
parámetro. Por ejemplo,

PowerShell

[int]$i = 10 # constrains $i to designating ints only


$i = "Hello" # error, no conversion to int
$i = "0x10" # ok, conversion to int
$i = $true # ok, conversion to int

function F ([int]$p1, [switch]$p2, [regex]$p3) { ... }

Cualquier variable que pertenezca al espacio de nombres Env: , Alias: o al espacio de


nombres del sistema de archivos (secciones 2.3.2 y 3.1) se restringe implícitamente al
tipo string . Cualquier variable que pertenezca al espacio de nombres Function:
(secciones 2.3.2 y 3.1) se restringe implícitamente al tipo scriptblock .
6. Conversiones
Artículo • 16/03/2022

Se realiza una conversión de tipos cuando se usa un valor de un tipo en un contexto que
requiere un tipo diferente. Si dicha conversión se produce automáticamente, se conoce
como conversión implícita. (Un ejemplo común de esto es con algunos operadores que
necesitan convertir uno o varios de los valores que designan sus operandos). Se permite
la conversión implícita siempre que se conserve la sensación del valor de origen, como
cuando no hay ninguna pérdida de precisión de un número al convertirse.

El operador de conversión (sección 7.2.9) permite la conversión explícita.

Las conversiones se describen a continuación, y se proporciona información


complementaria según sea necesario en la descripción de cada operador en la
sección 6.19.

La conversión explícita de un valor al tipo que ya tiene no produce ningún cambio en


ese valor ni en su representación.

Las reglas para entregar la conversión cuando el valor de una expresión se enlaza a un
parámetro se tratan en la sección 6.17.

6.1 Conversión a void


Un valor de cualquier tipo se puede descartar explícitamente al convertirlo al tipo void.
No hay ningún resultado.

6.2 Conversión a bool


Las reglas para convertir cualquier valor al tipo bool son las siguientes:

Un valor numérico o char de cero se convierte en False; un valor numérico o char


distinto de cero se convierte en True.
Un valor de tipo NULL se convierte en False.
Una cadena de longitud 0 se convierte en False; una cadena de longitud mayor
que 0 se convierte en True.
Un parámetro switch con valor $true se convierte en True y uno con valor $false
se convierte en False.
Todos los demás valores de tipo de referencia distintos de NULL se convierten en
True.
Si el tipo implementa IList:

Si la longitud del objeto > 2, el valor se convierte en True.


En caso de que la longitud del objeto es 1 y ese primer elemento no es en sí
mismo un IList, si el valor de ese elemento es cierto, el valor se convierte en True.
De lo contrario, si el recuento del primer elemento >= 1, el valor se convierte en
True.
De lo contrario, el valor se convierte en False.

6.3 Conversión a char


Las reglas para convertir cualquier valor al tipo char son las siguientes:

La conversión de un valor de tipo bool, decimal, float o double es errónea.


Un valor de tipo NULL se convierte en el carácter NULL (U+0000).
Un valor de tipo entero cuyo valor se puede representar en el tipo char tiene ese
valor. De lo contrario, la conversión es errónea.
La conversión de un valor de cadena que tiene una longitud distinta de 1 es
errónea.
Un valor de cadena con una longitud 1 se convierte en un elemento char que tiene
ese valor de carácter.
Un valor de tipo numérico cuyo valor después de redondear cualquier parte
fraccional se puede representar en el tipo de destino que tiene ese valor
redondeado. De lo contrario, la conversión es errónea.
Para otros valores de tipo de referencia, si el tipo de referencia admite dicha
conversión, es la que se usa. De lo contrario, la conversión es errónea.

6.4 Conversión a integer


Las reglas para convertir cualquier valor al tipo byte, int o long son las siguientes:

El valor bool False se convierte en cero; El valor bool True se convierte en 1.


Un valor de tipo char cuyo valor se puede representar en el tipo de destino tiene
ese valor. De lo contrario, la conversión es errónea.
Un valor de tipo numérico cuyo valor después de redondear cualquier parte
fraccional se puede representar en el tipo de destino que tiene ese valor
redondeado. De lo contrario, la conversión es errónea.
Un valor de tipo NULL se convierte en cero.
Una cadena que representa un número se convierte tal como se describe en la
sección 6.16. Si después del truncamiento de la parte fraccional el resultado se
puede representar en el tipo de destino, la cadena tiene un formato correcto e
incluye el tipo de destino. De lo contrario, la conversión es errónea. Si la cadena no
representa un número, la conversión es errónea.
Para otros valores de tipo de referencia, si el tipo de referencia admite dicha
conversión, es la que se usa. De lo contrario, la conversión es errónea.

6.5 Conversión a float y double


Las reglas para convertir cualquier valor al tipo float o double son las siguientes:

El valor bool False se convierte en cero; El valor bool True se convierte en 1.


Un valor char se representa exactamente.
Un valor de tipo numérico se representa exactamente, si es posible; pero para las
conversiones int, long y decimal a float y para las conversiones long y decimal a
double, se pueden perder algunos de los bits menos significativos del valor entero.
Un valor de tipo NULL se convierte en cero.
Una cadena que representa un número se convierte tal como se describe en la
sección 6.16. De lo contrario, la conversión es errónea.
Para otros valores de tipo de referencia, si el tipo de referencia admite dicha
conversión, es la que se usa. De lo contrario, la conversión es errónea.

6.6 Conversión a decimal


Las reglas para convertir cualquier valor al tipo decimal son las siguientes:

El valor bool False se convierte en cero; El valor bool True se convierte en 1.


Un valor de tipo char se representa exactamente.
Un valor de tipo numérico se representa exactamente, pero si ese valor es
demasiado grande o demasiado pequeño para caber en el tipo de destino, la
conversión será errónea.
Un valor de tipo NULL se convierte en cero.
Una cadena que representa un número se convierte tal como se describe en la
sección 6.16. De lo contrario, la conversión es errónea.
Para otros valores de tipo de referencia, si el tipo de referencia admite dicha
conversión, es la que se usa. De lo contrario, la conversión es errónea.
La escala del resultado de una conversión correcta es tal que la parte fraccional no
tiene ceros finales.

6.7 Conversión a object


El valor de cualquier tipo excepto el tipo NULL (4.1.2) se puede convertir al tipo object.
El valor conserva su tipo y representación.

6.8 Conversión a string


Las reglas para convertir cualquier valor en tipo string son las siguientes:

El valor bool $false se convierte en "False"; el valor bool $true se convierte en


"True".
Un valor de tipo char se convierte en una cadena de 1 carácter que contiene ese
valor char.
Un valor de tipo numérico se convierte en una cadena que tiene el formato de un
literal numérico correspondiente. Pero el resultado no tiene espacios iniciales o
finales, ningún signo más inicial, los enteros tienen base 10 y no hay ningún sufijo
de tipo. Para una conversión decimal, se conserva la escala. Para los valores de -∞,
+∞ y NaN, las cadenas resultantes son "-Infinity", "Infinity" y "NaN",
respectivamente.
Un valor de tipo NULL se convierte en la cadena vacía.
Para una matriz unidimensional, el resultado es una cadena que contiene el valor
de cada elemento de esa matriz, de principio a fin, convertida en cadena, con
elementos que separa el separador de campos de salida actual (sección 2.3.2.2).
Para una matriz que tiene elementos que son matrices en sí mismos, solo se
convierten los elementos de nivel superior. La cadena utilizada para representar el
valor de un elemento que es una matriz está definida por la implementación. En el
caso de una matriz multidimensional, se aplana (sección 9.12) y, después, se trata
como una matriz unidimensional.
Un valor de tipo NULL se convierte en la cadena vacía.
Un valor de tipo bloque de script se convierte en una cadena que contiene el texto
de ese bloque sin los caracteres delimitadores { y }.
Para un valor de tipo de enumeración, el resultado es una cadena que contiene el
nombre de cada constante de enumeración codificada en ese valor, separados por
comas.
Para otros valores de tipo de referencia, si el tipo de referencia admite dicha
conversión, es la que se usa. De lo contrario, la conversión es errónea.

La cadena utilizada para representar el valor de un elemento que es una matriz tiene el
formato System.type[] , System.type[,] , y así sucesivamente. Para otros tipos de
referencia, se llama al método ToString . Para otros tipos enumerables, el valor de
origen se trata como una matriz unidimensional.
6.9 Conversión a array
Las reglas para convertir cualquier valor en un tipo array son las siguientes:

Es posible que el tipo de destino no sea una matriz multidimensional.


Un valor de tipo NULL se conserva tal cual es.
Para un valor escalar distinto de $null o un valor de tipo tabla hash, se crea una
matriz de 1 elemento cuyo valor es el escalar después de realizar la conversión al
tipo de elemento de destino.
Para un valor de matriz unidimensional, se crea una matriz del tipo de destino y
cada elemento se copia con la conversión de la matriz de origen al elemento
correspondiente de la matriz de destino.
Para un valor de matriz multidimensional, esa matriz se aplana primero
(sección 9.12) y, después, se trata como un valor de matriz unidimensional.
Un valor de cadena se convierte en una matriz de caracteres de la misma longitud
con caracteres sucesivos de la cadena que ocupa las posiciones correspondientes
en la matriz.

Para otros tipos enumerables, se crea una matriz de 1 elemento cuyo valor es el
elemento correspondiente después de realizar la conversión al tipo de elemento de
destino, si existe dicha conversión. De lo contrario, la conversión es errónea.

6.10 Conversión a xml


El objeto se convierte al tipo string y, después, en un objeto de documento XML de tipo
xml .

6.11 Conversión a regex


Una expresión que designa un valor de tipo string se puede convertir al tipo regex .

6.12 Conversión a scriptblock


Las reglas para convertir cualquier valor al tipo scriptblock son las siguientes:

Un valor de cadena se trata como el nombre de un comando, seguido


opcionalmente de los argumentos de una llamada a ese comando.

6.13 Conversión a tipos de enumeración


Las reglas para convertir cualquier valor en un tipo de enumeración son las siguientes:

Un valor de tipo string que contiene uno de los valores con nombre (teniendo en
cuenta mayúsculas y minúsculas) para un tipo de enumeración se convierte en ese
valor con nombre.
Un valor de tipo string que contiene una lista separada por comas de valores con
nombre (teniendo en cuenta mayúsculas y minúsculas) para un tipo de
enumeración se convierte en el OR bit a bit de todos los valores con nombre.

6.14 Conversión a otros tipos de referencia


Las reglas para convertir cualquier valor en un tipo de referencia distinto de un tipo
array o string son las siguientes:

Un valor de tipo NULL se conserva tal cual es.


De lo contrario, el comportamiento está definido por la implementación.

Aquí entran en juego una serie de piezas de maquinaria. Incluyen el posible uso de
constructores de argumento único o constructores predeterminados si el valor es una
tabla hash, operadores de conversión implícitos y explícitos, y métodos Parse para el
tipo de destino; el uso de Convert.ConvertTo y el mecanismo de conversión de ETS.

6.15 Conversiones aritméticas habituales


Si ninguno de los operandos designa un valor con tipo numérico:

Si el operando izquierdo designa un valor de tipo bool, la conversión será errónea.


De lo contrario, todos los operandos que designan el valor $null se convierten en
cero de tipo int y el proceso continúa con las conversiones numéricas que se
enumeran a continuación.
De lo contrario, si el operando izquierdo designa un valor de tipo char y el
operando derecho designa un valor de tipo bool, la conversión será errónea.
De lo contrario, si el operando izquierdo designa un valor de tipo string pero no
representa un número (sección 6.16), la conversión será errónea.
De lo contrario, si el operando derecho designa un valor de tipo string pero no
representa un número (sección 6.16), la conversión será errónea.
De lo contrario, todos los operandos que designan valores de tipo string se
convierten en números (sección 6.16) y el proceso continúa con las conversiones
numéricas que se enumeran a continuación.
De lo contrario, la conversión es errónea.

Conversiones numéricas:
Si un operando designa un valor de tipo decimal, el valor que designa el otro
operando se convierte a ese tipo, si es necesario. El resultado tiene el tipo decimal.
De lo contrario, si un operando designa un valor de tipo double, el valor que
designa el otro operando se convierte a ese tipo, si es necesario. El resultado tiene
el tipo double.
De lo contrario, si un operando designa un valor de tipo float, los valores que
designan ambos operandos se convierten al tipo double, si es necesario. El
resultado tiene el tipo double.
De lo contrario, si un operando designa un valor de tipo long, el valor que designa
el otro valor de operando se convierte a ese tipo, si es necesario. El resultado tiene
el tipo first en la secuencia long y double que puede representar su valor.
De lo contrario, los valores que designan ambos operandos se convierten al tipo
int, si es necesario. El resultado tiene el tipo first de la secuencia int, long, double
que puede representar su valor sin truncamiento.

6.16 Conversión de cadena a tipo numérico


En función de su contenido, una cadena se puede convertir explícita o implícitamente en
un valor numérico. Concretamente, puede:

Una cadena vacía se convierte en el valor cero.


Se omiten los espacios iniciales y finales, pero es posible que una cadena no
conste solo de espacios.
Una cadena que contiene solo espacios en blanco o terminadores de línea se
convierte al valor cero.
Se permite un signo + o - inicial.
Un número entero puede tener un prefijo hexadecimal (0x o 0X).
Se permite un exponente con signo opcional.
No se permiten sufijos de tipo ni multiplicadores.
Las cadenas que distinguen mayúsculas de minúsculas "-Infinity", "Infinity" y "NaN"
se reconocen como los valores -∞, +∞ y NaN, respectivamente.

6.17 Conversión durante el enlace de


parámetros
Para obtener información acerca del enlace de parámetros, consulte §8.14.

Cuando el valor de una expresión se enlaza a un parámetro, hay consideraciones de


conversión adicionales, tal como se describe a continuación:
Si el tipo de parámetro es bool o switch (secciones 4.2.5 y 8.10.5) y el parámetro
no tiene ningún argumento, el valor del parámetro en el comando al que se llama
se establece en $true . Si el tipo de parámetro es distinto de bool o switch, se
produce un error en un parámetro que no tiene ningún argumento.
Si el tipo de parámetro es switch y el valor del argumento es $null , el valor del
parámetro se establece en $false .
Si el tipo de parámetro es object o es el mismo que el tipo del argumento, el valor
del argumento se pasa sin conversión.
Si el tipo de parámetro no es object o scriptblock, se evalúa un argumento que
tiene el tipo scriptblock y su resultado se pasa como el valor del argumento. (Esto
se conoce como enlace de bloque de script retrasado). Si el tipo de parámetro es
object o scriptblock, un argumento que tiene el tipo scriptblock se pasa tal cual
está.
Si el tipo de parámetro es una colección de tipo T2 y el argumento es un escalar
de tipo T1, ese escalar se convierte en una colección de tipo T2 que contiene un
elemento. Si es necesario, el valor escalar se convierte al tipo T2 con las reglas de
conversión de esta sección.
Si el tipo de parámetro es un tipo escalar distinto de object y el argumento es una
colección, el argumento es erróneo.
Si el tipo de parámetro esperado es una colección de tipo T2 y el argumento es
una colección de tipo T1, el argumento se convierte en una colección de tipo T2
con la misma longitud que la colección de argumentos. Si es necesario, los valores
del elemento de colección de argumentos se convierten al tipo T2 mediante las
reglas de conversión de esta sección.
Si los pasos anteriores y las conversiones especificadas más arriba en este capítulo
no son suficientes, se aplican las reglas de la sección 6.18. Si estos fallan, se
producirá un error en el enlace de parámetros.

6.18 Conversión de .NET


Para una conversión implícita, primero se intenta realizar conversiones integradas de
PowerShell. Si estas no pueden resolver la conversión, se probarán los convertidores
siguientes personalizados de .NET, en orden, de arriba abajo. Si se encuentra una
conversión pero produce una excepción, se producirá un error en la conversión.

PSTypeConverter: hay dos maneras de asociar la implementación de la clase


PSTypeConverter a su clase de destino: mediante el archivo de configuración de
tipos (types.ps1xml) o aplicando el atributo
System.ComponentModel.TypeConverterAttribute a la clase de destino. Consulte la
documentación del SDK de PowerShell para obtener más información.
TypeConverter: este tipo de CLR proporciona una forma unificada para convertir
tipos de valores a otros tipos, así como para acceder a valores estándar y
subpropiedades. El tipo de convertidor más común es aquel que convierte a una
representación de texto y desde esta. El convertidor de tipos de una clase está
enlazado a la clase con un elemento
System.ComponentModel.TypeConverterAttribute . A menos que se invalide este

atributo, todas las clases que heredan de esta clase usan el mismo convertidor de
tipos que la clase base. Consulte la documentación del SDK de PowerShell y de
Microsoft .NET Framework para obtener más información.

Método Parse: si el tipo de origen es string y el tipo de destino tiene un método


denominado Parse , se llama a ese método para realizar la conversión.

Constructores: si el tipo de destino tiene un constructor que toma un único


argumento cuyo tipo es el del tipo de origen, se llama a ese constructor para
realizar la conversión.

Operador de conversión implícita: si el tipo de origen tiene un operador de


conversión implícito que se convierte al tipo de destino, se llama a ese operador
para realizar la conversión.

Operador de conversión explícita: si el tipo de origen tiene un operador de


conversión explícito que se convierte al tipo de destino, se llama a ese operador
para realizar la conversión. Si el tipo de destino tiene un operador de conversión
explícito que se convierte desde el tipo de origen, se llama a ese operador para
realizar la conversión.

IConvertable: se llama a System.Convert.ChangeType para realizar la conversión.

6.19 Conversión a ordered


Las reglas para convertir cualquier valor en el pseudotipo ordered son las siguientes:

Si el valor es un literal hash (sección 2.3.5.6), el resultado es un objeto con un tipo


definido por la implementación que se comporta como una tabla hash y el orden
de las claves coincide con el orden especificado en el literal hash.
De lo contrario, el comportamiento está definido por la implementación.

Solo los literales hash (sección 2.3.5.6) se pueden convertir en ordered. El resultado es
una instancia de System.Collections.Specialized.OrderedDictionary .

6.20 Conversión a pscustomobject


Las reglas para convertir cualquier valor en el pseudotipo pscustomobject son las
siguientes:

Un valor de tipo hashtable se convierte en un objeto de PowerShell. Cada clave de


la tabla hash se convierte en NoteProperty con el valor correspondiente.
De lo contrario, el comportamiento está definido por la implementación.

La conversión siempre se permite, pero no cambia el tipo del valor.


7. Expresiones
Artículo • 16/03/2022

Sintaxis:

Syntax

expression:
logical-expression

Descripción:

Una expresión es una secuencia de operadores y operandos que designa un método,


una función, una ubicación grabable o un valor; especifica el cálculo de un valor;
produce uno o varios efectos secundarios o realiza alguna combinación de ellos. Por
ejemplo,

El literal 123 es una expresión que designa el valor int 123.


La expresión 1,2,3,4 designa el objeto de matriz de 4 elementos con los valores
mostrados.
La expresión 10.4 * $a especifica un cálculo.
La expresión $a++ produce un efecto secundario.
La expresión $a[$i--] = $b[++$j] realiza una combinación de estas cosas.

Excepto como se especifica para algunos operadores, no se especifican el orden de


evaluación de los términos de una expresión ni el orden en que tienen lugar los efectos
secundarios. Entre los ejemplos de comportamiento no especificado se incluyen los
siguientes: $i++ + $i , $i + --$i y $w[$j++] = $v[$j] .

Una implementación de PowerShell puede proporcionar compatibilidad con tipos


definidos por el usuario y esos tipos pueden tener operaciones definidas en ellos. Todos
los detalles de estos tipos y operaciones están definidos por la implementación.

Una expresión de nivel superior es aquella que no forma parte de alguna expresión
mayor. Si una expresión de nivel superior contiene un operador de efecto secundario, el
valor de esa expresión no se escribe en la canalización; de lo contrario, sí que se escribe.
Vea la sección 7.1.1 para obtener una explicación detallada de esto.

Normalmente, una expresión que designa una colección (sección 4) se enumera en sus
elementos constituyentes cuando se usa el valor de esa expresión. Pero este no es el
caso cuando la expresión es una invocación de cmdlet. Por ejemplo,
PowerShell

$x = 10,20,30
$a = $($x; 99) # $a.Length is 4

$x = New-Object 'int[]' 3
$a = $($x; 99) # equivalent, $a.Length is 4

$a = $(New-Object 'int[]' 3; 99) # $a.Length is 2

En los dos primeros usos del operador $(...) , la expresión que designa la colección es
la variable $x , que se enumera dando como resultado tres valores int , más el elemento
int 99. Pero en el tercer caso, la expresión es una llamada directa a un cmdlet, por lo
que el resultado no se enumera y $a es una matriz de dos elementos: int[3] y int .

Si PowerShell no define una operación, se inspecciona el tipo del valor que designa el
operando izquierdo para ver si tiene un método op_<operation> correspondiente.

7.1. Expresiones primarias


Sintaxis:

Syntax

primary-expression:
value
member-access
element-access
invocation-expression
post-increment-expression
post-decrement-expression

value:
parenthesized-expression
sub-expression
array-expression
script-block-expression
hash-literal-expression
literal
type-literal
variable

7.1.1 Paréntesis de agrupación


Sintaxis:
 Sugerencia

La notación ~opt~ en las definiciones de sintaxis indica que la entidad léxica es


opcional en la sintaxis.

Syntax

parenthesized-expression:
( new-lines~opt~ pipeline new-lines~opt~ )

Descripción:

Una expresión entre paréntesis es una expresión principal cuyo tipo y valor son los
mismos que los de la expresión sin paréntesis. Si la expresión designa una variable, la
expresión entre paréntesis designa esa misma variable. Por ejemplo, $x.m and ($x).m
son equivalentes.

Los paréntesis de agrupación se pueden usar en una expresión para documentar la


prioridad y la asociatividad predeterminadas de esa expresión. También se pueden usar
para invalidar esa prioridad y asociatividad predeterminadas. Por ejemplo,

PowerShell

4 + 6 * 2 # 16
4 + (6 * 2) # 16 document default precedence
(4 + 6) * 2 # 20 override default precedence

Normalmente, los paréntesis de agrupación en el nivel superior son redundantes. Pero


este no siempre es el caso. Considere el ejemplo siguiente:

PowerShell

2,4,6 # Length 3; values 2,4,6


(2,4),6 # Length 2; values [object[]],int

En el segundo caso, los paréntesis cambian la semántica, lo que da lugar a una matriz
cuyos dos elementos son una matriz de 2 ints y el valor int escalar 6.

Esta es otra excepción:

PowerShell

23.5/2.4 # pipeline gets 9.79166666666667


$a = 1234 * 3.5 # value not written to pipeline
$a # pipeline gets 4319

En el primer y tercer caso, el valor del resultado se escribe en la canalización. Pero


aunque se evalúa la expresión en el segundo caso, el resultado no se escribe en la
canalización debido a la presencia del operador de efecto secundario = en el nivel
superior. (La eliminación de la parte $a = permite el valor que se va a escribir, ya que *
no es un operador de efecto secundario).

Para impedir que un valor de cualquier expresión que no contenga efectos secundarios
de nivel superior se escriba en la canalización, descártelo explícitamente, tal como se
muestra a continuación:

PowerShell

# None of these value are written to pipeline


[void](23.5/2.4)
[void]$a
$null = $a
$a > $null

Para escribir en la canalización el valor de cualquier expresión que contenga efectos


secundarios de nivel superior, incluya esa expresión entre paréntesis, tal como se
muestra a continuación:

PowerShell

($a = 1234 * 3.5) # pipeline gets 4319

De esta forma, los paréntesis de agrupación en este caso no son redundantes.

En el ejemplo siguiente, tenemos la sustitución de variables (§2.3.5.2) que tiene lugar en


un literal de cadena:

PowerShell

">$($a = -23)<" # value not written to pipeline, get


><
">$(($a = -23))<" # pipeline gets >-23<

En el primer caso, los paréntesis representan los delimitadores de una subexpresión que
no agrupan paréntesis y, como la expresión de nivel superior contiene un operador de
efecto secundario, el valor de la expresión no se escribe en la canalización. Por supuesto,
los caracteres > y < todavía están escritos. Si se agregan paréntesis de agrupación (tal
como se muestra en el segundo caso), la escritura está habilitada.
En los ejemplos siguientes se incluyen operadores de efecto secundario de nivel
superior:

PowerShell

$a = $b = 0 # value not written to pipeline


$a = ($b = 0) # value not written to pipeline
($a = ($b = 0)) # pipeline gets 0

++$a # value not written to pipeline


(++$b) # pipeline gets 1

$a-- # value not written to pipeline


($b--) # pipeline gets 1

El uso de paréntesis de agrupación en torno a una expresión que no contiene efectos


secundarios de nivel superior hace que esos paréntesis sean redundantes. Por ejemplo:

PowerShell

$a # pipeline gets 0
($a) # no side effect, so () redundant

Considere el ejemplo siguiente que tiene dos efectos secundarios, ninguno de los cuales
está en el nivel superior:

PowerShell

12.6 + ($a = 10 - ++$b) # pipeline gets 21.6.

El resultado se escribe en la canalización, ya que la expresión de nivel superior no tiene


efectos secundarios.

7.1.2 Acceso a miembros


Sintaxis:

Syntax

member-access: Note no whitespace is allowed after primary-expression.


primary-expression . member-name
primary-expression :: member-name

Descripción:
El operador . se usa para seleccionar un miembro de instancia de un objeto o una clave
de Hashtable , El operando izquierdo debe designar un objeto y el derecho un miembro
de instancia accesible.

El operando derecho designa un miembro de instancia accesible dentro del tipo del
objeto que ha designado el operando izquierdo o, si el operando izquierdo designa una
matriz, el operando derecho designa miembros de instancia accesibles dentro de cada
elemento de la matriz.

No se permite el espacio en blanco antes del operador . .

Este operador es asociativo a la izquierda.

El operador :: se usa para seleccionar un miembro estático de un tipo determinado. El


operando izquierdo debe designar un tipo y el derecho un miembro estático accesible
dentro de ese tipo.

No se permite el espacio en blanco antes del operador :: .

Este operador es asociativo a la izquierda.

Si el operando derecho designa una ubicación grabable dentro del tipo del objeto que
designa el operando izquierdo, toda la expresión designará una ubicación grabable.

Ejemplos:

PowerShell

$a = 10, 20, 30
$a.Length # get instance property

(10, 20, 30).Length

$property = "Length"
$a.$property # property name is a variable

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123


}
$h1.FirstName # designates the key FirstName
$h1.Keys # gets the collection of keys

[int]::MinValue # get static property


[double]::PositiveInfinity # get static property
$property = "MinValue"
[long]::$property # property name is a variable

foreach ($t in [byte], [int], [long]) {


$t::MaxValue # get static property
}
$a = @{ID = 1 }, @{ID = 2 }, @{ID = 3 }
$a.ID # get ID from each element in the array

7.1.3 Expresiones de invocación


Sintaxis:

Syntax

invocation-expression: Note no whitespace is allowed after primary-


expression.
primary-expression . member-name argument-list
primary-expression :: member-name argument-list

argument-list:
( argument-expression-list~opt~ new-lines~opt~ )

Descripción:

Una expresión de invocación llama al método que designa la expresión primaria.nombre


de miembro o expresión primaria::nombre de miembro. Los paréntesis de lista de
argumentos contienen una lista de expresiones posiblemente vacía, separada por comas,
que designa los argumentos cuyos valores se pasan al método. Antes de llamar al
método, los argumentos se evalúan y convierten según las reglas de §6, en caso
necesario, para que coincidan con los tipos que espera el método. El orden de
evaluación de expresión primaria.nombre de miembro, expresión primaria::nombre de
miembro y los argumentos no se han especificado.

Este operador es asociativo a la izquierda.

El tipo del resultado de una expresión de invocación es un designador de método


(sección 4.5.24).

Ejemplos:

PowerShell

[math]::Sqrt(2.0) # call method with argument 2.0


[char]::IsUpper("a") # call method
$b = "abc#$%XYZabc"
$b.ToUpper() # call instance method

[math]::Sqrt(2) # convert 2 to 2.0 and call method


[math]::Sqrt(2D) # convert 2D to 2.0 and call method
[math]::Sqrt($true) # convert $true to 1.0 and call method
[math]::Sqrt("20") # convert "20" to 20 and call method
$a = [math]::Sqrt # get method descriptor for Sqrt
$a.Invoke(2.0) # call Sqrt via the descriptor
$a = [math]::("Sq"+"rt") # get method descriptor for Sqrt
$a.Invoke(2.0) # call Sqrt via the descriptor
$a = [char]::ToLower # get method descriptor for ToLower
$a.Invoke("X") # call ToLower via the descriptor

7.1.4 Acceso de elemento


Sintaxis:

Syntax

element-access: Note no whitespace is allowed between primary-expression and


[.
primary-expression [ new-lines~opt~ expression new-lines~opt~ ]

Descripción:

No debe haber ningún espacio en blanco entre expresión primaria y el corchete


izquierdo ( [ ).

7.1.4.1 Subíndice de una matriz

Descripción:

Las variables se analizan en detalle en la sección 9. Si expresión es una matriz


unidimensional, vea la sección 7.1.4.5.

Cuando expresión primaria designa una matriz unidimensional A, el operador []


devuelve el elemento ubicado en A[0 + expression] después de que el valor de
expresión se haya convertido en int . El resultado tiene el tipo de elemento de la matriz
que se está subindizando. Si expresión es negativo, A[expression] designa el elemento
ubicado en A[A.Length + expression] .

Cuando expresión primaria designa una matriz bidimensional B, el operador []


devuelve el elemento situado en B[0 + row,0 + column] después de que el valor de los
componentes de fila y columna de expresión (que se especifican como una lista
separada por comas) se haya convertido en int . El resultado tiene el tipo de elemento
de la matriz que se está subindizando. A diferencia de una matriz unidimensional, las
posiciones negativas no tienen ningún significado especial.
Cuando expresión primaria designa una matriz de tres o más dimensiones, se aplican las
reglas para matrices bidimensionales y las posiciones de dimensión se especifican como
una lista de valores separados por comas.

Si se intenta obtener acceso de lectura en un elemento no existente, el resultado es


$null . Es un error escribir en un elemento no existente.

Para una expresión de subíndice de matriz multidimensional, no se especifica el orden


de evaluación de las expresiones de posición de dimensión. Por ejemplo, dada una
matriz tridimensional $a , el comportamiento de $a[$i++,$i,++$i] no se especifica.

Si expresión es una matriz, vea la sección 7.1.4.5.

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

$a = [int[]](10,20,30) # [int[]], Length 3


$a[1] # returns int 20
$a[20] # no such position, returns $null
$a[-1] # returns int 30, i.e., $a[$a.Length-1]
$a[2] = 5 # changes int 30 to int 5
$a[20] = 5 # implementation-defined behavior

$a = New-Object 'double[,]' 3,2


$a[0,0] = 10.5 # changes 0.0 to 10.5
$a[0,0]++ # changes 10.5 to 10.6

$list = ("red",$true,10),20,(1.2, "yes")


$list[2][1] # returns string "yes"

$a = @{ A = 10 },@{ B = $true },@{ C = 123.45 }


$a[1]["B"] # $a[1] is a Hashtable, where B is a key

$a = "red","green"
$a[1][4] # returns string "n" from string in $a[1]

Si se intenta obtener acceso de escritura a un elemento no existente, se produce una


excepción IndexOutOfRange.

7.1.4.2 Subíndice de una cadena

Descripción:
Cuando primary-expression designa una cadena S, el operador [] devuelve el carácter
ubicado en la posición de base cero que indica expression, como un char. Si expression
es mayor o igual que la longitud de esa cadena, el resultado es $null . Si expression es
negativo, S[expression] designa el elemento ubicado en S[S.Length + expression] .

Ejemplos:

PowerShell

$s = "Hello" # string, Length 5, positions 0-4


$c = $s[1] # returns "e" as a string
$c = $s[20] # no such position, returns $null
$c = $s[-1] # returns "o", i.e., $s[$s.Length-1]

7.1.4.3 Subíndice de una tabla hash


Descripción:

Cuando primary-expression designa una tabla hash, el operador [] devuelve los valores
asociados a las claves que designa expression. El tipo de expression no está restringido.

Cuando expression es un nombre de clave único, el resultado es el valor asociado y tiene


ese tipo, a menos que no exista dicha clave, en cuyo caso el resultado es $null . Si
$null se usa como clave, el comportamiento está definido por la implementación. Si

expresión es una matriz de nombres de clave, vea la sección 7.1.4.5.

Si expresión es una matriz, vea la sección 7.1.4.5.

Ejemplos:

PowerShell

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }


$h1['FirstName'] # the value associated with key FirstName
$h1['BirthDate'] # no such key, returns $null

$h1 = @{ 10 = "James"; 20.5 = "Anderson"; $true = 123 }


$h1[10] # returns value "James" using key 10
$h1[20.5] # returns value "Anderson" using key 20.5
$h1[$true] # returns value 123 using key $true

Cuando expresión es un nombre de clave único, si $null se usa como el único valor para
subindizar una tabla hash, se genera una excepción NullArrayIndex.
7.1.4.4 Subíndice de un documento XML
Descripción:

Cuando expresión primaria designa un objeto de tipo xml, expresión se convierte en


cadena, si es necesario, y el operador [] devuelve el primer elemento secundario con el
nombre que especifica expresión. El tipo de expresión debe ser cadena. El tipo del
resultado está definido por la implementación. El resultado se puede subindizar para
devolver su primer elemento secundario. Si no existe ningún elemento secundario con
el nombre que especifica expresión, el resultado es $null . El resultado no designa una
ubicación grabable.

Ejemplos:

PowerShell

$x = [xml]@"
<Name>
<FirstName>Mary</FirstName>
<LastName>King</LastName>
</Name>
"@

$x['Name'] # refers to the element Name


$x['Name']['FirstName'] # refers to the element FirstName within Name
$x['FirstName'] # No such child element at the top level, result
is `$null`

El tipo del resultado es System.Xml.XmlElement o System.String .

7.1.4.5 Generación de segmentos de matriz

Cuando expresión primaria designa un objeto de un tipo enumerable (sección 4) o una


tabla hash, y expresión es una matriz unidimensional, el resultado es un segmento de
matriz (sección 9.9) que contiene los elementos de expresión primaria que designan los
elementos de expresión.

En el caso de una tabla hash, el segmento de matriz contiene los valores asociados a las
claves proporcionadas, a menos que no exista dicha clave, en cuyo caso el elemento
correspondiente es $null . Si $null se usa como cualquier nombre de clave, el
comportamiento está definido por la implementación.

Ejemplos:

PowerShell
$a = [int[]](30,40,50,60,70,80,90)
$a[1,3,5] # slice has Length 3, value 40,60,80
++$a[1,3,5][1] # preincrement 60 in array 40,60,80
$a[,5] # slice with Length 1
$a[@()] # slice with Length 0
$a[-1..-3] # slice with Length 0, value 90,80,70
$a = New-Object 'int[,]' 3,2
$a[0,0] = 10; $a[0,1] = 20; $a[1,0] = 30
$a[1,1] = 40; $a[2,0] = 50; $a[2,1] = 60
$a[(0,1),(1,0)] # slice with Length 2, value 20,30, parens needed
$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }
$h1['FirstName'] # the value associated with key FirstName
$h1['BirthDate'] # no such key, returns $null
$h1['FirstName','IDNum'] # returns [object[]], Length 2 (James/123)
$h1['FirstName','xxx'] # returns [object[]], Length 2 (James/$null)
$h1[$null,'IDNum'] # returns [object[]], Length 1 (123)

Windows PowerShell: cuando expresión es una colección de dos o más nombres de


clave, si $null se usa como cualquier nombre de clave, esa clave se omite y no tiene
ningún elemento correspondiente en la matriz resultante.

7.1.5 Operadores de incremento y decremento postfijos


Sintaxis:

Syntax

post-increment-expression:
primary-expression ++

post-decrement-expression:
primary-expression dashdash

dashdash:
--

Descripción:

La expresión primaria debe designar una ubicación grabable que tenga un valor de tipo
numérico (sección 4) o el valor $null . Si el valor que designa el operando es $null , ese
valor se convierte al tipo int y al valor cero antes de que se evalúe el operador. El tipo
del valor que designa expresión primaria puede cambiar cuando se almacena el
resultado. Vea la sección 7.11 para obtener información sobre el cambio de tipos
mediante la asignación.

El resultado que genera el operador postfijo ++ es el valor que designa el operando.


Una vez obtenido ese resultado, el valor que designa el operando se incrementa en 1
del tipo adecuado. El tipo del resultado de la expresión E++ es el mismo que para el
resultado de la expresión E + 1 (sección 7.7).

El resultado que genera el operador postfijo -- es el valor que designa el operando.


Una vez obtenido ese resultado, el valor que designa el operando se reduce en 1 del
tipo adecuado. El tipo del resultado de la expresión E-- es el mismo que para el
resultado de la expresión E - 1 (sección 7.7).

Estos operadores son asociativos a la izquierda.

Ejemplos:

PowerShell

$i = 0 # $i = 0
$i++ # $i is incremented by 1
$j = $i-- # $j takes on the value of $i before the decrement

$a = 1,2,3
$b = 9,8,7
$i = 0
$j = 1
$b[$j--] = $a[$i++] # $b[1] takes on the value of $a[0], then $j is
# decremented, $i incremented

$i = 2147483647 # $i holds a value of type int


$i++ # $i now holds a value of type double because
# 2147483648 is too big to fit in type int

[int]$k = 0 # $k is constrained to int


$k = [int]::MaxValue # $k is set to 2147483647
$k++ # 2147483648 is too big to fit, imp-def bahavior

$x = $null # target is unconstrained, $null goes to [int]0


$x++ # value treated as int, 0->1

Operador 7.1.6 $(...)


Sintaxis:

Syntax

sub-expression:
$( new-lines~opt~ statement-list~opt~ new-lines~opt~ )

Descripción:
Si se omite lista de instrucciones, el resultado es $null . De lo contrario, se evalúa lista de
instrucciones. Los objetos escritos en la canalización como parte de la evaluación se
recopilan en una matriz unidimensional sin restricciones, en orden. Si la matriz de
objetos recopilados está vacía, el resultado es $null . Si la matriz de objetos recopilados
contiene un único elemento, el resultado es ese elemento; De lo contrario, el resultado
es la matriz unidimensional sin restricciones de los resultados recopilados.

Ejemplos:

PowerShell

$j = 20
$($i = 10) # pipeline gets nothing
$(($i = 10)) # pipeline gets int 10
$($i = 10; $j) # pipeline gets int 20
$(($i = 10); $j) # pipeline gets [object[]](10,20)
$(($i = 10); ++$j) # pipeline gets int 10
$(($i = 10); (++$j)) # pipeline gets [object[]](10,22)
$($i = 10; ++$j) # pipeline gets nothing
$(2,4,6) # pipeline gets [object[]](2,4,6)

Operador 7.1.7 @(...)


Sintaxis:

Syntax

array-expression:
@( new-lines~opt~ statement-list~opt~ new-lines~opt~ )

Descripción:

Si se omite lista de instrucciones, el resultado es una matriz unidimensional sin


restricciones de longitud cero. De lo contrario, se evalúa lista de instrucciones y los
objetos escritos en la canalización como parte de la evaluación se recopilan en una
matriz unidimensional sin restricciones, en orden. El resultado es la matriz
unidimensional sin restricciones (posiblemente vacía).

Ejemplos:

PowerShell

$j = 20
@($i = 10) # 10 not written to pipeline, result is array of 0
@(($i = 10)) # pipeline gets 10, result is array of 1
@($i = 10; $j) # 10 not written to pipeline, result is array of 1
@(($i = 10); $j) # pipeline gets 10, result is array of 2
@(($i = 10); ++$j) # pipeline gets 10, result is array of 1
@(($i = 10); (++$j)) # pipeline gets both values, result is array of 2
@($i = 10; ++$j) # pipeline gets nothing, result is array of 0

$a = @(2,4,6) # result is array of 3


@($a) # result is the same array of 3
@(@($a)) # result is the same array of 3

7.1.8 Expresión de bloque de script


Sintaxis:

Syntax

script-block-expression:
{ new-lines~opt~ script-block new-lines~opt~ }

script-block:
param-block~opt~ statement-terminators~opt~ script-block-body~opt~

script-block-body:
named-block-list
statement-list

Descripción:

bloque de parámetros se describe en la sección 8.10.9. lista de bloques con nombre se


describe en la sección 8.10.7.

Un bloque de script es un bloque de instrucciones sin nombre que se puede usar como
una sola unidad. Los bloques de script se pueden usar para invocar un bloque de código
como si fuera un solo comando o se pueden asignar a variables que se pueden ejecutar.

Se ejecuta lista de bloques con nombre o lista de instrucciones, y el tipo y los valores del
resultado son el tipo y los valores de los resultados de esos conjuntos de instrucciones.

Una expresión de bloque de script tiene el tipo scriptblock (sección 4.3.7).

Si se omite bloque de parámetros, los argumentos pasados al bloque de script están


disponibles mediante $args (sección 8.10.1).

Durante el enlace de parámetros, un bloque de script se puede pasar como un objeto


de bloque de script o como resultado después de evaluar el bloque de script. Para
obtener más información, vea la sección 6.17.
7.1.9 Expresión literal hash
Sintaxis:

Syntax

hash-literal-expression:
@{ new-lines~opt~ hash-literal-body~opt~ new-lines~opt~ }

hash-literal-body:
hash-entry
hash-literal-body statement-terminators hash-entry

hash-entry:
key-expression = new-lines~opt~ statement

key-expression:
simple-name
unary-expression

statement-terminators:
statement-terminator
statement-terminators statement-terminator

statement-terminator:
;
new-line-character

Descripción:

Una expresión literal hash se usa para crear una tabla hash (sección 10) de cero o más
elementos, cada uno de los cuales es un par clave-valor.

La clave puede tener cualquier tipo excepto el tipo NULL. Los valores asociados pueden
tener cualquier tipo, incluido el tipo NULL, y cada uno de esos valores puede ser
cualquier expresión que designe el valor deseado, incluido $null .

El orden de los pares clave-valor no es significativo.

Ejemplos:

PowerShell

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }


$last = "Anderson"; $IDNum = 120
$h2 = @{ FirstName = "James"; LastName = $last; IDNum = $IDNum + 3 }
$h3 = @{ }
$h4 = @{ 10 = "James"; 20.5 = "Anderson"; $true = 123 }
que crea dos tablas hash, $h1 y $h2 , cada una de las cuales contiene tres pares clave-
valor; y una tercera, $h3 , que está vacía. La tabla hash $h4 tiene claves de varios tipos.

7.1.10 Expresión literal de tipo


Sintaxis:

Syntax

type-literal:
[ type-spec ]

type-spec:
array-type-name new-lines~opt~ dimension~opt~ ]
generic-type-name new-lines~opt~ generic-type-arguments ]
type-name

dimension:
,
dimension ,

generic-type-arguments:
type-spec new-lines~opt~
generic-type-arguments , new-lines~opt~ type-spec

array-type-name:
type-name [

generic-type-name:
type-name [

Descripción:

Un literal de tipo se representa en una implementación mediante algún tipo subyacente


no especificado. Como resultado, un nombre de tipo es un sinónimo de su tipo
subyacente.

Los literales de tipo se usan en varios contextos:

Especificación de una conversión explícita (sección 6, sección 7.2.9)


Creación de una matriz restringida por tipos (sección 9.4)
Acceso a los miembros estáticos de un objeto (sección 7.1.2)
Especificación de una restricción de tipo en una variable (sección 5.3) o en un
parámetro de función (sección 8.10.2)

Ejemplos:
Algunos ejemplos de literales de tipo son [int] , [object[] y [int[,,]] . Un tipo de pila
genérico (sección 4.4) especializado para contener cadenas podría escribirse como
[Stack[string]] y un tipo de diccionario genérico especializado para contener claves

int con valores de cadena asociados podría escribirse como [Dictionary[int,string]] .

El tipo de un literal de tipo es System.Type . El nombre completo del tipo Stack[string]


sugerido anteriormente es System.Collections.Generic.Stack[int] . El nombre completo
del tipo Dictionary[int,string] sugerido anteriormente es
System.Collections.Generic.Dictionary[int,string] .

7.2 Operadores unarios


Sintaxis:

Syntax

unary-expression:
primary-expression
expression-with-unary-operator

expression-with-unary-operator:
, new-lines~opt~ unary-expression
-not new-lines~opt~ unary-expression
! new-lines~opt~ unary-expression
-bnot new-lines~opt~ unary-expression
+ new-lines~opt~ unary-expression
dash new-lines~opt~ unary-expression
pre-increment-expression
pre-decrement-expression
cast-expression
-split new-lines~opt~ unary-expression
-join new-lines~opt~ unary-expression

dash:*
- (U+002D)
EnDash character (U+2013)
EmDash character (U+2014)
Horizontal bar character (U+2015)

pre-increment-expression:
++ new-lines~opt~ unary-expression

pre-decrement-expression:
dashdash new-lines~opt~ unary-expression

cast-expression:
type-literal unary-expression
dashdash:
dash dash

7.2.1 Operador de coma unario


Descripción:

Este operador crea una matriz unidimensional sin restricciones que tiene un elemento,
cuyo tipo y valor son los de expresión unaria.

Este operador es asociativo a la derecha.

Ejemplos:

PowerShell

$a = ,10 # create an unconstrained array of 1 element, $a[0],


# which has type int

$a = ,(10,"red") # create an unconstrained array of 1 element,


$a[0],
# which is an unconstrained array of 2 elements,
# $a[0][0] an int, and $a[0][1] a string

$a = ,,10 # create an unconstrained array of 1 element, which is


# an unconstrained array of 1 element, which is an int
# $a[0][0] is the int. Contrast this with @(@(10))

7.2.2 Operador NOT lógico


Descripción:

El operador -not convierte el valor que designa expresión unaria al tipo bool
(sección 6,2), si es necesario, y genera un resultado de ese tipo. Si el valor de expresión
unaria es True, el resultado es False, y viceversa. Operador ! es una ortografía alternativa
para -not.

Este operador es asociativo a la derecha.

Ejemplos:

PowerShell

-not $true # False


-not -not $false # False
-not 0 # True
-not 1.23 # False
!"xyz" # False

7.2.3 Operador NOT bit a bit


Descripción:

El operador -bnot convierte el valor que designa expresión unaria en un tipo entero
(sección 6,4), si es necesario. Si el valor convertido se puede representar en el tipo int,
ese será el tipo del resultado. De otra manera, si el valor convertido se puede
representar en el tipo long, ese será el tipo del resultado. De lo contrario, la expresión
tiene un formato incorrecto. El valor resultante es el complemento de uno del valor
convertido.

Este operador es asociativo a la derecha.

Ejemplos:

PowerShell

-bnot $true # int with value 0xFFFFFFFE


-bnot 10 # int with value 0xFFFFFFF5
-bnot 2147483648.1 # long with value 0xFFFFFFFF7FFFFFFF
-bnot $null # int with value 0xFFFFFFFF
-bnot "0xabc" # int with value 0xFFFFF543

7.2.4 Suma unaria


Descripción:

Una expresión con el formato +expresión unaria se trata como si se hubiera escrito
como 0 + unary-expression (sección 7.7). El literal entero 0 tiene el tipo int .

Este operador es asociativo a la derecha.

Ejemplos:

PowerShell

+123L # type long, value 123


+0.12340D # type decimal, value 0.12340
+"0xabc" # type int, value 2748

7.2.5 Resta unaria


Descripción:

Una expresión con el formato -expresión unaria se trata como si se hubiera escrito como
0 - unary-expression (sección 7.7). El literal entero 0 tiene el tipo int .

Este operador es asociativo a la derecha.

Ejemplos:

-$true # tipo int, valor -1 -123L # tipo long, valor -123 -0.12340D # tipo decimal, valor
-0.12340

7.2.6 Operadores de incremento y decremento prefijos


Descripción:

La expresión unaria debe designar una ubicación grabable que tenga un valor de tipo
numérico (sección 4) o el valor $null . Si el valor que designa su expresión unaria es
$null , el valor de expresión unaria se convierte al tipo int y al valor cero antes de que se
evalúe el operador.

7 Nota

El tipo del valor que designa expresión unaria puede cambiar cuando se almacena
el resultado. Vea la sección 7.11 para obtener información sobre el cambio de tipos
mediante la asignación.

Para el operador ++ de prefijo, el valor de expresión unaria se incrementa en 1 del tipo


adecuado. El resultado es el nuevo valor después de que se haya realizado el
incremento. La expresión ++E es equivalente a E += 1 (sección 7.11.2).

Para el operador -- de prefijo, el valor de expresión unaria se reduce en 1 del tipo


adecuado. El resultado es el nuevo valor después de que se haya realizado el
decremento. La expresión --E es equivalente a E -= 1 (sección 7.11.2).

Estos operadores son asociativos a la derecha.

Ejemplos:

PowerShell

$i = 0 # $i = 0
$++i # $i is incremented by 1
$j = --$i # $i is decremented then $j takes on the value of $i
$a = 1,2,3
$b = 9,8,7
$i = 0;
$j = 1
$b[--$j] = $a[++$i] # $j is # decremented, $i incremented, then $b[0]
# takes on the value of $a[1]

$i = 2147483647 # $i holds a value of type int


++$i # $i now holds a value of type double because
# 2147483648 is too big to fit in type int

[int]$k = 0 # $k is constrained to int


$k = [int]::MinValue # $k is set to -2147483648
$--k # -2147483649 is too small to fit, imp-def behavior

$x = $null # target is unconstrained, $null goes to [int]0


$--x # value treated as int, 0->-1

7.2.7 Operador unario -join


Descripción:

El operador unario -join genera una cadena que es la concatenación del valor de uno o
varios objetos que designa expresión unaria. (Se puede insertar un separador mediante
la versión binaria de este operador [sección 7.8.4.4]).

La expresión unaria puede ser un valor escalar o una colección.

Ejemplos:

PowerShell

-join (10, 20, 30) # result is "102030"


-join (123, $false, 19.34e17) # result is "123False1.934E+18"
-join 12345 # result is "12345"
-join $null # result is ""

7.2.8 Operador unario -split


Descripción:

El operador unario -split divide una o varias cadenas que designa expresión unaria y
devuelve sus subpartes en una matriz unidimensional restringida de cadena. Trata
cualquier grupo contiguo de caracteres de espacio en blanco como delimitador entre
subpartes sucesivas. (Se puede especificar una cadena de delimitador explícita mediante
la versión binaria de este operador [sección 7.8.4.5]). Este operador tiene dos variantes
(sección 7.8).

El texto delimitador no se incluye en las cadenas resultantes. Se omiten los espacios en


blanco iniciales y finales de la cadena de entrada. Una cadena de entrada que está vacía
o contiene espacios en blanco solo da como resultado una matriz de 1 cadena, que está
vacía.

La expresión unaria puede designar un valor escalar o una matriz de cadenas.

Ejemplos:

PowerShell

-split " red\`tblue\`ngreen " # 3 strings: "red", "blue", "green"


-split ("yes no", "up down") # 4 strings: "yes", "no", "up", "down"
-split " " # 1 (empty) string

7.2.9 Operador de conversión


Descripción:

Este operador convierte explícitamente (sección 6) el valor que designa expresión unaria
en el tipo que designa literal de tipo. Si literal de tipo es distinto de void, el tipo del
resultado es el tipo con nombre y el valor es el de después de la conversión. Si literal de
tipo es void, no se escribe ningún objeto en la canalización y no hay ningún resultado.

Cuando una expresión de cualquier tipo se convierte en ese mismo tipo, el tipo y el
valor resultantes son el tipo y el valor de expresión unaria.

Este operador es asociativo a la derecha.

Ejemplos:

PowerShell

[bool]-10 # a bool with value True


[int]-10.70D # a decimal with value -10
[int]10.7 # an int with value 11
[long]"+2.3e+3" # a long with value 2300
[char[]]"Hello" # an array of 5 char with values H, e, l, l, and o.

7.3 Operador de coma binario


Sintaxis:

Syntax

array-literal-expression:
unary-expression
unary-expression , new-lines~opt~ array-literal-expression

Descripción:

El operador de coma binario crea una matriz unidimensional cuyos elementos son los
valores que designan sus operandos, en orden léxico. La matriz tiene un tipo sin
restricciones.

Ejemplos:

PowerShell

2,4,6 # Length 3; values 2,4,6


(2,4),6 # Length 2; values [object[]],int
(2,4,6),12,(2..4) # Length 3; [object[]],int,[object[]]
2,4,6,"red",$null,$true # Length 6

La incorporación de paréntesis de agrupación a determinadas expresiones de coma


binarias no documenta la prioridad predeterminada; más bien cambia el resultado.

7.4 Operador de rango


Sintaxis:

Syntax

range-expression:
array-literal-expression
range-expression *..* new-lines~opt~
array-literal-expression

Descripción:

Una expresión de rango crea una matriz unidimensional sin restricciones cuyos
elementos son los valores de la secuencia int que especifican los límites de intervalo. Los
valores que designan los operandos se convierten en int, si es necesario (sección 6.4). El
operando que designa el valor inferior después de la conversión es el límite inferior,
mientras que el operando que designa el valor más alto después de la conversión es el
límite superior. Ambos límites pueden ser los mismos; en cuyo caso, la matriz resultante
tiene longitud 1. Si el operando izquierdo designa el límite inferior, la secuencia está en
orden ascendente. Si el operando izquierdo designa el límite superior, la secuencia está
en orden descendente.

Conceptualmente, este operador es un acceso directo para la secuencia del operador de


coma binario correspondiente. Por ejemplo, el intervalo 5..8 también se puede generar
mediante 5,6,7,8 . Pero si se necesita una secuencia ascendente o descendente sin
tener una matriz, una implementación puede evitar la generación de una matriz real. Por
ejemplo, en foreach ($i in 1..5) { ... } , no es necesario crear ninguna matriz.

Se puede usar una expresión de rango para especificar un segmento de matriz


(sección 9.9).

Ejemplos:

PowerShell

1..10 # ascending range 1..10


-500..-495 # descending range -500..-495
16..16 # sequence of 1

$x = 1.5
$x..5.40D # ascending range 2..5

$true..3 # ascending range 1..3


-2..$null # ascending range -2..0
"0xf".."0xa" # descending range 15..10

7.5 Operador de formato


Sintaxis:

Syntax

format-expression:
range-expression
format-expression format-operator new-lines~opt~ range-expression

format-operator:
dash f

dash:
- (U+002D)
EnDash character (U+2013)
EmDash character (U+2014)
Horizontal bar character (U+2015)
Descripción:

Una expresión de formato da formato a uno o varios valores que designa expresión de
rango según una cadena de especificación de formato que designa expresión de formato.
Las posiciones de los valores que designa expresión de formato se numeran a partir de
cero y aumentan en orden léxico. El resultado tiene el tipo string .

Una cadena de especificación de formato puede contener cero o más especificaciones


de formato, cada una con el formato siguiente:

{N [ ,M ][ : FormatString ]}

N representa una posición de valor de expresión de rango (obligatorio), M representa el


ancho de pantalla mínimo (opcional) y FormatString indica el formato (opcional). Si el
ancho de un valor con formato supera el ancho especificado, el ancho aumenta según
corresponda. Los valores cuyas posiciones no se hacen referencia en FormatString se
omiten después de evaluar los efectos secundarios. Si N hace referencia a una posición
inexistente, el comportamiento está definido por la implementación. El valor de tipo
$null y void tienen el formato de cadenas vacías. Las matrices tienen el formato de

subexpresión (sección 7.1.6). Para incluir los caracteres "{" y "}" en una especificación de
formato sin que se interpreten como delimitadores de formato, escríbalos como "{{" y
"}}", respectivamente.

Para obtener una definición completa de las especificaciones de formato, vea el tipo
System.IFormattable en el Informe técnico TR/84 de la Ecma.

Ejemplos:

PowerShell

`$i` = 10; $j = 12
"{2} <= {0} + {1}\`n" -f $i,$j,($i+$j) # 22 <= 10 + 12
">{0,3}<" -f 5 # > 5<
">{0,-3}<" -f 5 # >5 <
">{0,3:000}<" -f 5 # >005<
">{0,5:0.00}<" -f 5.0 # > 5.00<
">{0:C}<" -f 1234567.888 # >$1,234,567.89<
">{0:C}<" -f -1234.56 # >($1,234.56)<
">{0,12:e2}<" -f 123.456e2 # > 1.23e+004<
">{0,-12:p}<" -f -0.252 # >-25.20 % <
$format = ">{0:x8}<"
$format -f 123455 # >0001e23f<

En una especificación de formato si N hace referencia a una posición inexistente, se


genera un error FormatError.
7.6 Operadores de multiplicación
Sintaxis:

Syntax

multiplicative-expression:
format-expression
multiplicative-expression * new-lines~opt~ format-expression
multiplicative-expression / new-lines~opt~ format-expression
multiplicative-expression % new-lines~opt~ format-expression

7.6.1 Multiplicación
Descripción:

El resultado del operador de multiplicación * es el producto de los valores que


designan los dos operandos después de aplicar las conversiones aritméticas habituales
(sección 6.15).

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

12 * -10L # long result -120


-10.300D * 12 # decimal result -123.600
10.6 * 12 # double result 127.2
12 * "0xabc" # int result 32976

7.6.2 Replicación de cadenas


Descripción:

Cuando el operando izquierdo designa una cadena, el operador binario * crea una
cadena nueva que contiene la que designa el operando izquierdo, replicada el número
de veces que designa el valor del operando derecho mientras se convierte al tipo entero
(sección 6.4).

Este operador es asociativo a la izquierda.

Ejemplos:
PowerShell

"red" * "3" # string replicated 3 times


"red" * 4 # string replicated 4 times
"red" * 0 # results in an empty string
"red" * 2.3450D # string replicated twice
"red" * 2.7 # string replicated 3 times

7.6.3 Replicación de matriz


Descripción:

Cuando el operando izquierdo designa una cadena, el operador binario * crea una
matriz unidimensional sin restricciones nueva que contiene el valor que designa el
operando izquierdo, replicado el número de veces que designa el valor del operando
derecho mientras se convierte al tipo entero (sección 6.4). Un recuento de replicación de
cero da como resultado una matriz de longitud 1. Si el operando izquierdo designa una
matriz multidimensional, se aplana (sección 9.12) antes de usarse.

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

$a = [int[]](10,20) # [int[]], Length 2*1


$a * "3" # [object[]], Length 2*3
$a * 4 # [object[]], Length 2*4
$a * 0 # [object[]], Length 2*0
$a * 2.3450D # [object[]], Length 2*2
$a * 2.7 # [object[]], Length 2*3
(New-Object 'float[,]' 2,3) * 2 # [object[]], Length 2*2

7.6.4 División
Descripción:

El resultado del operador de división / es el cociente cuando el valor que designa el


operando izquierdo se divide por el valor que designa el operando derecho después de
aplicar las conversiones aritméticas habituales (sección 6.15).

Si se intenta realizar una división de enteros o decimales entre cero, se genera un error
de terminación definido por la implementación.

Este operador es asociativo a la izquierda.


Ejemplos:

PowerShell

10/-10 # int result -1


12/-10 # double result -1.2
12/-10D # decimal result 1.2
12/10.6 # double result 1.13207547169811
12/"0xabc" # double result 0.00436681222707424

Si se intenta realizar una división de enteros o decimales entre cero, se produce una
excepción RuntimeException.

7.6.5 Resto
Descripción:

El resultado del operador de resto % es el resto cuando el valor que designa el


operando izquierdo se divide por el valor que designa el operando derecho después de
aplicar las conversiones aritméticas habituales (sección 6.15).

Si se intenta realizar una división de enteros o decimales entre cero, se genera un error
de terminación definido por la implementación.

Ejemplos:

PowerShell

10 % 3 # int result 1
10.0 % 0.3 # double result 0.1
10.00D % "0x4" # decimal result 2.00

Si se intenta realizar una división de enteros o decimales entre cero, se produce una
excepción RuntimeException.

7.7 Operadores de suma


Sintaxis:

Syntax

additive-expression:
multiplicative-expression
additive-expression + new-lines~opt~ multiplicative-expression
additive-expression dash new-lines~opt~ multiplicative-expression
7.7.1 Suma
Descripción:

El resultado del operador de suma + es la suma de los valores que designan los dos
operandos después de aplicar las conversiones aritméticas habituales (sección 6.15).

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

12 + -10L # long result 2


-10.300D + 12 # decimal result 1.700
10.6 + 12 # double result 22.6
12 + "0xabc" # int result 2760

7.7.2 Concatenación de cadenas


Descripción:

Cuando el operando izquierdo designa una cadena, el operador binario + crea una
cadena nueva que contiene el valor que designa el operando izquierdo, seguido de
inmediato por los valores que designa el operando derecho mientras se convierte al
tipo entero (sección 6.8).

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

"red" + "blue" # "redblue"


"red" + "123" # "red123"
"red" + 123 # "red123"
"red" + 123.456e+5 # "red12345600"
"red" + (20,30,40) # "red20 30 40"

7.7.3 Concatenación de matrices


Descripción:
Cuando el operando izquierdo designa una matriz, el operador binario + crea una
matriz unidimensional sin restricciones nueva que contiene el elemento que designa el
operando izquierdo seguido de inmediato por los valores que designa el operando
derecho. Las matrices multidimensionales presentes en cualquiera de los operandos se
aplanan (sección 9.12) antes de usarse.

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

$a = [int[]](10,20) # [int[]], Length 2


$a + "red" # [object[]], Length 3
$a + 12.5,$true # [object[]], Length 4
$a + (New-Object 'float[,]' 2,3) # [object[]], Length 8
(New-Object 'float[,]' 2,3) + $a # [object[]], Length 8

7.7.4 Concatenación de tabla hash


Descripción:

Cuando ambos operandos designan tablas hash, el operador binario + crea una tabla
hash nueva que contiene los elementos que designa el operando izquierdo seguido
inmediatamente de los elementos que designa el operando derecho.

Si las tablas hash contienen la misma clave, se genera un error de terminación definido
por la implementación.

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

$h1 = @{ FirstName = "James"; LastName = "Anderson" }


$h2 = @{ Dept = "Personnel" }
$h3 = $h1 + $h2 # new Hashtable, Count = 3

Si las tablas hash contienen la misma clave, se genera una excepción de tipo
BadOperatorArgument.

7.7.5 Resta
Descripción:

El resultado del operador de resta - es la diferencia cuando el valor que designa el


operando derecho se resta del valor que designa el operando izquierdo después de
aplicar las conversiones aritméticas habituales (sección 6.15).

Este operador es asociativo a la izquierda.

Ejemplos:

PowerShell

12 - -10L # long result 2c


-10.300D - 12 # decimal result -22.300
10.6 - 12 # double result -1.4
12 - "0xabc" # int result -2736

7.8 Operadores de comparación


Sintaxis:

Syntax

comparison-operator: one of
dash as dash ccontains dash ceq
dash cge dash cgt dash cle
dash clike dash clt dash cmatch
dash cne dash cnotcontains dash cnotlike
dash cnotmatch dash contains dash creplace
dash csplit dash eq dash ge
dash gt dash icontains dash ieq
dash ige dash igt dash ile
dash ilike dash ilt dash imatch
dash in dash ine dash inotcontains
dash inotlike dash inotmatch dash ireplace
dash is dash isnot dash isplit
dash join dash le dash like
dash lt dash match dash ne
dash notcontains dash notin dash notlike
dash notmatch dash replace dash shl
dash shr dash split

dash:
- (U+002D)
EnDash character (U+2013)
EmDash character (U+2014)
Horizontal bar character (U+2015)
Descripción:

El tipo del valor que designa el operando izquierdo determina cómo se convierte el
valor que designa el operando derecho (sección 6), si es necesario, antes de realizarse la
comparación.

Algunos operadores de comparación (escritos aquí como -op) tienen dos variantes, una
que distingue mayúsculas de minúsculas (-cop) y otra que no (-i op). La versión -op es
equivalente a -i op. La distinción entre mayúsculas y minúsculas solo es significativa con
las comparaciones de valores de tipo cadena. En contextos de comparación que no son
de cadena, las dos variantes se comportan del mismo modo.

Estos operadores son asociativos a la izquierda.

7.8.1 Operadores relacionales y de igualdad


Descripción:

Hay dos operadores de igualdad: igualdad ( -eq ) y desigualdad ( -ne ); y cuatro


operadores relacionales: menor que ( -lt ), menor o igual que ( -le ), mayor que ( -gt ), y
mayor o igual que ( -ge ). Cada uno de ellos tiene dos variantes (sección 7.8).

Para que dos cadenas se comparen como iguales, deben tener la misma longitud y
contenido, y la misma estructura de mayúsculas y minúsculas, si procede.

Si el valor que designa el operando izquierdo no es una colección, el resultado tiene el


tipo bool . De lo contrario, el resultado es una matriz unidimensional sin restricciones
posiblemente vacía que contiene los elementos de la colección que prueban True en
comparación con el valor que designa el operando derecho.

Ejemplos:

PowerShell

10 -eq "010" # True, int comparison


"010" -eq 10 # False, string comparison
"RED" -eq "Red" # True, case-insensitive comparison
"RED" -ceq "Red" # False, case-sensitive comparison
"ab" -lt "abc" # True

10,20,30,20,10 -ne 20 # 10,30,10, Length 3


10,20,30,20,10 -eq 40 # Length 0
10,20,30,20,10 -ne 40 # 10,20,30,20,10, Length 5
10,20,30,20,10 -gt 25 # 30, Length 1
0,1,30 -ne $true # 0,30, Length 2
0,"00" -eq "0" # 0 (int), Length 1
7.8.2 Operadores de contención
Descripción:

Hay cuatro operadores de contención: contiene ( -contains ), no contiene ( ‑notcontains ),


en ( -in ) y no en ( -notin ). Cada uno de ellos tiene dos variantes (sección 7.8).

Los operadores de contención devuelven un resultado de tipo booleano que indica si un


valor se produce (o no se produce) al menos una vez en los elementos de una matriz.
Con -contains y ‑notcontains , el operando derecho designa el valor y el operando
izquierdo designa la matriz. Con -in y -notin , los operandos se invierten. El operando
izquierdo designa el valor y el operando derecho designa la matriz.

A efectos de estos operadores, si el operando de matriz tiene un valor escalar, el valor


escalar se trata como una matriz de un elemento.

Ejemplos:

PowerShell

10,20,30,20,10 -contains 20 # True


10,20,30,20,10 -contains 42.9 # False
10,20,30 -contains "10" # True
"010",20,30 -contains 10 # False
10,20,30,20,10 -notcontains 15 # True
"Red",20,30 -ccontains "RED" # False

7.8.3 Operadores de pruebas de tipos y de conversión


Descripción:

El operador de tipo -is comprueba si el valor que designa el operando izquierdo tiene
el tipo o se deriva de un tipo que tiene el tipo que designa el operando derecho. El
operando derecho debe designar un tipo o un valor que se pueda convertir en un tipo
(por ejemplo, una cadena que designe un tipo). El tipo del resultado es bool . El
operador de tipo -isnot devuelve la negación lógica del formulario -is
correspondiente.

El operador de tipo -as intenta convertir el valor que designa el operando izquierdo al
tipo que designa el operando derecho. El operando derecho debe designar un tipo o un
valor que se pueda convertir en un tipo (por ejemplo, una cadena que designe un tipo).
Si se produce un error en la conversión, se devuelve $null ; de lo contrario, se devuelve
el valor convertido y el tipo de valor devuelto de ese resultado es el tipo en tiempo de
ejecución del valor convertido.

Ejemplos:

PowerShell

$a = 10 # value 10 has type int


$a -is [int] # True

$t = [int]
$a -isnot $t # False
$a -is "int" # True
$a -isnot [double] # True

$x = [int[]](10,20)
$x -is [int[]] # True

$a = "abcd" # string is derived from object


$a -is [object] # True

$x = [double]
foreach ($t in [int],$x,[decimal],"string") {
$b = (10.60D -as $t) * 2 # results in int 22, double 21.2
} # decimal 21.20, and string "10.6010.60"

7.8.4 Operadores de coincidencia de patrones y


manipulación de texto

7.8.4.1 Operadores -like y -notlike

Descripción:

Si el operando izquierdo no designa una colección, el resultado tiene el tipo bool . De lo


contrario, el resultado es una matriz unidimensional sin restricciones posiblemente vacía
que contiene los elementos de la colección que prueban True en comparación con el
valor que designa el operando derecho. El operando derecho puede designar una
cadena que contenga expresiones con caracteres comodín (sección 3.15). Estos
operadores tienen dos variantes (sección 7.8).

Ejemplos:

PowerShell

"Hello" -like "h*" # True, starts with h


"Hello" -clike "h*" # False, does not start with lowercase
h
"Hello" -like "*l*" # True, has an l in it somewhere
"Hello" -like "??l" # False, no length match

"-abc" -like "[-xz]*" # True, - is not a range separator


"#$%\^&" -notlike "*[A-Za-z]" # True, does not end with alphabetic
character
"He" -like "h[aeiou]?*" # False, need at least 3 characters
"When" -like "*[?]" # False, ? is not a wildcard character
"When?" -like "*[?]" # True, ? is not a wildcard character

"abc","abbcde","abcgh" -like "abc*" # object[2], values


"abc" and "abcgh"

7.8.4.2 Operadores -match y -notmatch


Descripción:

Si el operando izquierdo no designa una colección, el resultado tiene el tipo bool y, si


ese resultado es $true , los elementos de la tabla hash $matches se establecen en las
cadenas que coinciden (o que no coinciden) con el valor que designa el operando
derecho. De lo contrario, el resultado es una matriz unidimensional sin restricciones
posiblemente vacía que contiene los elementos de la colección que prueban True en
comparación con el valor que designa el operando derecho y $matches no se establece.
El operando derecho puede designar una cadena que contiene expresiones regulares
(sección 3.16), en cuyo caso, se hace referencia a ella como un patrón. Estos operadores
tienen dos variantes (sección 7.8).

Estos operadores admiten subcoincidencias (sección 7.8.4.6).

Ejemplos:

PowerShell

"Hello" -match ".l" # True, $matches key/value is 0/"el"


"Hello" -match '\^h.*o$' # True, $matches key/value is
0/"Hello"
"Hello" -cmatch '\^h.*o$' # False, $matches not set
"abc\^ef" -match ".\\\^e" # True, $matches key/value is
0/"c\^e"

"abc" -notmatch "[A-Za-z]" # False


"abc" -match "[\^A-Za-z]" # False
"He" -match "h[aeiou]." # False, need at least 3 characters
"abc","abbcde","abcgh" -match "abc.*" # Length is 2, values "abc", "abcgh"

7.8.4.3 Operador -replace


Descripción:

El operador -replace permite el reemplazo de texto en una o varias cadenas que


designa el operando izquierdo mediante los valores que designa el operando derecho.
Este operador tiene dos variantes (sección 7.8). El operando derecho tiene uno de los
formatos siguientes:

La cadena que se va a localizar, que puede contener expresiones regulares


(sección 3.16). En este caso, la cadena de reemplazo es implícitamente "".
Una matriz de 2 objetos que contiene la cadena que se va a localizar, seguida de la
cadena de reemplazo.

Si el operando izquierdo designa una cadena, el resultado tiene una cadena de tipo. Si
el operando izquierdo designa una matriz unidimensional de cadena, el resultado es
una matriz unidimensional sin restricciones, cuya longitud es la misma que para la
matriz del operando izquierdo, que contiene las cadenas de entrada una vez
completado el reemplazo.

Este operador admite subcoincidencias (sección 7.8.4.6).

Ejemplos:

PowerShell

"Analogous","an apple" -replace "a","*" # "*n*logous","*n *pple"


"Analogous" -creplace "[aeiou]","?" # "An?l?g??s"
"Analogous","an apple" -replace '\^a',"%%A" # "%%Analogous","%%An apple"
"Analogous" -replace "[aeiou]",'$&$&' # "AAnaaloogoouus"

7.8.4.4 Operador binario -join

Descripción:

El operador binario -join genera una cadena que es la concatenación del valor de uno
o varios objetos que designa el operando izquierdo después de haberse convertido en
cadena (sección 6,7), si es necesario. La cadena que designa el operando derecho se usa
para separar los valores (posiblemente vacíos) de la cadena resultante.

El operando izquierdo puede ser un valor escalar o una colección.

Ejemplos:

PowerShell
(10, 20, 30) -join "\|" # result is "10\|20\|30"
12345 -join "," # result is "12345", no separator needed
($null,$null) -join "<->" # result is "<->", two zero-length values

7.8.4.5 Operador binario -split


Descripción:

El operador binario -split divide una o varias cadenas que designa el operando
izquierdo y devuelve sus subpartes en una matriz unidimensional restringida de cadena.
Este operador tiene dos variantes (sección 7.8). El operando izquierdo puede designar
un valor escalar o una matriz de cadenas. El operando derecho tiene uno de los
formatos siguientes:

Una cadena de delimitador.


Una matriz de 2 objetos que contiene una cadena de delimitador seguida de un
recuento de divisiones numéricas.
Una matriz de 3 objetos que contiene una cadena de delimitador, un recuento de
divisiones numéricas y una cadena de opciones.
Un bloque de script.
Una matriz de 2 objetos que contiene un bloque de script seguido de un recuento
de divisiones numéricas.

La cadena de delimitador puede contener expresiones regulares (sección 3.16). Se usa


para localizar subpartes con las cadenas de entrada. El delimitador no se incluye en las
cadenas resultantes. Si el operando izquierdo designa una cadena vacía, se produce un
elemento de cadena vacío. Si la cadena de delimitador es una cadena vacía, se
encuentra en cada posición del carácter de las cadenas de entrada.

De manera predeterminada, todas las subpartes de las cadenas de entrada se colocan


en el resultado como elementos independientes, pero el recuento de divisiones se
puede usar para modificar este comportamiento. Si ese recuento es negativo, cero, o
mayor o igual que el número de subpartes de una cadena de entrada, cada subparte
entra en un elemento independiente. Si ese recuento es menor que el número de
subpartes de la cadena de entrada, hay elementos count en el resultado, con el
elemento final que contiene todas las subpartes más allá de las primeras subpartes
count - 1.

Una cadena de opciones contiene cero o más nombres de opción con cada par
adyacente, separados por una coma. Se omiten los espacios en blanco iniciales, finales e
insertados. Los nombres de opción pueden estar en cualquier orden y distinguen
mayúsculas de minúsculas.
Si una cadena de opciones contiene el nombre de opción SimpleMatch, también puede
contener el nombre de opción IgnoreCase. Si una cadena de opciones contiene el
nombre de opción RegexMatch, o no contiene RegexMatch o SimpleMatch, puede
contener cualquier nombre de opción excepto SimpleMatch. Pero no debe contener
Multiline ni Singleline.

Este es el conjunto de nombres de opción:

Opción Descripción

CultureInvariant Omite las diferencias culturales en el idioma al evaluar el delimitador.

ExplicitCapture Omite los grupos de coincidencias sin nombre para que solo se
devuelvan grupos de captura explícitos en la lista de resultados.

IgnoreCase Fuerza la coincidencia sin distinguir mayúsculas de minúsculas,


aunque se utilice -csplit .

IgnorePatternWhitespace Omite los comentarios y los espacios en blanco sin escape marcados
con el signo de número (#).

Multiline Este modo reconoce el inicio y el final de las líneas y cadenas. El modo
predeterminado es Singleline.

RegexMatch Usa la coincidencia de expresiones regulares para evaluar el


delimitador. Este es el valor predeterminado.

SimpleMatch Usa una comparación de cadenas simple al evaluar el delimitador.

Singleline Este modo reconoce solo el inicio y el final de las cadenas. Este es el
modo predeterminado.

El bloque de script (sección 7.1.8) especifica las reglas para determinar el delimitador y
debe evaluarse para el tipo booleano.

Ejemplos:

PowerShell

"one,forty two,," -split "," # 5 strings: "one" "forty two" ""


""

"abc","de" -split "" # 9 strings: "" "a" "b" "c" "" ""
"d" "e" ""

"ab,cd","1,5,7,8" -split ",", 2 # 4 strings: "ab" "cd" "1" "5,7,8"

"10X20x30" -csplit "X", 0, "SimpleMatch" # 2 strings: "10" "20x30"

"analogous" -split "[AEIOU]", 0, "RegexMatch, IgnoreCase"


# 6 strings: "" "n" "l" "g" "" "s"

"analogous" -split { $_ -eq "a" -or $_ -eq "o" }, 4


# 4 strings: "" "n" "l" "gous"

7.8.4.6 Subcoincidencias
El patrón que coincide con -match , -notmatch y -replace puede contener subpartes
(denominadas subcoincidencias) delimitadas por paréntesis. Considere el ejemplo
siguiente:

"red" -match "red"

El resultado es $true y la clave 0 de $matches contiene "red", esa parte de la cadena


que designa el operando izquierdo y que coincide exactamente con el patrón que
designa el operando derecho.

En el ejemplo siguiente, todo el patrón es una subcoincidencia:

"red" -match "(red)"

Como antes, la clave 0 contiene "red", pero la clave 1 también contiene "red", que es esa
parte de la cadena que designa el operando izquierdo y que coincide exactamente con
la subcoincidencia.

Tenga en cuenta el patrón siguiente más complejo:

"red" -match "((r)e)(d)"

Este patrón permite subcoincidencias de "r", "re", "d" o "red".

De nuevo, la clave 0 contiene "red". La clave 1 contiene "re", la clave 2 contiene "r" y la
clave 3 contiene "d". Los pares clave-valor están en orden coincidente de izquierda a
derecha en el patrón, con coincidencias de cadena más largas anteriores a las más
cortas.

En el caso de -replace , el texto de reemplazo puede acceder a las subcoincidencias


mediante nombres con el formato $n , donde la primera coincidencia es $1 , la segunda
es $3 , y así sucesivamente. Por ejemplo,

PowerShell

"Monday morning" -replace '(Monday|Tuesday)


(morning|afternoon|evening)','the $2 of $1'
La cadena resultante es "la mañana del lunes".

En lugar de tener claves en $matches en índices de base cero, las subcoincidencias se


pueden nombrar con el formato ?<*name*> . Por ejemplo, "((r)e)(d)" se puede escribir
con tres subcoincidencias con nombre, m1, m2 y m3, tal como se muestra a
continuación: "(?<m1>(?<m2>r)e)(?<m3>d)" .

7.8.5 Operadores de desplazamiento


Descripción:

El operador de desplazamiento a la izquierda ( -shl ) y el operador de desplazamiento a


la derecha ( -shr ) convierten el valor que diseña el operando izquierdo en un tipo
entero y el valor que designa el operando derecho a int, si es necesario, mediante las
conversiones aritméticas habituales (sección 6.15).

El operador de desplazamiento a la izquierda desplaza el operando izquierdo a la


izquierda un número de bits calculados, tal como se describe a continuación. Las
posiciones de bits vacíos de orden inferior se establecen en cero.

El operador de desplazamiento a la derecha desplaza el operando izquierdo a la


derecha un número de bits calculados, tal como se describe a continuación. Los bits de
orden inferior del operando izquierdo se descartan y los bits restantes se desplazan a la
derecha. Cuando el operando izquierdo es un valor con signo, las posiciones de bits
vacíos de orden superior se establecen en cero si el operando izquierdo no es negativo
y en uno si es negativo. Cuando el operando izquierdo es un valor sin signo, las
posiciones de bits vacíos de orden superior se establecen en cero.

Cuando el operando izquierdo tiene el tipo int, el recuento de desplazamientos lo dan


los cinco bits de orden inferior del operando derecho. Cuando el operando derecho
tiene el tipo long, el recuento de desplazamientos lo da el orden inferior de seis bits del
operando derecho.

Ejemplos:

PowerShell

0x0408 -shl 1 # int with value 0x0810


0x0408 -shr 3 # int with value 0x0081
0x100000000 -shr 0xfff81 # long with value 0x80000000

7.9 Operadores bit a bit


Sintaxis:

Syntax

bitwise-expression:
comparison-expression
bitwise-expression -band new-lines~opt~ comparison-expression
bitwise-expression -bor new-lines~opt~ comparison-expression
bitwise-expression -bxor new-lines~opt~ comparison-expression

Descripción:

El operador AND bit a bit -band , el operador OR bit a bit -bor y el operador XOR bit a
bit -bxor convierten los valores que designan sus operandos en tipos enteros, si es
necesario, mediante las conversiones aritméticas habituales (sección 6.15). Después de
la conversión, si ambos valores tienen el tipo int, ese es el tipo del resultado. De lo
contrario, si ambos valores tienen el tipo long, ese es el tipo del resultado. Si un valor
tiene el tipo int y el otro tiene el tipo long, el tipo del resultado es long. De lo contrario,
la expresión tiene un formato incorrecto. El resultado es el operador AND bit a bit, OR
bit a bit o XOR bit a bit, respectivamente, de los valores del operando posiblemente
convertidos.

Estos operadores son asociativos a la izquierda. Son conmutativos si ninguno de los


operandos contiene un efecto secundario.

Ejemplos:

PowerShell

0x0F0F -band 0xFE # int with value 0xE


0x0F0F -band 0xFEL # long with value 0xE
0x0F0F -band 14.6 # long with value 0xF

0x0F0F -bor 0xFE # int with value 0xFFF


0x0F0F -bor 0xFEL # long with value 0xFFF
0x0F0F -bor 14.40D # long with value 0xF0F

0x0F0F -bxor 0xFE # int with value 0xFF1


0x0F0F -bxor 0xFEL # long with value 0xFF1
0x0F0F -bxor 14.40D # long with value 0xF01
0x0F0F -bxor 14.6 # long with value 0xF00

7.10 Operadores lógicos


Sintaxis:
Syntax

logical-expression:
bitwise-expression
logical-expression -and new-lines~opt~ bitwise-expression
logical-expression -or new-lines~opt~ bitwise-expression
logical-expression -xor new-lines~opt~ bitwise-expression

Descripción:

El operador AND lógico -and convierte los valores que designan sus operandos en
bool , si es necesario (sección 6.2). El resultado es el operador AND lógico de los valores
del operando posiblemente convertidos y tiene el tipo bool . Si el operando izquierdo se
evalúa como False, no se evalúa el operando derecho.

El operador OR lógico -or convierte los valores que designan sus operandos en bool , si
es necesario (sección 6.2). El resultado es el operador OR lógico de los valores del
operando posiblemente convertidos y tiene el tipo bool . Si el operando izquierdo se
evalúa como True, no se evalúa el operando derecho.

El operador XOR lógico -xor convierte los valores que designan sus operandos en bool
(sección 6.2). El resultado es el operador XOR lógico de los valores del operando
posiblemente convertidos y tiene el tipo bool .

Estos operadores son asociativos a la izquierda.

Ejemplos:

PowerShell

$j = 10
$k = 20
($j -gt 5) -and (++$k -lt 15) # True -and False -> False
($j -gt 5) -and ($k -le 21) # True -and True -> True
($j++ -gt 5) -and ($j -le 10) # True -and False -> False
($j -eq 5) -and (++$k -gt 15) # False -and True -> False

$j = 10
$k = 20
($j++ -gt 5) -or (++$k -lt 15) # True -or False -> True
($j -eq 10) -or ($k -gt 15) # False -or True -> True
($j -eq 10) -or (++$k -le 20) # False -or False -> False

$j = 10
$k = 20
($j++ -gt 5) -xor (++$k -lt 15) # True -xor False -> True
($j -eq 10) -xor ($k -gt 15) # False -xor True -> True
($j -gt 10) -xor (++$k -le 25) # True -xor True -> False
7.11 Operadores de asignación
Sintaxis:

Syntax

assignment-expression:
expression assignment-operator statement

assignment-operator: *one of
= dash = += *= /= %=

Descripción:

Un operador de asignación almacena un valor en la ubicación grabable que designa


expresión. Para obtener una explicación del operador de asignación = , vea la
sección 7.11.1. Para obtener una explicación del resto de operadores de asignación, vea
la sección 7.11.2.

Una expresión de asignación tiene el valor que designa expresión después de que se
haya realizado la asignación, pero esa expresión de asignación no designa por sí misma
una ubicación grabable. Si la expresión está restringida por tipos (sección 5.3), el tipo
usado en esa restricción es el tipo del resultado. De lo contrario, el tipo del resultado es
el tipo después de que se hayan aplicado las conversiones aritméticas habituales
(sección 6.15).

Este operador es asociativo a la derecha.

7.11.1 Asignación simple


Descripción:

En la asignación simple ( = ), el valor que designa la instrucción reemplaza el valor


almacenado en la ubicación grabable que designa la expresión. Pero si la expresión
designa una clave inexistente en una tabla hash, esa clave se agrega a la tabla hash con
un valor asociado del valor que designa la instrucción.

Tal como se muestra en la gramática, expresión puede designar una lista separada por
comas de ubicaciones grabables. Esto se conoce como asignación múltiple. La
instrucción designa una lista de uno o varios valores separados por comas. Las comas de
cualquiera de las dos listas de operandos forman parte de la sintaxis de varias
asignaciones y no representan el operador de coma binario. Los valores se toman de la
lista que designa la instrucción, en orden léxico, y se almacenan en la ubicación grabable
correspondiente que designa la expresión. Si la lista que designa la instrucción tiene
menos valores que los que hay en ubicaciones grabables en la expresión, el exceso de
ubicaciones toma el valor $null . Si la lista que designa la instrucción tiene más valores
que ubicaciones grabables de expresión, todas las ubicaciones de expresión más a la
derecha toman el valor de instrucción correspondiente y la ubicación de expresión más a
la derecha se convierte en una matriz unidimensional sin restricciones, con todos los
valores de instrucción restantes como elementos.

Para las instrucciones que tienen valores (sección 8.1.2), instrucción puede ser una
instrucción.

Ejemplos:

PowerShell

$a = 20; $b = $a + 12L # $b has type long, value 22


$hypot = [Math]::Sqrt(3*3 + 4*4) # type double, value 5
$a = $b = $c = 10.20D # all have type decimal, value 10.20
$a = (10,20,30),(1,2) # type [object[]], Length 2
[int]$x = 10.6 # type int, value 11
[long]$x = "0xabc" # type long, value 0xabc
$a = [float] # value type literal [float]
$i,$j,$k = 10,"red",$true # $i is 10, $j is "red", $k is True
$i,$j = 10,"red",$true # $i is 10, $j is [object[]], Length 2
$i,$j = (10,"red"),$true # $i is [object[]], Length 2, $j is True
$i,$j,$k = 10 # $i is 10, $j is $null, $k is $null

$h = @{}
[int] $h.Lower, [int] $h.Upper = -split "10 100"

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }


$h1.Dept = "Finance" # adds element Finance
$h1["City"] = "New York" # adds element City

[int]$Variable:v = 123.456 # v takes on the value 123


${E:output.txt} = "a" # write text to the given file
$Env:MyPath = "x:\data\file.txt" # define the environment variable
$Function:F = { param ($a, $b) "Hello there, $a, $b" }
F 10 "red" # define and invoke a function
function Demo { "Hi there from inside Demo" }
$Alias:A = "Demo" # create alias for function Demo
A # invoke function Demo via the alias

7.11.2 Asignación compuesta


Descripción:
Una asignación compuesta tiene el formato E1 op= E2 y es equivalente a la expresión de
asignación simple E1 = E1 op (E2) salvo que, en el caso de asignación compuesta, la
expresión E1 solo se evalúa una vez. Si expresión está restringida por tipos (sección 5.3),
el tipo usado en esa restricción es el tipo del resultado. De lo contrario, el tipo del
resultado lo determina op. Para obtener información sobre *= , vea la sección 7.6.1,
sección 7.6.2, sección 7.6.3; para obtener información sobre /= , vea la sección 7.6.4;
para obtener información sobre %= , vea la sección 7.6.5; para obtener información sobre
+= , vea la sección 7.7.1, sección 7.7.2, sección 7.7.3; para obtener información sobre -= ,

vea la sección 7.7.5.

7 Nota

Un operando que designa un valor sin restricciones de tipo numérico puede tener
su tipo que cambia un operador de asignación cuando se almacena el resultado.

Ejemplos:

PowerShell

$a = 1234; $a *= (3 + 2) # type is int, value is 1234 * (3 + 2)


$b = 10,20,30 # $b[1] has type int, value 20
$b[1] /= 6 # $b[1] has type double, value 3.33...

$i = 0
$b = 10,20,30
$b[++$i] += 2 # side effect evaluated only once

[int]$Variable:v = 10 # v takes on the value 10


$Variable:v -= 3 # 3 is subtracted from v

${E:output.txt} = "a" # write text to the given file


${E:output.txt} += "b" # append text to the file giving ab
${E:output.txt} *= 4 # replicate ab 4 times giving abababab

7.12 Operadores de redireccionamiento


Sintaxis:

Syntax

pipeline:
assignment-expression
expression redirections~opt~ pipeline-tail~opt~
command verbatim-command-argument~opt~ pipeline-tail~opt~
redirections:
redirection
redirections redirection

redirection:
merging-redirection-operator
file-redirection-operator redirected-file-name

redirected-file-name:
command-argument
primary-expression

file-redirection-operator: one of
> >> 2> 2>> 3> 3>> 4> 4>>
5> 5>> 6> 6>> > >> <

merging-redirection-operator: one of
>&1 2>&1 3>&1 4>&1 5>&1 6>&1
>&2 1>&2 3>&2 4>&2 5>&2 6>&2

Descripción:

El operador de redireccionamiento > toma la salida estándar de la canalización y la


redirige a la ubicación que designa nombre de archivo redirigido, lo que sobrescribe el
contenido actual de esa ubicación.

El operador de redireccionamiento >> toma la salida estándar de la canalización y la


redirige a la ubicación que designa nombre de archivo redirigido, anexando al contenido
actual de esa ubicación, si lo hubiera. Si esa ubicación no existe, se crea.

El operador de redireccionamiento con formato n> toma la salida del flujo n de la


canalización y la redirige a la ubicación que designa nombre de archivo redirigido, lo que
sobrescribe el contenido actual de esa ubicación.

El operador de redireccionamiento con formato n>> toma la salida del flujo n de la


canalización y la redirige a la ubicación que designa nombre de archivo redirigido,
anexando al contenido actual de esa ubicación, si lo hubiera. Si esa ubicación no existe,
se crea.

El operador de redireccionamiento con formato m>&n escribe la salida del flujo m en la


misma ubicación que e flujo n.

Estas son los flujos válidos:

STREAM Descripción

1 Flujo de salida estándar


STREAM Descripción

2 Flujo de salida de error

3 Flujo de salida de advertencia

4 Flujo de salida detallada

5 Flujo de salida de depuración

* Salida estándar, salida de error, salida de advertencia, salida detallada y flujos de


salida de depuración

Los operadores de redireccionamiento 1>&2 , 6> , 6>> y < están reservados para un uso
futuro.

Si en la salida el valor de nombre de archivo redirigido es $null , la salida se descarta.

Normalmente, el valor de una expresión que contiene un efecto secundario de nivel


superior no se escribe en la canalización a menos que esa expresión esté entre
paréntesis. Pero si este tipo de expresión es el operando izquierdo de un operador que
redirige la salida estándar, se escribe el valor.

Ejemplos:

PowerShell

$i = 200 # pipeline gets nothing


$i # pipeline gets result
$i > output1.txt # result redirected to named file
++$i >> output1.txt # result appended to named file
type file1.txt 2> error1.txt # error output redirected to named file
type file2.txt 2>> error1.txt # error output appended to named file
dir -Verbose 4> verbose1.txt # verbose output redirected to named file

# Send all output to output2.txt


dir -Verbose -Debug -WarningAction Continue *> output2.txt

# error output redirected to named file, verbose output redirected


# to the same location as error output
dir -Verbose 4>&2 2> error2.txt
8. Instrucciones
Artículo • 19/05/2022

8.1 Listas y bloques de instrucciones


Sintaxis:

 Sugerencia

La notación ~opt~ en las definiciones de sintaxis indica que la entidad léxica es


opcional en la sintaxis.

Syntax

statement-block:
new-lines~opt~ { statement-list~opt~ new-lines~opt~ }

statement-list:
statement
statement-list statement

statement:
if-statement
label~opt~ labeled-statement
function-statement
flow-control-statement statement-terminator
trap-statement
try-statement
data-statement
inlinescript-statement
parallel-statement
sequence-statement
pipeline statement-terminator

statement-terminator:
;
new-line-character

Descripción:

Una instrucción especifica algún tipo de acción que se va a realizar. A menos que se
indique lo contrario dentro de esta cláusula, las instrucciones se ejecutan en orden
léxico.
Un elemento statement-block permite agrupar un conjunto de instrucciones en una sola
unidad sintáctica.

8.1.1 Instrucciones etiquetadas


Sintaxis:

Syntax

labeled-statement:
switch-statement
foreach-statement
for-statement
while-statement
do-statement

Descripción:

Una instrucción de iteración (§8.4) o una instrucción switch (§8.6), opcionalmente, puede
ir precedida de inmediato por una etiqueta de instrucción, label. Una etiqueta de
instrucción se usa como destino opcional de una instrucción break (§8.5.1) o continue
(§8.5.2). Sin embargo, una etiqueta no modifica el flujo de control.

No se permite que haya un espacio en blanco entre los dos puntos ( : ) y el token que lo
sigue.

Ejemplos:

PowerShell

:go_here while ($j -le 100) {


# ...
}

:labelA
for ($i = 1; $i -le 5; ++$i) {
:labelB
for ($j = 1; $j -le 3; ++$j) {
:labelC
for ($k = 1; $k -le 2; ++$k) {
# ...
}
}
}

8.1.2 Valores de instrucción


El valor de una instrucción es el conjunto acumulativo de valores que escribe en la
canalización. Si la instrucción escribe un único valor escalar, es decir, el valor de la
instrucción. Si la instrucción escribe varios valores, el valor de la instrucción es ese
conjunto de valores almacenados en elementos de una matriz unidimensional sin
restricciones, en el orden en que se escribieron. Considere el ejemplo siguiente:

$v = for ($i = 10; $i -le 5; ++$i) { }

No hay ninguna iteración del bucle y no se escribe nada en la canalización. El valor de la


instrucción es $null .

$v = for ($i = 1; $i -le 5; ++$i) { }

Aunque el bucle itera cinco veces, no se escribe nada en la canalización. El valor de la


instrucción es $null.

$v = for ($i = 1; $i -le 5; ++$i) { $i }

El bucle itera cinco veces cada vez que se escribe en la canalización el valor int $i . El
valor de la instrucción es object[] de longitud 5.

$v = for ($i = 1; $i -le 5; ) { ++$i }

Aunque el bucle itera cinco veces, no se escribe nada en la canalización. El valor de la


instrucción es $null .

$v = for ($i = 1; $i -le 5; ) { (++$i) }

El bucle itera cinco veces con cada valor que se escribe en la canalización. El valor de la
instrucción es object[] de longitud 5.

$i = 1; $v = while ($i++ -lt 2) { $i }

El bucle itera una vez. El valor de la instrucción es el elemento int con valor 2.

A continuación, se presentan algunos ejemplos adicionales:

PowerShell

# if $count is not currently defined then define it with int value 10


$count = if ($count -eq $null) { 10 } else { $count }

$i = 1
$v = while ($i -le 5) {
$i # $i is written to the pipeline
if ($i -band 1) {
"odd" # conditionally written to the pipeline

++$i # not written to the pipeline

}
# $v is object[], Length 8, value 1,"odd",2,3,"odd",4,5,"odd"

8.2 Instrucciones de canalización


Sintaxis:

Syntax

pipeline:
assignment-expression
expression redirections~opt~ pipeline-tail~opt~
command verbatim-command-argument~opt~ pipeline-tail~opt~

assignment-expression:
expression assignment-operator statement

pipeline-tail:
| new-lines~opt~ command
| new-lines~opt~ command pipeline-tail

command:
command-name command-elements~opt~
command-invocation-operator command-module~opt~ command-name-expr
command-elements~opt~

command-invocation-operator: one of
& .

command-module:
primary-expression

command-name:
generic-token
generic-token-with-subexpr

generic-token-with-subexpr:
No whitespace is allowed between ) and command-name.
generic-token-with-subexpr-start statement-list~opt~ )

command-namecommand-name-expr:
command-name

primary-expressioncommand-elements:
command-element
command-elements command-element
command-element:
command-parameter
command-argument
redirection

command-argument:
command-name-expr

verbatim-command-argument:
--% verbatim-command-argument-chars

Descripción:

redirections se analiza en §7.12; assignment-expression se analiza en §7.11 y el punto


command-invocation-operator ( . ) se analiza en §3.5.5. Para obtener una discusión de la
asignación de argumentos a parámetros en las invocaciones de comandos, consulte
§8.14.

El primer comando de una canalización es una expresión o una invocación de


comandos. Normalmente, una invocación de comandos comienza con un elemento
command-name, que suele ser un identificador básico. command-elements representa la
lista de argumentos del comando. Una nueva línea o un punto y coma sin escapes
termina una canalización.

Una invocación de comandos consta del nombre del comando seguido de cero o más
argumentos. Las reglas que regulan los argumentos son las siguientes:

Un argumento que no es una expresión, pero que contiene texto arbitrario sin
espacios en blanco sin escapes, se trata como si estuviera entre comillas dobles. Se
conserva la escritura bicameral.

La sustitución de variables y la expansión de subexpresiones ((§2.3.5.2) tiene lugar


dentro de expandable-string-literal s y expandable-here-string-literal s.

El texto entre comillas permite incluir espacios en blanco iniciales, finales e


incrustados en el valor del argumento. [Nota: La presencia de espacios en blanco
en un argumento entre comillas no convierte un solo argumento en varios
argumentos. nota final]

Al poner un argumento entre paréntesis, esa expresión se evalúa con el resultado


que se pasa en lugar del texto de la expresión original.

Para pasar un argumento similar a un parámetro de modificador (§2.3.4) pero sin


esa finalidad, ponga ese argumento entre comillas.
Al especificar un argumento que coincide con un parámetro que tiene la
restricción de tipo [switch] (§8.10.5), la presencia del nombre de argumento por sí
solo hace que el parámetro se establezca en $true . Sin embargo, el valor del
parámetro se puede establecer explícitamente anexando un sufijo al argumento.
Por ejemplo, con un parámetro restringido de tipo p, un argumento de -p:$true
establece p en True, mientras que -p:$false establece p en False.

Un argumento de -- indica que todos los argumentos que lo siguen se van a


pasar en su forma real como si se pusieran comillas dobles alrededor de ellos.

Un argumento de --% indica que todos los argumentos que lo siguen se van a
pasar con un procesamiento y análisis mínimos. Este argumento se denomina
parámetro textual. Los argumentos que siguen al parámetro textual no son
expresiones de PowerShell aunque sean expresiones de PowerShell
sintácticamente válidas.

Si el tipo de comando es Aplicación, el parámetro --% no se pasa al comando. Los


argumentos que siguen a --% tienen expandida cualquier variable de entorno (cadenas
rodeadas de % ). Por ejemplo:

PowerShell

echoargs.exe --% "%path%" # %path% is replaced with the value $env:path

No se especifica el orden de evaluación de los argumentos.

Para obtener información acerca del enlace de parámetros, consulte §8.14. Para obtener
información sobre la búsqueda de nombres, consulte §3.8.

Una vez completado el procesamiento de argumentos, se invoca el comando. Si el


comando invocado finaliza normalmente (§8.5.4), el control vuelve al punto del script o
la función que sigue inmediatamente a la invocación de comandos. Para obtener una
descripción del comportamiento de una finalización anómala, consulte break (§8.5.1),
continue (§8.5.2), throw (§8.5.3), exit (§8.5.5), try (§8.7) y trap (§8.8).

Normalmente, un comando se invoca mediante su nombre seguido de cualquier


argumento. Sin embargo, se puede usar el operador command-invocation, &. Si el
nombre del comando contiene espacios en blanco sin escapes, se debe poner entre
comillas e invocar con este operador. Como un bloque de scripts no tiene nombre,
también se debe invocar con este operador. Por ejemplo, las siguientes invocaciones de
una llamada a comando Get-Factorial son equivalentes:
PowerShell

Get-Factorial 5
& Get-Factorial 5
& "Get-Factorial" 5

Se permiten llamadas a funciones recursivas directas e indirectas. Por ejemplo,

PowerShell

function Get-Power([int]$x, [int]$y) {


if ($y -gt 0) { return $x * (Get-Power $x (--$y)) }
else { return 1 }
}

Ejemplos:

PowerShell

New-Object 'int[,]' 3,2


New-Object -ArgumentList 3,2 -TypeName 'int[,]'

dir e:\PowerShell\Scripts\*statement*.ps1 | Foreach-Object {$_.Length}

dir e:\PowerShell\Scripts\*.ps1 | Select-String -List "catch" | Format-Table


path,linenumber -AutoSize

8.3 La instrucción if
Sintaxis:

Syntax

if-statement:
if new-lines~opt~ ( new-lines~opt~ pipeline new-lines~opt~ ) statement-
block
elseif-clauses~opt~ else-clause~opt~

elseif-clauses:
elseif-clause
elseif-clauses elseif-clause

elseif-clause:
new-lines~opt~ elseif new-lines~opt~ ( new-lines~opt~ pipeline new-
lines~opt~ ) statement-block

else-clause:
new-lines~opt~ else statement-block
Descripción:

Las expresiones de control pipeline deben ser de tipo booleano o poder convertirse de
forma implícita a ese tipo. La cláusula else-clause es opcional. Puede haber cero o más
cláusulas elseif-clause.

Si se comprueba que la expresión pipeline es True, su statement-block se ejecuta y


finaliza la ejecución de la instrucción. De lo contrario, si hay una cláusula elseif-clause
presente, si se comprueba que su expresión pipeline es True, su statement-block se
ejecuta y finaliza la ejecución de la instrucción. De lo contrario, si hay una cláusula else-
clause presente, su statement-block se ejecuta.

Ejemplos:

PowerShell

$grade = 92
if ($grade -ge 90) { "Grade A" }
elseif ($grade -ge 80) { "Grade B" }
elseif ($grade -ge 70) { "Grade C" }
elseif ($grade -ge 60) { "Grade D" }
else { "Grade F" }

8.4 Instrucciones de iteración

8.4.1 La instrucción while


Sintaxis:

Syntax

while-statement:
while new-lines~opt~ ( new-lines~opt~ while-condition new-lines~opt~ )
statement-block

while-condition:
new-lines~opt~ pipeline

Descripción:

La expresión de control while-condition debe ser de tipo booleano o poder convertirse


de forma implícita a ese tipo. El cuerpo del bucle, que consta de statement-block, se
ejecuta repetidamente hasta que se comprueba que la expresión de control es False. La
expresión de control se evalúa antes de cada ejecución del cuerpo del bucle.

Ejemplos:

PowerShell

$i = 1
while ($i -le 5) { # loop 5 times
"{0,1}`t{1,2}" -f $i, ($i*$i)
++$i
}

8.4.2 La instrucción do
Sintaxis:

Syntax

do-statement:
do statement-block new-lines~opt~ while new-lines~opt~ ( while-condition
new-lines~opt~ )
do statement-block new-lines~opt~ until new-lines~opt~ ( while-condition
new-lines~opt~ )

while-condition:
new-lines~opt~ pipeline

Descripción:

La expresión de control while-condition debe ser de tipo booleano o poder convertirse


de forma implícita a ese tipo. Cuando se usa while, el cuerpo del bucle, que incluye
statement-block, se ejecuta repetidamente hasta que se comprueba que la expresión de
control es True. Cuando se usa until, el cuerpo del bucle se ejecuta repetidamente hasta
que se comprueba que la expresión de control es True. La expresión de control se evalúa
después de cada ejecución del cuerpo del bucle.

Ejemplos:

PowerShell

$i = 1
do {
"{0,1}`t{1,2}" -f $i, ($i * $i)
}
while (++$i -le 5) # loop 5 times
$i = 1
do {
"{0,1}`t{1,2}" -f $i, ($i * $i)
}
until (++$i -gt 5) # loop 5 times

8.4.3 Instrucción for


Sintaxis:

Syntax

for-statement:
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~ statement-terminator
new-lines~opt~ for-condition~opt~ statement-terminator
new-lines~opt~ for-iterator~opt~
new-lines~opt~ ) statement-block

for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~ statement-terminator
new-lines~opt~ for-condition~opt~
new-lines~opt~ ) statement-block

for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~
new-lines~opt~ ) statement-block

for-initializer:
pipeline

for-condition:
pipeline

for-iterator:
pipeline

Descripción:

La expresión de control for-condition debe ser de tipo booleano o poder convertirse de


forma implícita a ese tipo. El cuerpo del bucle, que incluye statement-block, se ejecuta
repetidamente hasta que se comprueba que la expresión de control es True. La
expresión de control se evalúa antes de cada ejecución del cuerpo del bucle.

La expresión for-initializer se evalúa antes de la primera evaluación de la expresión de


control. De la expresión for-initializer solo se evalúan sus efectos secundarios; cualquier
valor que genera se descarta y no se escribe en la canalización.
La expresión for-iterator se evalúa después de cada ejecución del cuerpo del bucle. De la
expresión for-iterator solo se evalúan sus efectos secundarios; cualquier valor que
genera se descarta y no se escribe en la canalización.

Si la expresión for-condition se omite, se comprueba que la expresión de control es True.

Ejemplos:

PowerShell

for ($i = 5; $i -ge 1; --$i) { # loop 5 times


"{0,1}`t{1,2}" -f $i, ($i * $i)
}

$i = 5
for (; $i -ge 1; ) { # equivalent behavior
"{0,1}`t{1,2}" -f $i, ($i * $i)
--$i
}

8.4.4 Instrucción foreach


Sintaxis:

Syntax

foreach-statement:
foreach new-lines~opt~ foreach-parameter~opt~ new-lines~opt~
( new-lines~opt~ variable new-lines~opt~ *in* new-lines~opt~
pipeline
new-lines~opt~ ) statement-block

foreach-parameter:
-parallel

Descripción:

Se ejecuta el cuerpo del bucle, que incluye statement-block, para cada elemento
designado por la instancia de variable en la colección designada por la canalización
pipeline. El ámbito de variable no se limita a la instrucción foreach. Por lo tanto,
conserva su valor final una vez que el cuerpo del bucle haya terminado de ejecutarse. Si
pipeline designa un valor escalar (excepto el valor $null) en lugar de una colección, se
trata como colección de un elemento. Si pipeline designa el valor $null , entonces
pipeline se trata como una colección de cero elementos.
Si se especifica el parámetro foreach-parameter -parallel , el comportamiento lo define
la implementación.

El parámetro foreach-parameter ‑parallel solo se permite en un flujo de trabajo


(§8.10.2).

Cada instrucción foreach tiene su propio enumerador, $foreach (§2.3.2.2, §4.5.16), que
solo existe mientras se ejecuta ese bucle.

Los objetos generados por la canalización pipeline se recopilan antes de que statement-
block comience a ejecutarse. Sin embargo, con el cmdlet ForEach-Object, statement-
block se ejecuta en cada objeto a medida que se genera.

Ejemplos:

PowerShell

$a = 10, 53, 16, -43


foreach ($e in $a) {
...
}
$e # the int value -43

foreach ($e in -5..5) {


...
}

foreach ($t in [byte], [int], [long]) {


$t::MaxValue # get static property
}

foreach ($f in Get-ChildItem *.txt) {


...
}

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }


foreach ($e in $h1.Keys) {
"Key is " + $e + ", Value is " + $h1[$e]
}

8.5 Instrucciones de control de flujo


Sintaxis:

Syntax

flow-control-statement:
break label-expression~opt~
continue label-expression~opt~
throw pipeline~opt~
return pipeline~opt~
exit pipeline~opt~

label-expression:
simple-name
unary-expression

Descripción:

Una instrucción flow-control provoca una transferencia incondicional del control a otra
ubicación.

8.5.1 Instrucción break


Descripción:

Una instrucción break con un elemento label-expression se conoce como instrucción


break con etiqueta. Una instrucción break sin un elemento label-expression se conoce
como instrucción break sin etiqueta.

Fuera de una instrucción trap, una instrucción break sin etiqueta incluida directamente
en una instrucción de iteración (§8.4) finaliza la ejecución de esa instrucción de iteración
envolvente más pequeña. Una instrucción break sin etiqueta incluida directamente en
una instrucción switch (§8.6) finaliza la coincidencia de patrones para la condición
switch-condition del modificador actual. Consulte la sección (§8.8) para obtener más
detalles sobre el uso de break desde dentro de una instrucción trap.

Una instrucción de iteración o una instrucción switch también puede ir precedida de


forma inmediata por una etiqueta de instrucción (§8.1.1). Dicha etiqueta de instrucción
se puede usar como destino de una instrucción break con etiqueta y, en ese caso, la
instrucción finaliza la ejecución de la instrucción de iteración envolvente de destino.

No es necesario resolver una instrucción break con etiqueta en ningún ámbito local; la
búsqueda de una etiqueta coincidente puede continuar en la pila de llamadas, incluso
más allá de los límites de script y de llamadas a funciones. Si no se encuentra ninguna
etiqueta coincidente, se termina la invocación del comando actual.

El nombre de la etiqueta designada por label-expression no necesita tener un valor


constante.

Si label-expression es de tipo unary-expression, se convierte en una cadena.

Ejemplos:
PowerShell

$i = 1
while ($true) { # infinite loop
if ($i * $i -gt 100) {
break # break out of current while loop
}
++$i
}

$lab = "go_here"
:go_here
for ($i = 1; ; ++$i) {
if ($i * $i -gt 50) {
break $lab # use a string value as target
}
}

:labelA
for ($i = 1; $i -le 2; $i++) {

:labelB
for ($j = 1; $j -le 2; $j++) {

:labelC
for ($k = 1; $k -le 3; $k++) {
if (...) { break labelA }
}
}
}

8.5.2 Instrucción continue


Descripción:

Una instrucción continue con un elemento label-expression se conoce como instrucción


continue con etiqueta. Una instrucción continue sin un elemento label-expression se
conoce como instrucción continue sin etiqueta.

El uso de continue desde una instrucción trap se analiza en la sección §8.8.

Una instrucción continue sin etiqueta dentro de un bucle finaliza la ejecución del bucle
actual y transfiere el control a la llave de cierre de la instrucción de iteración envolvente
más pequeña (§8.4). Una instrucción continue sin etiqueta dentro de un modificador
switch finaliza la ejecución de la iteración switch actual y transfiere el control a la
condición switch-condition del elemento switch envolvente más pequeño (§8.6).
Una instrucción de iteración o una instrucción switch (§8.6) puede ir precedida de
forma inmediata por una etiqueta de instrucción (§8.1.1). Dicha etiqueta se puede usar
como destino de una instrucción continue con etiqueta incluida; en ese caso, la
instrucción finaliza la ejecución del bucle o la iteración switch actual y transfiere el
control a la etiqueta de instrucción switch o iteración envolvente de destino.

No es necesario resolver una instrucción continue con etiqueta en ningún ámbito local;
la búsqueda de una etiqueta coincidente puede aplicar continue hasta la pila de
llamadas, incluso más allá de los límites de script y de llamadas a funciones. Si no se
encuentra ninguna etiqueta coincidente, se termina la invocación del comando actual.

El nombre de la etiqueta designada por label-expression no necesita tener un valor


constante.

Si label-expression es de tipo unary-expression, se convierte en una cadena.

Ejemplos:

PowerShell

$i = 1
while (...) {
...
if (...) {
continue # start next iteration of current loop
}
...
}

$lab = "go_here"
:go_here
for (...; ...; ...) {
if (...) {
continue $lab # start next iteration of labeled loop
}
}

:labelA
for ($i = 1; $i -le 2; $i++) {

:labelB
for ($j = 1; $j -le 2; $j++) {

:labelC
for ($k = 1; $k -le 3; $k++) {
if (...) { continue labelB }
}
}
}
8.5.3 Instrucción throw
Descripción:

Una excepción es una forma de controlar una condición de error en el nivel del sistema
o de la aplicación. La instrucción throw genera una excepción. (Consulte la sección §8.7
para ver un análisis del control de excepciones).

Si la canalización pipeline se omite y la instrucción throw no está en una cláusula catch-


clause, el comportamiento lo define la implementación. Si la canalización pipeline está
presente y la instrucción throw está en una cláusula catch-clause, la excepción detectada
por catch-clause se vuelve a generar después de ejecutar cualquier cláusula finally-
clause asociada a catch-clause.

Si pipeline está presente, el tipo de excepción que se produce lo define la


implementación.

Cuando se produce una excepción, el control se transfiere a la primera cláusula catch de


una instrucción try envolvente que pueda controlar la excepción. La ubicación en la que
la excepción se produce inicialmente se denomina punto de inicio. Una vez que se inicia
una excepción, se siguen los pasos descritos en la sección §8.7 repetidamente hasta que
se encuentre una cláusula catch que coincida con la excepción o no se encuentre
ninguna.

Ejemplos:

PowerShell

throw
throw 100
throw "No such record in file"

Si se omite pipeline y la instrucción throw no está incluida en una cláusula catch-clause,


se escribe el texto "ScriptHalted" en la canalización y el tipo de excepción que se genera
es System.Management.Automation.RuntimeException .

Si pipeline está presente, la excepción que se genera se encapsula en un objeto de tipo


System.Management.Automation.RuntimeException , que incluye información sobre la
excepción como objeto System.Management.Automation.ErrorRecord (al que se puede
acceder a través de $_ ).

Ejemplo 1: throw 123 da como resultado una excepción de tipo RuntimeException.


Dentro del bloque catch, $_.TargetObject contiene el objeto encapsulado; en este caso
System.Int32 con el valor 123.
Ejemplo 2: throw "xxx" da como resultado una excepción de tipo RuntimeException.
Dentro del bloque catch, $_.TargetObject contiene el objeto encapsulado; en este caso
System.String con el valor "xxx".

Ejemplo 3: throw 10,20 da como resultado una excepción de tipo RuntimeException.


Dentro del bloque catch, $_.TargetObject contiene el objeto encapsulado; en este caso
System.Object[] , una matriz de dos elementos sin restricciones con los valores 10 y 20

de System .Int32.

8.5.4 Instrucción return


Descripción:

La instrucción return escribe en la canalización los valores designados por pipeline, si


los hay, y devuelve el control al autor de llamada del script o la función. Una función o
script puede tener cero o más instrucciones return .

Si la ejecución llega hasta la llave de cierre de una función, se asume un valor return
implícito sin pipeline.

La instrucción return simplifica la sintaxis para permitir que los programadores puedan
expresarse como lo hacen en otros lenguajes; sin embargo, el valor que devuelve una
función o script en realidad incluye todos los valores escritos en la canalización por esa
función o script más cualquier valor especificado por la canalización pipeline. Si solo se
escribe un valor escalar en la canalización, su tipo es el mismo del valor devuelto. De lo
contrario, el tipo de valor devuelto es una matriz unidimensional sin restricciones que
contiene todos los valores escritos en la canalización.

Ejemplos:

PowerShell

function Get-Factorial ($v) {


if ($v -eq 1) {
return 1 # return is not optional
}

return $v * (Get-Factorial ($v - 1)) # return is optional


}

El autor de llamada a Get-Factorial obtiene un valor int .

PowerShell
function Test {
"text1" # "text1" is written to the pipeline
# ...
"text2" # "text2" is written to the pipeline
# ...
return 123 # 123 is written to the pipeline
}

El autor de llamada a Test obtiene una matriz unidimensional sin restricciones de tres
elementos.

8.5.5 Instrucción exit


Descripción:

La instrucción exit finaliza el script actual y devuelve el control y un código de salida al


entorno host o al script de llamada. Si se proporciona pipeline, el valor que designa se
convierte en int, si es necesario. Si no existe dicha conversión o pipeline se omite, se
devuelve el valor int cero.

Ejemplos:

PowerShell

exit $count # terminate the script with some accumulated count

8.6 Instrucción switch


Sintaxis:

Syntax

switch-statement:
switch new-lines~opt~ switch-parameters~opt~ switch-condition switch-
body

switch-parameters:
switch-parameter
switch-parameters switch-parameter

switch-parameter:
-regex
-wildcard
-exact
-casesensitive
-parallel
switch-condition:
( new-lines~opt~ pipeline new-lines~opt~ )
-file new-lines~opt~ switch-filename

switch-filename:
command-argument
primary-expression

switch-body:
new-lines~opt~ { new-lines~opt~ switch-clauses }

switch-clauses:
switch-clause
switch-clauses switch-clause

switch-clause:
switch-clause-condition statement-block statement-terimators~opt~

switch-clause-condition:
command-argument
primary-expression

Descripción:

Si la condición switch-condition designa un valor único, el control se pasa a uno o varios


bloques de instrucciones de patrones correspondientes. Si no hay patrones que
coincidan, se puede realizar alguna acción predeterminada.

Un modificador debe contener una o varias cláusulas switch-clause, cada una


empezando con un patrón (una cláusula switch no predeterminada) o la contraseña
default (una cláusula switch predeterminada). Un modificador debe contener cero o

una cláusula switch default y cero o más cláusulas switch no predeterminadas. Las
cláusulas switch se pueden escribir en cualquier orden.

Varios patrones pueden tener el mismo valor. Un patrón no puede ser un literal y un
modificador puede tener patrones con tipos diferentes.

Si el valor de switch-condition coincide con un valor de patrón, se ejecuta el elemento


statement-block de ese patrón. Si varios valores de patrón coinciden con el valor de
switch-condition, se ejecuta el elemento statement-block de cada patrón coincidente, en
orden léxico, a menos que uno de esos elementos statement-block contengan una
instrucción break statement (§8.5.1).

Si el valor de switch-condition no coincide con ningún valor de patrón, si existe una


cláusula switch default , se ejecuta su elemento statement-block. De lo contrario, se
finaliza la coincidencia de patrones para esa switch-condition.
Los modificadores se pueden anidar y cada uno de ellos tiene su propio conjunto de
cláusulas switch. En tales casos, una cláusula switch pertenece al modificador más
interno actualmente en el ámbito.

En la entrada a cada elemento statement-block, se le asigna automáticamente a $_ el


valor de condición switch-condition que hizo que el control pasará a ese elemento
statement-block. $_ también está disponible en la switch-clause-condition de ese
elemento statement-block.

La coincidencia de no-cadenas se realiza mediante pruebas de igualdad (§7.8.1).

De manera predeterminada, si la coincidencia implica cadenas, la comparación no


distingue entre mayúsculas y minúsculas. La presencia de switch-parameter -
casesensitive hace que la comparación distinga mayúsculas de minúsculas.

Un patrón puede contener caracteres comodín (§3.15); en ese caso, se realizan


comparaciones entre las cadenas con caracteres comodín, pero solo si está presente el
parámetro switch-parameter -wildcard. De manera predeterminada, la comparación
distingue mayúsculas de minúsculas.

Un patrón puede contener una expresión regular (§3.16); en ese caso, se realizan
comparaciones entre las cadenas con expresiones regulares, pero solo si está presente
el parámetro switch-parameter -regex . De manera predeterminada, la comparación
distingue mayúsculas de minúsculas. Si -regex está presente y hay coincidencia con un
patrón, se define $matches en el elemento statement-block de la cláusula switch-clause
de ese patrón.

Se puede abreviar un parámetro switch-parameter; es posible utilizar cualquier parte


inicial distintiva de un parámetro. Por ejemplo, ‑regex , ‑rege , ‑reg , ‑re y ‑r son
equivalentes.

Si se especifican parámetros switch-parameter en conflicto, tiene prioridad el último


especificado en términos léxicos. La presencia de ‑exact deshabilita a -regex y -
wildcard ; sin embargo, no tiene efecto en ‑case .

Si se especifica el parámetro switch-parameter ‑parallel , el comportamiento lo define


la implementación.

El parámetro switch-parameter ‑parallel solo se permite en un flujo de trabajo


(§8.10.2).

Si un patrón es una expresión script-block-expression, se evalúa ese bloque y el resultado


se convierte en bool, si es necesario. Si el resultado tiene el valor $true , se ejecuta el
elemento statement-block correspondiente; de lo contrario, no se ejecuta.

Si la condición switch-condition designa varios valores, se aplica el modificador a cada


valor en orden léxico con las reglas descritas anteriormente para una condición switch-
condition que designa un valor único. Cada instrucción switch tiene su propio
enumerador, $switch (§2.3.2.2, §4.5.16), que solo existe mientras se ejecuta ese
modificador.

Una instrucción switch puede tener una etiqueta y puede incluir instrucciones break
(§8.5.1) y continue (§8.5.2) con y sin etiqueta.

Si la condición switch-condition es -file switch-filename, en lugar de recorrer en


iteración los valores de una expresión, el modificador recorre en iteración los valores del
archivo que se designa en switch-filename. El archivo se lee una línea a la vez y cada
línea comprende un valor. Los caracteres de terminador de línea no se incluyen en los
valores.

Ejemplos:

PowerShell

$s = "ABC def`nghi`tjkl`fmno @#$"


$charCount = 0; $pageCount = 0; $lineCount = 0; $otherCount = 0
for ($i = 0; $i -lt $s.Length; ++$i) {
++$charCount
switch ($s[$i]) {
"`n" { ++$lineCount }
"`f" { ++$pageCount }
"`t" { }
" " { }
default { ++$otherCount }
}
}

switch -wildcard ("abc") {


a* { "a*, $_" }
?B? { "?B? , $_" }
default { "default, $_" }
}

switch -regex -casesensitive ("abc") {


^a* { "a*" }
^A* { "A*" }
}

switch (0, 1, 19, 20, 21) {


{ $_ -lt 20 } { "-lt 20" }
{ $_ -band 1 } { "Odd" }
{ $_ -eq 19 } { "-eq 19" }
default { "default" }
}

8.7 La instrucción try/finally


Sintaxis:

Syntax

try-statement:
try statement-block catch-clauses
try statement-block finally-clause
try statement-block catch-clauses finally-clause

catch-clauses:
catch-clause
catch-clauses catch-clause

catch-clause:
new-lines~opt~ catch catch-type-list~opt~
statement-block

catch-type-list:
new-lines~opt~ type-literal
catch-type-list new-lines~opt~ , new-lines~opt~

type-literalfinally-clause:
new-lines~opt~ finally statement-block

Descripción:

La instrucción try proporciona un mecanismo para detectar excepciones que se


producen al ejecutar un elemento de bloque. La instrucción try también proporciona la
capacidad de especificar un bloque de código que siempre se ejecuta cuando el control
sale de la instrucción try. El proceso de generar una excepción a través de la instrucción
throw se describe en §8.5.3.

Un bloque try es el elemento statement-block asociado con la instrucción try. Un bloque


catch es el elemento statement-block asociado con una cláusula catch-clause. Un bloque
finally es el elemento statement-block asociado con una cláusula finally-clause.

Una cláusula catch-clause sin una lista catch-type-list se conoce como cláusula catch
general.

Cada cláusula catch-clause es un controlador de excepciones y una cláusula catch-clause


cuya lista catch-type-list contiene el tipo de excepción generada es una cláusula catch
coincidente. Una cláusula catch general coincide con todos los tipos de excepción.

Aunque las cláusulas catch-clauses y finally-clause son opcionales, debe estar presente
al menos una de ellas.

El procesamiento de una excepción generada consiste en evaluar los pasos siguientes


varias veces hasta encontrar una cláusula catch que coincida con la excepción.

En el ámbito actual, se examina cada instrucción try que incluye el punto de inicio.
Para cada instrucción try S, se evalúan los pasos siguientes, empezando por la
instrucción try más interna y finalizando con la más externa:

Si el bloque try de S incluye el punto de inicio y si S tiene una o varias


cláusulas catch, estas cláusulas catch se examinan en orden léxico para buscar
un controlador adecuado para la excepción. La primera cláusula catch que
especifica el tipo de excepción o un tipo base del tipo de excepción se
considera una coincidencia. Una cláusula catch general se considera una
coincidencia para cualquier tipo de excepción. Si se encuentra una cláusula
catch coincidente, el procesamiento de la excepción se completa al transferir el
control al bloque de esa cláusula catch. Dentro de una cláusula catch
coincidente, la variable $_ contiene una descripción de la excepción actual.

De lo contrario, si el bloque try o un bloque catch de S incluye el punto de


inicio y si S tiene un bloque finally , el control se transfiere al bloque finally. Si
el bloque finally genera otra excepción, finaliza el procesamiento de la
excepción actual. De lo contrario, cuando el control llega al final del bloque
finally , se continúa el procesamiento de la excepción actual.

Si no se encontró un controlador de excepciones en el ámbito actual, se repiten los


pasos anteriores para el ámbito que incluye un punto de inicio correspondiente a
la instrucción desde la que se invocó el ámbito actual.

Si el procesamiento de excepciones se completa y finaliza todos los ámbitos, lo


que indica que no hay controlador para la excepción, no se especifica el
comportamiento.

Para evitar cláusulas catch inaccesibles en un bloque try, es posible que una cláusula
catch no especifique un tipo de excepción igual o derivado de un tipo especificado en
una cláusula catch anterior dentro de ese mismo bloque try.

Las instrucciones de un bloque finally siempre se ejecutan cuando el control sale de


una instrucción try . Esto se cumple si la transferencia del control se produce como
resultado de una ejecución normal, como resultado de la ejecución de una instrucción
break , continue o return , o como resultado de una excepción generada a partir de la

instrucción try .

Si se genera una excepción al ejecutar un bloque finally , la excepción se genera en la


instrucción try de inclusión siguiente. Si se estaba procesando el control de otra
excepción, esa excepción se perderá. El proceso de generar una excepción se analiza
más detalladamente en la descripción de la instrucción throw .

Las instrucciones try pueden coexistir con las instrucciones trap ; consulte §8.8 para
más detalles.

Ejemplos:

PowerShell

$a = new-object 'int[]' 10
$i = 20 # out-of-bounds subscript

while ($true) {
try {
$a[$i] = 10
"Assignment completed without error"
break
}

catch [IndexOutOfRangeException] {
"Handling out-of-bounds index, >$_<`n"
$i = 5
}

catch {
"Caught unexpected exception"
}

finally {
# ...
}
}

Cada excepción iniciada se genera como


System.Management.Automation.RuntimeException . Si hay cláusulas catch-clause
específicas del tipo en el bloque try , se inspecciona la propiedad InnerException de la
excepción para intentar encontrar una coincidencia, tal como ocurre con el
tipo System.IndexOutOfRangeException mencionado anteriormente.

8.8 La instrucción trap


Sintaxis:

Syntax

trap-statement:
*trap* new-lines~opt~ type-literal~opt~ new-lines~opt~ statement-block

Descripción:

Una instrucción trap con y sin type-literal es análoga a un bloque catch (§8.7) con y sin
catch-type-list, respectivamente, excepto en que una instrucción trap solo puede
interceptar un tipo a la vez.

Se pueden definir varias instrucciones trap en el mismo elemento statement-block y su


orden de definición no es relevante. Si se definen dos instrucciones trap con el mismo
type-literal en el mismo ámbito, se usa la primera en orden léxico para procesar una
excepción de tipo coincidente.

A diferencia de un bloque catch , una instrucción trap coincide exactamente con un


tipo de excepción; no se realiza ninguna coincidencia de tipo derivado.

Cuando se produce una excepción, si no hay ninguna instrucción trap coincidente en el


ámbito actual, se busca una instrucción trap coincidente en el ámbito de inclusión, lo
que puede implicar buscar en el script de llamada, la función o el filtro y, luego, en el
autor de llamada, y así sucesivamente. Si la búsqueda se completa y finaliza todos los
ámbitos, lo que indica que no hay controlador para la excepción, no se especifica el
comportamiento.

El cuerpo statement-body de una instrucción trap se ejecuta solo para procesar la


excepción correspondiente; de lo contrario, la ejecución la pasa por alto.

Si el cuerpo statement-body de una instrucción trap se cierra de forma normal, de


manera predeterminada se escribe un objeto de error en la secuencia de error, la
excepción se considera controlada y la ejecución continúa con la instrucción
inmediatamente posterior a la del ámbito que contiene la instrucción trap que hizo
visible la excepción. La causa de la excepción podría estar en un comando llamado por
el comando que contiene la instrucción trap .

Si la instrucción final ejecutada en el cuerpo statement-body de una instrucción trap es


continua (§8.5.2), se suprime la escritura del objeto de error en la secuencia de error y la
ejecución continúa con la instrucción inmediatamente posterior a la del ámbito que
contiene la instrucción trap que hizo visible la excepción. Si la instrucción final ejecutada
en el cuerpo statement-body de una instrucción trap se interrumpe (§8.5.1), se suprime
la escritura del objeto de error en la secuencia de error y se vuelve a generar la
excepción.

Dentro de una instrucción trap , la variable $_ contiene una descripción del error actual.

Considere el caso en el que una excepción iniciada a partir de un bloque try no tiene
un bloque catch coincidente, pero sí existe una instrucción trap coincidente en un
nivel de bloque superior. Una vez que se ejecuta la cláusula finally del bloque try , la
instrucción trap obtiene el control incluso si algún ámbito primario tiene un bloque
catch coincidente. Si se define una instrucción trap dentro del bloque try mismo y

ese bloque try tiene un bloque catch coincidente, la instrucción trap obtiene el
control.

Ejemplos:

En el ejemplo siguiente, se escribe el objeto de error y la ejecución continúa con la


instrucción inmediatamente posterior a la que generó la intercepción; es decir, se
escribe "Donde" (Listo) en la canalización.

PowerShell

$j = 0; $v = 10/$j; "Done"
trap { $j = 2 }

En el ejemplo siguiente, se suprime la escritura del objeto de error y la ejecución


continúa con la instrucción inmediatamente posterior a la que generó la intercepción; es
decir, se escribe "Donde" (Listo) en la canalización.

PowerShell

$j = 0; $v = 10/$j; "Done"
trap { $j = 2; continue }

En el ejemplo siguiente, se suprime la escritura del objeto de error y se vuelve a generar


la excepción.

PowerShell

$j = 0; $v = 10/$j; "Done"
trap { $j = 2; break }

En el ejemplo siguiente, las instrucciones trap y exception-generating se encuentran en


el mismo ámbito. Una vez detectada y controlada la excepción, se reanuda la ejecución
escribiendo 1 en la canalización.

PowerShell

&{trap{}; throw '\...'; 1}

En el ejemplo siguiente, las instrucciones trap y exception-generating se encuentran en


ámbitos distintos. Una vez detectada y controlada la excepción, se reanuda la ejecución
escribiendo 2 (no 1) en la canalización.

PowerShell

trap{} &{throw '\...'; 1}; 2

8.9 La instrucción de datos


Sintaxis:

Syntax

data-statement:
data new-lines~opt~ data-name data-commands-allowed~opt~ statement-block

data-name:
simple-name

data-commands-allowed:
new-lines~opt~ -supportedcommand data-commands-list

data-commands-list:
new-lines~opt~ data-command
data-commands-list , new-lines~opt~ data-command

data-command:
command-name-expr

Descripción:

Una instrucción de datos crea una sección de datos para mantener los datos de esa
sección separados del código. Esta separación admite funciones como archivos de
recursos de cadenas independientes para texto, como mensajes de error y cadenas de
ayuda. También ayuda a admitir la internacionalización al facilitar el aislamiento, la
localización y el procesamiento de cadenas que se traducirán a distintos idiomas.

Un script o una función puede tener cero o más secciones de datos.


El elemento statement-block de una sección de datos se limita a contener solo las
características de PowerShell siguientes:

Todos los operadores, excepto -match


Instrucción if
Estas variables automáticas: $PsCulture , $PsUICulture , $true , $false y $null .
Comentarios
Procesos
Instrucciones separadas por punto y coma ( ; )
Literales
Llamadas al cmdlet ConvertFrom-StringData
Cualquier otro cmdlet identificado mediante el parámetro supportedcommand

Si se usa el cmdlet ConvertFrom-StringData , los pares clave-valor se pueden expresar


con cualquier forma de literal de cadena. Sin embargo, los literales expandable-string-
literal y expandable-here-string-literal no pueden contener ninguna sustitución de
variables ni expansiones de subexpresiones.

Ejemplos:

El parámetro SupportedCommand indica que solo los cmdlets o funciones que se


especificaron generan datos. Por ejemplo, la sección de datos siguiente incluye un
cmdlet escrito por el usuario, ConvertTo-XML , que da formato a los datos de un archivo
XML:

PowerShell

data -supportedCommand ConvertTo-XML {


Format-XML -strings string1, string2, string3
}

Considere el ejemplo siguiente, en el que la sección de datos contiene un comando


ConvertFrom-StringData que convierte las cadenas en una tabla hash, cuyo valor se

asigna a $messages .

PowerShell

$messages = data {
ConvertFrom-StringData -stringdata @'
Greeting = Hello
Yes = yes
No = no
'@
}
Es posible acceder a las claves y los valores de la tabla hash mediante
$messages.Greeting , $messages.Yes y $messages.No , respectivamente.

Ahora, esto se puede guardar como un recurso en inglés. Se pueden crear recursos en
alemán y español en otros archivos, con las secciones de datos siguientes:

PowerShell

$messages = data {
ConvertFrom-StringData -stringdata @"
Greeting = Guten Tag
Yes = ja
No = nein
"@
}

$messagesS = data {
ConvertFrom-StringData -stringdata @"
Greeting = Buenos días
Yes = sí
No = no
"@
}

Si está presente dataname, asigna un nombre a la variable (sin usar $ al inicio) en la que
se almacenará el valor de la instrucción de datos. En concreto, $name = data { ... } es
equivalente a data name { ... } .

8.10 Definiciones de función


Sintaxis:

Syntax

function-statement:
function new-lines~opt~ function-name function-parameter-
declaration~opt~ { script-block }
filter new-lines~opt~ function-name function-parameter-declaration~opt~
{ script-block }
workflow new-lines~opt~ function-name function-parameter-
declaration~opt~ { script-block }

function-name:
command-argument

command-argument:
command-name-expr

function-parameter-declaration:
new-lines~opt~ ( parameter-list new-lines~opt~ )

parameter-list:
script-parameter
parameter-list new-lines~opt~ , script-parameter

script-parameter:
new-lines~opt~ attribute-list~opt~ new-lines~opt~ variable script-
parameter-default~opt~

script-block:
param-block~opt~ statement-terminators~opt~ script-block-body~opt~

param-block:
new-lines~opt~ attribute-list~opt~ new-lines~opt~ param new-lines~opt~
( parameter-list~opt~ new-lines~opt~ )

parameter-list:
script-parameter
parameter-list new-lines~opt~ , script-parameter

script-parameter-default:
new-lines~opt~ = new-lines~opt~ expression

script-block-body:
named-block-list
statement-list

named-block-list:
named-block
named-block-list named-block

named-block:
block-name statement-block statement-terminators~opt~

block-name: one of
dynamicparam begin process end

Descripción:

Una definición de función especifica el nombre de la función, el filtro o el flujo de trabajo


que se define y los nombres de sus parámetros, si corresponde. También contiene cero
o más instrucciones que se ejecutan para lograr el propósito de esa función.

Cada función es una instancia de la clase System.Management.Automation.FunctionInfo .

8.10.1 Funciones de filtro


Mientras que una función normal se ejecuta una vez en una canalización y accede a la
colección de entrada a través de $input , un filtro es un tipo especial de función que se
ejecuta una vez para cada objeto en la colección de entrada. El objeto que se procesa
actualmente está disponible a través de la variable $_ .

Un filtro con bloques sin nombre (§8.10.7) es equivalente a una función con un bloque
process, pero sin ningún bloque begin ni end.

Tenga en cuenta esta definición de función de filtro y estas llamadas:

PowerShell

filter Get-Square2 { # make the function a filter


$_ * $_ # access current object from the collection
}

-3..3 | Get-Square2 # collection has 7 elements


6, 10, -3 | Get-Square2 # collection has 3 elements

Cada filtro es una instancia de la clase System.Management.Automation.FilterInfo


(§4.5.11).

8.10.2 Funciones de flujo de trabajo


Una función de flujo de trabajo es como una función normal con semántica definida por
la implementación. Una función de flujo de trabajo se convierte en una secuencia de
actividades de Windows Workflow Foundation y se ejecuta en el motor de
Windows Workflow Foundation.

8.10.3 Procesamiento de argumentos


Tenga en cuenta la definición siguiente de una función denominada Get-Power :

PowerShell

function Get-Power ([long]$base, [int]$exponent) {


$result = 1
for ($i = 1; $i -le $exponent; ++$i) {
$result *= $base
}
return $result
}

Esta función tiene dos parámetros, $base y $exponent . También contiene un conjunto de
instrucciones que, en el caso de los valores de exponente no negativos, calcula
$base^$exponent^ y devuelve el resultado al autor de las llamada de Get-Power .
Cuando un script, una función o un filtro comienza a ejecutarse, se inicializa cada
parámetro en el valor de su argumento correspondiente. Si no hay ningún argumento
correspondiente y se suministra un valor predeterminado (§8.10.4), se usa ese valor; de
lo contrario, se usa el valor $null . De ese modo, cada parámetro es una variable nueva
del mismo modo que si se hubiese inicializado mediante asignación al inicio del
elemento script-block.

Si un parámetro script-parameter contiene una restricción de tipo (como [long] y


[int] , mencionadas anteriormente), el valor del argumento correspondiente se

convierte en ese tipo, si fuese necesario; de lo contrario, no se produce ninguna


conversión.

Cuando un script, una función o un filtro comienza a ejecutarse, se define la variable


$args dentro como una matriz unidimensional sin restricciones que contiene todos los
argumentos no enlazados por nombre o posición, en orden léxico.

Tenga en cuenta la definición de función y las llamadas siguientes:

PowerShell

function F ($a, $b, $c, $d) { ... }

F -b 3 -d 5 2 4 # $a is 2, $b is 3, $c is 4, $d is 5, $args Length 0
F -a 2 -d 3 4 5 # $a is 2, $b is 4, $c is 5, $d is 3, $args Length 0
F 2 3 4 5 -c 7 -a 1 # $a is 1, $b is 2, $c is 7, $d is 3, $args Length 2

Para más información sobre el enlace de parámetros, consulte §8.14.

8.10.4 Inicializadores de parámetros


La declaración de un parámetro p puede contener un inicializador; en ese caso, se usa el
valor de ese inicializador para inicializar el parámetro p, siempre que p no esté enlazado
a ningún argumento de la llamada.

Tenga en cuenta la definición de función y las llamadas siguientes:

PowerShell

function Find-Str ([string]$str, [int]$start_pos = 0) { ... }

Find-Str "abcabc" # 2nd argument omitted, 0 used for $start_pos


Find-Str "abcabc" 2 # 2nd argument present, so it is used for $start_pos
8.10.5 Restricción de tipo [switch]
Cuando se pasa un parámetro de modificador, se debe restringir el parámetro
correspondiente en el comando según el modificador de tipo. El modificador de tipo
tiene dos valores, True y False.

Tenga en cuenta la definición de función y las llamadas siguientes:

PowerShell

function Process ([switch]$trace, $p1, $p2) { ... }

Process 10 20 # $trace is False, $p1 is 10, $p2 is 20


Process 10 -trace 20 # $trace is True, $p1 is 10, $p2 is 20
Process 10 20 -trace # $trace is True, $p1 is 10, $p2 is 20
Process 10 20 -trace:$false # $trace is False, $p1 is 10, $p2 is 20
Process 10 20 -trace:$true # $trace is True, $p1 is 10, $p2 is 20

8.10.6 Canalizaciones y funciones


Cuando se usa un script, una función o un filtro en una canalización, se entrega una
colección de valores a ese script o función. El script, la función o el filtro obtiene acceso
a esa colección a través del enumerador $input (§2.3.2.2, §4.5.16), que se define en la
entrada a ese script, esa función o ese filtro.

Tenga en cuenta la definición de función y las llamadas siguientes:

PowerShell

function Get-Square1 {
foreach ($i in $input) { # iterate over the collection
$i * $i
}
}

-3..3 | Get-Square1 # collection has 7 elements


6, 10, -3 | Get-Square1 # collection has 3 elements

8.10.7 Bloques con nombre


Las instrucciones dentro de un elemento script-block pueden pertenecer a un bloque sin
nombre de gran tamaño, o bien se pueden distribuir en uno o varios bloques con
nombre. Los bloques con nombre permiten el procesamiento personalizado de las
colecciones que provienen de canalizaciones y este tipo de bloques se puede definir en
cualquier orden.
Las instrucciones que se encuentran en un bloque begin (es decir, uno marcado con la
palabra clave begin) se ejecutan una vez, antes de que se entregue el primer objeto de
canalización.

Las instrucciones que se encuentran en un bloque process (es decir, uno marcado con la
palabra clave process) se ejecutan para cada objeto de canalización entregado. ( $_
proporciona acceso al objeto que se está procesando desde la colección de entrada
procedente de la canalización). Esto significa que si se envía una colección de cero
elementos a través de la canalización, el bloque process no se ejecuta en absoluto. Sin
embargo, si se llama al script o la función fuera de un contexto de canalización, este
bloque se ejecuta exactamente una vez y $_ se establece en $null , porque no hay
ningún objeto de colección actual.

Las instrucciones que se encuentran en un bloque end (es decir, uno marcado con la
palabra clave end) se ejecutan una vez, después de que se entrega el último objeto de
canalización.

8.10.8 Bloque dynamicParam


Hasta ahora, las subsecciones de §8.10 hablan de parámetros estáticos, que se definen
como parte del código fuente. También es posible definir parámetros dinámicos a través
de un bloque dynamicParam, otra forma de bloque con nombre (§8.10.7), que se marca
con la palabra clave dynamicParam . Gran parte de esta maquinaria está definida en la
implementación.

Los parámetros dinámicos son parámetros de un cmdlet, una función, un filtro o un


script que están disponibles solo bajo determinadas condiciones. Uno de estos casos es
el parámetro Encoding del cmdlet Set-Item .

En el elemento statement-block, utilice una instrucción if para especificar las condiciones


en las que el parámetro está disponible en la función. Use el cmdlet New-Object a fin de
crear un objeto de un tipo definido por la implementación para representar el
parámetro y especifique su nombre. Además, use New-Object para crear un objeto de
un tipo definido por la implementación distinto a fin de representar los atributos del
parámetro definidos por la implementación.

En el ejemplo siguiente se muestra una función con parámetros estándar denominados


Name y Path, y un parámetro dinámico opcional denominado DP1. El parámetro DP1 se
encuentra en el conjunto de parámetros PSet1 y tiene un tipo de Int32 . El parámetro
DP1 está disponible en la función Sample solo cuando el valor del parámetro Path
contiene "HKLM:", lo que indica que se utiliza en la unidad del Registro
HKEY_LOCAL_MACHINE .
PowerShell

function Sample {
Param ([String]$Name, [String]$Path)
DynamicParam {
if ($path -match "*HKLM*:") {
$dynParam1 = New-Object
System.Management.Automation.RuntimeDefinedParameter("dp1", [Int32],
$attributeCollection)

$attributes = New-Object
System.Management.Automation.ParameterAttribute
$attributes.ParameterSetName = 'pset1'
$attributes.Mandatory = $false

$attributeCollection = New-Object -Type


System.Collections.ObjectModel.Collection``1[System.Attribute]
$attributeCollection.Add($attributes)

$paramDictionary = New-Object
System.Management.Automation.RuntimeDefinedParameterDictionary
$paramDictionary.Add("dp1", $dynParam1)
return $paramDictionary
}
}
}

El tipo que se usa para crear un objeto que represente un parámetro dinámico es
System.Management.Automation.RuntimeDefinedParameter .

El tipo que se usa para crear un objeto que represente los atributos del parámetro es
System.Management.Automation.ParameterAttribute .

Los atributos del parámetro definidos por la implementación incluyen Mandatory,


Position y ValueFromPipeline.

8.10.9 Bloque param


Un bloque param-block proporciona una manera alternativa para declarar parámetros.
Por ejemplo, los conjuntos siguientes de declaraciones de parámetro son equivalentes:

PowerShell

function FindStr1 ([string]$str, [int]$start_pos = 0) { ... }


function FindStr2 {
param ([string]$str, [int]$start_pos = 0) ...
}
Un bloque param-block permite una lista attribute-list en el bloque param-block,
mientras que una declaración function-parameter-declaration no lo hace.

Un script puede tener un bloque param-block, pero no una declaración function-


parameter-declaration. Una definición de filtro o función puede tener una claración
function-parameter-declaration o un bloque param-block, pero no ambos.

Considere el ejemplo siguiente:

PowerShell

param ( [Parameter(Mandatory = $true, ValueFromPipeline=$true)]


[string[]] $ComputerName )

El único parámetro, $ComputerName , tiene el tipo string[] , es necesario y toma la


entrada de la canalización.

Consulte §12.3.7 para ver un análisis del atributo Parameter y más ejemplos.

8.11 La instrucción parallel


Sintaxis:

Syntax

parallel-statement:
*parallel* statement-block

La instrucción parallel contiene cero o más instrucciones que se ejecutan de una manera
definida por la implementación.

Una instrucción paralela solo se permite en un flujo de trabajo (§8.10.2).

8.12 La instrucción de secuencia


Sintaxis:

Syntax

sequence-statement:
*sequence* statement-block
La instrucción de secuencia contiene cero o más instrucciones que se ejecutan de una
manera definida por la implementación.

Una instrucción de secuencia solo se permite en un flujo de trabajo (§8.10.2).

8.13 La instrucción InlineScript


Sintaxis:

Syntax

inlinescript-statement:
inlinescript statement-block

La instrucción InlineScript contiene cero o más instrucciones que se ejecutan de una


manera definida por la implementación.

Una instrucción InlineScript solo se permite en un flujo de trabajo (§8.10.2).

8.14 Enlace de parámetros


Cuando se invoca un script, una función, un filtro o un cmdlet, cada argumento se
puede enlazar al parámetro correspondiente por posición, teniendo posición cero el
primer parámetro.

Tenga en cuenta el siguiente fragmento de definición para una función denominada


Get-Power y las llamadas a esta:

PowerShell

function Get-Power ([long]$base, [int]$exponent) { ... }

Get-Power 5 3 # argument 5 is bound to parameter $base in position 0


# argument 3 is bound to parameter $exponent in position
1
# no conversion is needed, and the result is 5 to the
power 3

Get-Power 4.7 3.2 # double argument 4.7 is rounded to int 5, double


argument
# 3.2 is rounded to int 3, and result is 5 to the power
3

Get-Power 5 # $exponent has value $null, which is converted to int 0


Get-Power # both parameters have value $null, which is converted
to int 0

Cuando se invoca un script, una función, un filtro o un cmdlet, se puede enlazar un


argumento al parámetro correspondiente por nombre. Para ello, se usa un parámetro
con argumento, que es un argumento que es el nombre del parámetro con un guion
inicial (-), seguido del valor asociado de ese argumento. El nombre del parámetro
utilizado puede tener cualquier ortografía sin distinción de mayúsculas y minúsculas, y
puede usar cualquier prefijo que designe de forma única el parámetro correspondiente.
Al elegir nombres del parámetro, evite usar los nombres de los parámetros comunes.

Tenga en cuenta las siguientes llamadas a la función Get-Power :

PowerShell

Get-Power -base 5 -exponent 3 # -base designates $base, so 5 is


# bound to that, exponent designates
# $exponent, so 3 is bound to that

Get-Power -Exp 3 -BAs 5 # $base takes on 5 and $exponent takes on 3

Get-Power -e 3 -b 5 # $base takes on 5 and $exponent takes on 3

Por otro lado, las llamadas a la función siguiente

PowerShell

function Get-Hypot ([double]$side1, [double]$side2) {


return [Math]::Sqrt($side1 * $side1 + $side2 * $side2)
}

debe usar los parámetros -side1 y -side2 , ya que no hay ningún prefijo que designe
solamente el parámetro.

El mismo nombre del parámetro no se puede usar varias veces con o sin valores de
argumento asociados diferentes.

Los parámetros pueden tener atributos (§12). Para obtener información sobre los
atributos individuales, consulte §12.3. Para obtener información acerca de los conjuntos
de parámetros, consulte §12.3.7.

Un script, una función, un filtro o un cmdlet puede recibir argumentos a través de la


línea de comandos de invocación, de la canalización, o de ambas. Estos son los pasos,
en orden, para resolver el enlace de parámetros:
1. Enlace todos los parámetros con nombre y, a continuación,
2. Enlace los parámetros posicionales y, a continuación,
3. Enlace desde la canalización por valor (§12.3.7) con coincidencia exacta y, a
continuación,
4. Enlace desde la canalización por valor (§12.3.7) con conversión y, a continuación,
5. Enlace desde la canalización por nombre (§12.3.7) con coincidencia exacta y, a
continuación,
6. Enlace desde la canalización por nombre (§12.3.7) con conversión

Algunos de estos pasos implican la conversión, tal como se describe en §6. Sin embargo,
el conjunto de conversiones usadas en el enlace no es exactamente el mismo que el que
se usa en las conversiones del lenguaje. Concretamente, puede:

Aunque el valor $null se puede convertir a booleano, $null no se puede enlazar


a bool .
Cuando el valor $null se pasa a un parámetro de modificador para un cmdlet, se
trata como si se pasara $true . Sin embargo, cuando se pasa a un parámetro de
modificador para una función, se trata como si se pasara $false .
Los parámetros de tipo booleano o modificador solo se pueden enlazar a
argumentos numéricos o booleanos.
Si el tipo de parámetro no es una colección, pero el argumento es algún tipo de
colección, no se intenta realizar ninguna conversión a menos que el tipo de
parámetro sea object o PsObject (el punto principal de esta restricción es no
permitir la conversión de una colección en un parámetro de cadena). De lo
contrario, se intentan realizar las conversiones habituales.

Si el tipo de parámetro es IList o ICollection<T> , solo se intentarán realizar esas


conversiones a través de Constructor, op_Implicit y op_Explicit. Si no existen tales
conversiones, se usa una conversión especial para parámetros de tipo "colección", que
incluye IList , ICollection<T> y matrices.

Los parámetros posicionales prefieren enlazarse sin conversión de tipos, si es posible.


Por ejemplo,

PowerShell

function Test {
[CmdletBinding(DefaultParameterSetname = "SetB")]
param([Parameter(Position = 0, ParameterSetname = "SetA")]
[decimal]$dec,
[Parameter(Position = 0, ParameterSetname = "SetB")]
[int]$in
)
$PsCmdlet.ParameterSetName
}

Test 42d # outputs "SetA"


Test 42 # outputs "SetB"
9. Matrices
Artículo • 10/03/2022

9.1. Introducción
PowerShell admite matrices de una o varias dimensiones con cada dimensión con cero o
más elementos. Dentro de una dimensión, los elementos se numeran en orden entero
ascendente a partir de cero. Se puede acceder a cualquier elemento individual a través
del operador de subíndice de matriz [] (§7.1.4). El número de dimensiones de una
matriz se conoce como rango.

Un elemento puede contener un valor de cualquier tipo, como un tipo de matriz. Una
matriz que tiene uno o varios elementos cuyos valores son de cualquier tipo de matriz
se conoce como matriz escalonada. Una matriz multidimensional tiene varias
dimensiones, en cuyo caso, el número de elementos de cada fila de una dimensión es el
mismo. Un elemento de una matriz escalonada puede contener una matriz
multidimensional y viceversa.

Las matrices multidimensionales se almacenan en orden de fila principal. El número de


elementos de una matriz es lo que se conoce como la longitud de dicha matriz, que se
fija cuando se crea esta. Por lo tanto, se puede acceder a los elementos de una matriz
unidimensional A con longitud N (es decir, subindexada) mediante las expresiones A[0],
A[1], ..., A[N-1] . Se puede acceder a los elementos de una matriz bidimensional B

que tenga M filas, teniendo cada fila N columnas, mediante las expresiones B[0,0],
B[0,1], ..., B[0,N-1], B[1,0], B[1,1], ..., B[1,N-1], ..., B[M-1,0], B[M-1,1], ...,

B[M-1,N-1] . Y así sucesivamente para matrices con tres o más dimensiones.

De forma predeterminada, una matriz es polimórfica, es decir, los elementos no


necesitan tener todos el mismo tipo. Por ejemplo,

PowerShell

$items = 10,"blue",12.54e3,16.30D # 1-D array of length 4


$items[1] = -2.345
$items[2] = "green"

$a = New-Object 'object[,]' 2,2 # 2-D array of length 4


$a[0,0] = 10
$a[0,1] = $false
$a[1,0] = "red"
$a[1,1] = $null
Una matriz unidimensional tiene el tipo type[] , una matriz bidimensional tiene el tipo
type[,] , una matriz tridimensional tiene el tipo type[,,] , y así sucesivamente, donde
type es objeto de una matriz de tipo no restringido, o bien el tipo restringido de una
matriz restringida (§9.4).

Todos los tipos de matriz derivan del tipo Matriz (§4.3.2).

9.2. Creación de matrices


Una matriz se crea a través de una expresión de creación de matrices, que tiene las
formas siguientes: operador de coma unario (§7.2.1), array-expression (§7.1.7), operador
de coma binario (§7.3), operador de intervalo (§7.4) o cmdlet New-Object.

Estos son algunos ejemplos de creación y uso de matrices:

PowerShell

$values = 10, 20, 30


for ($i = 0; $i -lt $values.Length; ++$i) {
"`$values[$i] = $($values[$i])"
}

$x = , 10 # x refers to an array of length 1


$x = @(10) # x refers to an array of length 1
$x = @() # x refers to an array of length 0

$a = New-Object 'object[,]' 2, 2 # create a 2x2 array of anything


$a[0, 0] = 10 # set to an int value
$a[0, 1] = $false # set to a boolean value
$a[1, 0] = "red" # set to a string value
$a[1, 1] = 10.50D # set to a decimal value
foreach ($e in $a) { # enumerate over the whole array
$e
}

Lo siguiente se escribe en la canalización:

Output

$values[0] = 10
$values[1] = 20
$values[2] = 30

10
False
red
10.50
El valor inicial predeterminado de cualquier elemento no inicializado explícitamente es
el valor predeterminado del tipo de ese elemento (es decir, $false , cero o $null ).

9.3. Concatenación de matrices


Las matrices de tipo y longitud arbitrarios se pueden concatenar a través de los
operadores + y += , lo que resulta en la creación de una matriz unidimensional sin
restricciones. Las matrices existentes no se modifican. Consulte §7.7.3 para obtener más
información y §9.4 para ver una discusión sobre cómo agregar contenido a una matriz
de tipo restringido.

9.4. Restricción de tipos de elemento


Se puede crear una matriz unidimensional para que esté restringida por tipos
antefijando la expresión de creación de matriz con una conversión de tipo de matriz. Por
ejemplo,

PowerShell

$a = [int[]](1,2,3,4) # constrained to int


$a[1] = "abc" # implementation-defined behavior
$a += 1.23 # new array is unconstrained

La sintaxis para crear una matriz multidimensional requiere la especificación de un tipo,


que se convierte en el tipo de restricción de esa matriz. Sin embargo, al especificar el
tipo object[] , realmente no hay ninguna restricción, ya que se puede asignar un valor
cualquiera a un elemento de una matriz de ese tipo.

La concatenación de dos matrices (§7.7.3) siempre da como resultado una nueva matriz
sin restricciones, aunque ambas estén restringidas por el mismo tipo. Por ejemplo,

PowerShell

$a = [int[]](1,2,3) # constrained to int


$b = [int[]](10,20) # constrained to int
$c = $a + $b # constraint not preserved
$c = [int[]]($a + $b) # result explicitly constrained to int

9.5. Matrices como tipos de referencia


Como los tipos de matriz son tipos de referencia, se puede crear una variable que
designe una matriz para hacer referencia a cualquier matriz de cualquier rango, longitud
y tipo de elemento. Por ejemplo,

PowerShell

$a = 10,20 # $a refers to an array of length 2


$a = 10,20,30 # $a refers to a different array, of length 3
$a = "red",10.6 # $a refers to a different array, of length 2
$a = New-Object 'int[,]' 2,3 # $a refers to an array of rank 2

La asignación de una matriz implica una copia superficial, es decir, la variable a la que se
asigna hace referencia a la misma matriz, no se realiza ninguna copia. Por ejemplo,

PowerShell

$a = 10,20,30
">$a<"
$b = $a # make $b refer to the same array as $a
">$b<"

$a[0] = 6 # change value of [0] via $a


">$a<"
">$b<" # change is reflected in $b

$b += 40 # make $b refer to a new array


$a[0] = 8 # change value of [0] via $a
">$a<"
">$b<" # change is not reflected in $b

Lo siguiente se escribe en la canalización:

Output

>10 20 30<
>10 20 30<
>6 20 30<
>6 20 30<
>8 20 30<
>6 20 30 40<

9.6. Matrices como elementos de matriz


Cualquier elemento de una matriz puede ser una matriz. Por ejemplo,

PowerShell
$colors = "red", "blue", "green"
$list = $colors, (,7), (1.2, "yes") # parens in (,7) are redundant; they
# are intended to aid readability
"`$list refers to an array of length $($list.Length)"
">$($list[1][0])<"
">$($list[2][1])<"

Lo siguiente se escribe en la canalización:

Output

$list refers to an array of length 3


>7<
>yes<

$list[1] hace referencia a una matriz de 1 elemento, el entero 7, al que se accede a

través de $list[1][0] , como se muestra. Compárelo con el caso sutilmente diferente


siguiente:

PowerShell

$list = $colors, 7, (1.2, "yes") # 7 has no prefix comma


">$($list[1])<"

Aquí, $list[1] hace referencia a un valor escalar, el entero 7, al que se accede a través
de $list[1] .

Considere el ejemplo siguiente:

PowerShell

$x = [string[]]("red","green")
$y = 12.5, $true, "blue"
$a = New-Object 'object[,]' 2,2
$a[0,0] = $x # element is an array of 2 strings
$a[0,1] = 20 # element is an int
$a[1,0] = $y # element is an array of 3 objects
$a[1,1] = [int[]](92,93) # element is an array of 2 ints

9.7 Subíndice negativo


Se describe en §7.1.4.1.
9.8. Comprobación de límites
Se describe en §7.1.4.1.

9.9. Segmentos de matriz


Un segmento de matriz es una matriz unidimensional sin restricciones cuyos elementos
son copias de cero o más elementos de una colección. Se crea a través del operador de
subíndice [] (§7.1.4.5).

9.10. Copia de una matriz


Un conjunto contiguo de elementos se puede copiar de una matriz a otra mediante el
método [Array]::Copy . Por ejemplo,

PowerShell

$a = [int[]](10,20,30)
$b = [int[]](0,1,2,3,4,5)
[Array]::Copy($a, $b, 2) # $a[0]->$b[0],
$a[1]->$b[1]
[Array]::Copy($a, 1, $b, 3, 2) # $a[1]->$b[3],
$a[2]->$b[4]

9.11. Enumeración en una matriz


Aunque es posible recorrer en bucle una matriz que accede a cada uno de sus
elementos a través del operador de subíndice, podemos enumerar los elementos de esa
matriz mediante la instrucción foreach. En una matriz multidimensional, los elementos
se procesan en orden de fila principal. Por ejemplo,

PowerShell

$a = 10, 53, 16, -43


foreach ($elem in $a) {
# do something with element via $e
}

foreach ($elem in -5..5) {


# do something with element via $e
}

$a = New-Object 'int[,]' 3, 2
foreach ($elem in $a) {
# do something with element via $e
}

9.12. Aplanamiento de una matriz


multidimensional
Algunas operaciones de una matriz multidimensional (como la replicación [§7.6.3] y la
concatenación [§7.7.3]) requieren que esa matriz se aplane, es decir, que se convierta en
una matriz unidimensional de tipo no restringido. La matriz resultante toma todos los
elementos en orden de fila principal.

Considere el ejemplo siguiente:

PowerShell

$a = "red",$true
$b = (New-Object 'int[,]' 2,2)
$b[0,0] = 10
$b[0,1] = 20
$b[1,0] = 30
$b[1,1] = 40
$c = $a + $b

La matriz designada por $c contiene los elementos "red", $true , 10, 20, 30 y 40.
10 Tablas hash
Artículo • 16/03/2022

Sintaxis:

 Sugerencia

La notación ~opt~ en las definiciones de sintaxis indica que la entidad léxica es


opcional en la sintaxis.

Syntax

hash-literal-expression:
@{ new-lines~opt~ hash-literal-body~opt~ new-lines~opt~ }

hash-literal-body:
hash-entry
hash-literal-body statement-terminators hash-entry

hash-entry:
key-expression = new-lines~opt~ statement

key-expression:
simple-name
unary-expression

statement-terminator:
;
new-line-character

10.1 Introducción
El tipo tabla hash representa una colección de objetos de par clave-valor que admite la
recuperación eficaz de un valor cuando se indexa mediante la clave. Cada par clave-
valor es un elemento, que se almacena en algún tipo de objeto definido por la
implementación.

La clave de un elemento no puede ser el valor NULL. No hay ninguna restricción en el


tipo de una clave o valor. No se admiten claves duplicadas.

Dado un objeto de par clave-valor, la clave y el valor asociados se pueden obtener


mediante las propiedades de instancia Key y Value, respectivamente.
Dada una o varias claves, se puede acceder a los valores correspondientes mediante el
operador de subíndice Hashtable [] (sección 7.1.4.3).

Todas las tablas hash tienen el tipo Hashtable (sección 4.3.3).

No se especifica el orden de las claves de la colección que devuelve Keys, pero es el


mismo orden que los valores asociados en la colección que devuelve Values.

Estos son algunos ejemplos que implican tablas hash:

PowerShell

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }


$h1.FirstName # designates the key FirstName
$h1["LastName"] # designates the associated value for key LastName
$h1.Keys # gets the collection of keys

Los elementos Hashtable se almacenan en un objeto de tipo DictionaryEntry y las


colecciones que devuelve Keys y Values tienen el tipo ICollection.

10.2 Creación de tablas hash


Un elemento Hashtable se crea mediante un literal hash (sección 7.1.9) o el cmdlet
New-Object. Se puede crear con cero o más elementos. La propiedad Count devuelve el
recuento de elementos actual.

10.3 Incorporación y eliminación de elementos


de tabla hash
Un elemento se puede agregar a Hashtable asignando (sección 7.11.1) un valor a un
nombre de clave inexistente o a un subíndice (sección 7.1.4.3) que usa un nombre de
clave inexistente. La eliminación de un elemento requiere el uso del método Remove.
Por ejemplo,

PowerShell

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }


$h1.Dept = "Finance" # adds element Finance
$h1["Salaried"] = $false # adds element Salaried
$h1.Remove("Salaried") # removes element Salaried
10.4 Concatenación de tabla hash
Las tablas hash se pueden concatenar mediante los operadores + y += , lo que da como
resultado la creación de un elemento Hashtable . Las tablas hash existentes no se
modifican. Vea la sección 7.7.4 para obtener más información.

10.5 Tablas hash como tipos de referencia


Puesto que Hashtable es un tipo de referencia, la asignación de un elemento Hashtable
implica una copia superficial, es decir, la variable a la que se asigna hace referencia a la
misma Hashtable , no se realiza ninguna copia de Hashtable . Por ejemplo,

PowerShell

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123 }


$h2 = $h1
$h1.FirstName = "John" # change key's value in $h1
$h2.FirstName # change is reflected in $h2

10.6 Enumeración en una tabla hash


Para procesar cada par de un elemento Hashtable , use la propiedad Keys para recuperar
la lista de claves como una matriz y, después, enumere en los elementos de esa matriz
obteniendo el valor asociado mediante la propiedad Value o un subíndice, como se
muestra a continuación.

PowerShell

$h1 = @{ FirstName = "James"; LastName = "Anderson"; IDNum = 123}


foreach ($e in $h1.Keys) {
"Key is " + $e + ", Value is " + $h1[$e]
}
11. Módulos
Artículo • 09/03/2022

11.1 Introducción
Tal como se indica §3.14, un módulo es una unidad independiente y reutilizable que
permite particionar, organizar y abstraer el código de PowerShell. Un módulo puede
contener uno o varios miembros de módulo, que son comandos (como cmdlets y
funciones) y elementos (como variables y alias). Los nombres de estos miembros se
pueden mantener en privado en el módulo o se pueden exportar a la sesión en la que se
importa el módulo.

Hay tres tipos de módulos distintos: manifiesto, script y binario. Un módulo de manifiesto
es un archivo que contiene información sobre un módulo y controla aspectos
determinados del uso de ese módulo. Un módulo de script es un archivo de script de
PowerShell con la extensión de archivo .psm1 en lugar de .ps1 . Un módulo binario
contiene tipos de clase que definen cmdlets y proveedores. A diferencia de los módulos
de script, los módulos binarios se escriben en lenguajes compilados. Esta especificación
no abarca los módulos binarios.

Un módulo binario es un ensamblado .NET (es decir, una DLL) que se compiló en las
bibliotecas de PowerShell.

Los módulos se pueden anidar; es decir, un módulo puede importar otro módulo. Un
módulo que tiene asociados módulos anidados es un módulo raíz.

De manera predeterminada, cuando se crea una sesión de PowerShell, no se importa


ningún módulo.

Cuando se importan los módulos, la ruta de búsqueda que se usa para localizarlos se
define en la variable de entorno PSModulePath.

Estos cmdlets se encargan de los módulos:

Get-Module: identifica los módulos que se importaron o que se pueden importar


Import-Module: agrega uno o varios módulos a la sesión actual (consulte §11.4)
Export-ModuleMember: identifica los miembros de módulo que se van a exportar
Remove-Module: quita uno o varios módulos de la sesión actual (consulte §11.5)
New-Module: crea un módulo dinámico (consulte §11.7)

11.2 Escritura de un módulo de script


Un módulo de script es un archivo de script. Considere el módulo de script siguiente:

PowerShell

function Convert-CentigradeToFahrenheit ([double]$tempC) {


return ($tempC * (9.0 / 5.0)) + 32.0
}
New-Alias c2f Convert-CentigradeToFahrenheit

function Convert-FahrenheitToCentigrade ([double]$tempF) {


return ($tempF - 32.0) * (5.0 / 9.0)
}
New-Alias f2c Convert-FahrenheitToCentigrade

Export-ModuleMember -Function Convert-CentigradeToFahrenheit


Export-ModuleMember -Function Convert-FahrenheitToCentigrade
Export-ModuleMember -Alias c2f, f2c

Este módulo contiene dos funciones y cada una de las cuales tiene un alias. De manera
predeterminada, solo se exportan todos los nombres de función. Sin embargo, una vez
que se usa Export-ModuleMember para exportar algo, solo se exportará lo que se exportó
explícitamente. Se puede exportar una serie de comandos y elementos en una o varias
llamadas a este cmdlet; estas llamadas son acumulativas para la sesión actual.

11.3 Instalación de un módulo de script


Un módulo de script se define en un archivo de script y los módulos se pueden
almacenar en cualquier directorio. La variable de entorno PSModulePath apunta a un
conjunto de directorios en los que se buscará cuando los cmdlets relacionados con
módulos busquen módulos cuyos nombres no incluyan una ruta de acceso absoluta. Se
pueden proporcionar rutas de búsqueda adicionales; por ejemplo,

$Env:PSModulepath = $Env:PSModulepath + ";<additional-path>"

Las rutas de acceso adicionales agregadas solo afectan a la sesión actual.

Como alternativa, se puede especificar una ruta de acceso completa cuando se importa
un módulo.

11.4 Importación de un módulo de script


Si desea utilizar los recursos de un módulo, ese módulo se debe importar a la sesión
actual con el cmdlet Import-Module . Import-Module puede restringir los recursos que
importan realmente.
Cuando se importa un módulo, se ejecuta su archivo de script. Se puede configurar ese
proceso al definir uno o varios parámetros del archivo de script y pasar los argumentos
correspondientes a través del parámetro ArgumentList de Import-Module .

Considere el script siguiente que utiliza estas funciones y alias que se definen en §11.2:

Import-Module "E:\Scripts\Modules\PSTest_Temperature" -Verbose

PowerShell

"0 degrees C is &quot; + (Convert-CentigradeToFahrenheit 0) + &quot; degrees


F"
"100 degrees C is " + (c2f 100) + " degrees F"
"32 degrees F is " + (Convert-FahrenheitToCentigrade 32) + " degrees C"
"212 degrees F is " + (f2c 212) + " degrees C"

La importación de un módulo provoca un conflicto de nombres si los comandos o


elementos del módulo tienen los mismos nombres que los comandos o elementos de la
sesión. Si hay un conflicto de nombres, se oculta o reemplaza un nombre. Puede usar el
parámetro Prefix de Import-Module para evitar los conflictos de nombres. Además, los
parámetros Alias, Cmdlet, Function y Variable pueden limitar la selección de comandos
que se van a importar, lo que disminuye las posibilidades de que haya un conflicto de
nombres.

Incluso si hay un comando oculto, se puede ejecutar si se califica su nombre con


respecto al nombre del módulo en el que se originó. Por ejemplo, & M\F 100 invoca la
función F en el módulo M y le pasa el argumento 100.

Cuando la sesión incluye comandos del mismo tipo con el mismo nombre, como dos
cmdlets con el mismo nombre, de forma predeterminada ejecuta el comando agregado
más recientemente.

Consulte §3.5.6 si desea ver un análisis del ámbito en relación con los módulos.

11.5 Eliminación de un módulo de script


Es posible quitar uno o varios módulos de una sesión a través del cmdlet Remove-Module .

Si quita un módulo, dicho módulo no se desinstala.

En un módulo de script, es posible especificar el código que se va a ejecutar antes de


quitar el módulo, tal como se muestra a continuación:

$MyInvocation.MyCommand.ScriptBlock.Module.OnRemove = { *on-removal-code* }
11.6 Manifiestos de módulo
Tal como se estableció en §11.1, un módulo de manifiesto es un archivo que contiene
información sobre un módulo y controla aspectos determinados del uso de ese módulo.

No es necesario que un módulo tenga un manifiesto correspondiente pero, si lo hace,


ese manifiesto tiene el mismo nombre que el módulo que describe, pero con una
extensión de archivo .psd1 .

Un manifiesto contiene un subconjunto limitado de script de PowerShell, lo que


devuelve una tabla hash que contiene un conjunto de claves. Estas claves y sus valores
especifican los elementos de manifiesto de ese módulo. Es decir, describen el contenido
y los atributos del módulo, definen los requisitos previos y determinan cómo se
procesan los componentes.

En esencia, un manifiesto es un archivo de datos; sin embargo, puede contener


referencias a tipos de datos, la instrucción if y los operadores aritméticos y de
comparación. (No se permiten bucles y definiciones de función y asignaciones). Un
manifiesto también tiene acceso de lectura a las variables de entorno y puede contener
llamadas al cmdlet Join-Path , por lo que se pueden construir rutas de acceso.

7 Nota

Nota del editor: El documento original contiene una lista de claves permitidas en
un archivo de manifiesto de módulo. Esa lista está obsoleta e incompleta. Para una
lista completa de las claves de un manifiesto de módulo, consulte New-
ModuleManifest.

La única clave obligatoria es ModuleVersion.

A continuación, verá un ejemplo de un manifiesto sencillo:

PowerShell

@{
ModuleVersion = '1.0'
Author = 'John Doe'
RequiredModules = @()
FunctionsToExport = 'Set*','Get*','Process*'
}

La clave GUID tiene un valor string . Esto especifica un identificador único global (GUID)
para el módulo. El GUID se puede utilizar para distinguir los módulos que tienen el
mismo nombre. Para llamar a un GUID nuevo, llame al método [guid]::NewGuid() .

11.7 Módulos dinámicos


Un módulo dinámico es un módulo que se crea en memoria que el cmdlet New-Module
crea en memoria en tiempo de ejecución. No se carga desde el disco. Considere el
ejemplo siguiente:

PowerShell

$sb = {
function Convert-CentigradeToFahrenheit ([double]$tempC) {
return ($tempC * (9.0 / 5.0)) + 32.0
}

New-Alias c2f Convert-CentigradeToFahrenheit

function Convert-FahrenheitToCentigrade ([double]$tempF) {


return ($tempF - 32.0) * (5.0 / 9.0)
}

New-Alias f2c Convert-FahrenheitToCentigrade

Export-ModuleMember -Function Convert-CentigradeToFahrenheit


Export-ModuleMember -Function Convert-FahrenheitToCentigrade
Export-ModuleMember -Alias c2f, f2c
}

New-Module -Name MyDynMod -ScriptBlock $sb


Convert-CentigradeToFahrenheit 100
c2f 100

El bloque de script $sb define el contenido del módulo. En este caso, dos funciones y
dos alias a esas funciones. Al igual que ocurre con un módulo en disco, solo las
funciones se exportan de manera predeterminada, por lo que existen llamadas a
cmdlets Export-ModuleMember para exportar tanto las funciones como los alias.

Una vez que New-Module se ejecuta, los cuatro nombres exportados están disponibles
para su uso en la sesión, tal como se muestra en las llamadas a Convert-
CentigradeToFahrenheit y c2f.

Al igual que todos los módulos, los miembros de los módulos dinámicos se ejecutan en
un ámbito de módulo privado que es un elemento secundario del ámbito global. Get-
Module no puede obtener un módulo dinámico, pero Get-Command puede obtener
miembros exportados.
Si desea que el módulo dinámico esté disponible para Get-Module , canalice un comando
New-Module a Import-Module , o bien canalice el objeto de módulo que New-Module
devuelve, a Import-Module . Esta acción agrega el módulo dinámico a la lista Get-Module ,
pero no guarda el módulo en el disco ni lo hace persistente.

11.8 Clausuras
Se puede usar un módulo dinámico para crear una función clausura, una función con
datos adjuntos. Considere el ejemplo siguiente:

PowerShell

function Get-NextID ([int]$startValue = 1) {


$nextID = $startValue
{
($script:nextID++)
}.GetNewClosure()
}

$v1 = Get-NextID # get a scriptblock with $startValue of 0


& $v1 # invoke Get-NextID getting back 1
& $v1 # invoke Get-NextID getting back 1

$v2 = Get-NextID 100 # get a scriptblock with $startValue of 100


& $v2 # invoke Get-NextID getting back 100
& $v2 # invoke Get-NextID getting back 101

La intención aquí es que Get-NextID devuelva el id. siguiente en una secuencia en la que
se puede especificar el valor. Sin embargo, se admiten varias secuencias, cada una con
su propio contexto $startValue y $nextID . Esto se logra con una llamada al método
[scriptblock]::GetNewClosure (§4.3.7).

Cada vez que GetNewClosure crea una clausura nueva, se crea un módulo dinámico
nuevo y las variables del ámbito del autor de la llamada (en este caso, el bloque de
script que contiene el incremento) se copian en este módulo nuevo. Para asegurarse de
que el valor de nextId definido dentro de la función primaria (pero fuera del bloque de
script) se incremente, se necesita el prefijo script: scope explícito.

Por supuesto, no es necesario que el bloque de script sea una función sin nombre, por
ejemplo:

PowerShell

$v3 = & { # get a scriptblock with $startValue of 200


param ([int]$startValue = 1)
$nextID = $startValue
{
($script:nextID++)
}.GetNewClosure()
} 200

& $v3 # invoke script getting back 200


& $v3 # invoke script getting back 201
12. Atributos
Artículo • 16/03/2022

Un objeto de atributo asocia información predefinida del sistema a un elemento de


destino, que puede ser un bloque de parámetros o un parámetro (sección 8.10). Cada
objeto de atributo tiene un tipo de atributo.

La información que proporciona un atributo también se conoce como metadatos. Los


metadatos se pueden examinar mediante el comando o el entorno de ejecución para
controlar cómo el comando procesa los datos o, antes del tiempo de ejecución,
mediante herramientas externas para controlar cómo se procesa o mantiene el propio
comando.

Se pueden aplicar varios atributos al mismo elemento de destino.

12.1 Especificación de atributos

 Sugerencia

La notación ~opt~ en las definiciones de sintaxis indica que la entidad léxica es


opcional en la sintaxis.

Syntax

attribute-list:
attribute
attribute-list new-lines~opt~ attribute

attribute:
[ new-lines~opt~ attribute-name ( attribute-arguments new-lines~opt~ )
new-lines~opt~ ]
type-literal

attribute-name:
type-spec

attribute-arguments:
attribute-argument
attribute-argument new-lines~opt~ ,
attribute-arguments

attribute-argument:
new-lines~opt~ expression
new-lines~opt~ simple-name
new-lines~opt~ simple-name = new-lines~opt~ expression
Un atributo consta de un nombre de atributo y una lista opcional de argumentos
posicionales y con nombre. Los argumentos posicionales (si los hay) preceden a los
argumentos con nombre. Un argumento con nombre consta de un nombre simple,
seguido opcionalmente de un signo igual y de una expresión. Si se omite la expresión, se
asume el valor $true .

El nombre de atributo es un tipo de atributo reservado (sección 12.3) o algún tipo de


atributo definido por la implementación.

12.2 Instancias de atributo


Una instancia de atributo es un objeto de un tipo de atributo. La instancia representa un
atributo en tiempo de ejecución.

Para crear un objeto de algún tipo de atributo A, use la notación A() . Un atributo se
declara incluyendo su instancia dentro de [] , como en [A()] . Algunos tipos de atributo
tienen parámetros posicionales y con nombre (sección 8.14), al igual que las funciones y
los cmdlets. Por ejemplo,

[A(10,IgnoreCase=$true)]

muestra una instancia de tipo A que se crea con un parámetro posicional cuyo valor de
argumento es 10 y un parámetro con nombre, IgnoreCase, cuyo valor de argumento es
$true .

12.3 Atributos reservados


Los atributos descritos en las secciones siguientes se pueden usar para aumentar o
modificar el comportamiento de las funciones, filtros, scripts y cmdlets de PowerShell.

12.3.1 Alias (atributo)


Este atributo se usa en un parámetro de script a fin de especificar un nombre alternativo
para un parámetro. Un parámetro puede tener varios alias y cada nombre de alias debe
ser único dentro de una lista de parámetros. Un uso posible es tener nombres diferentes
para un parámetro en conjuntos de parámetros diferentes (vea ParameterSetName).

El argumento del atributo tiene el tipo string[].


Considere una llamada de función Test1 que tiene el bloque de parámetros siguiente y
a la que se llama tal como se muestra:

PowerShell

param (
[Parameter(Mandatory = $true)]
[Alias("CN")]
[Alias("name", "system")]
[string[]] $ComputerName
)

Test1 "Mars", "Saturn" # pass argument by position


Test1 -ComputerName "Mars", "Saturn" # pass argument by name
Test1 -CN "Mars", "Saturn" # pass argument using first alias
Test1 -name "Mars", "Saturn" # pass argument using second alias
Test1 -sys "Mars", "Saturn" # pass argument using third alias

Considere una llamada de función Test2 que tiene el bloque de parámetros siguiente y
a la que se llama tal como se muestra:

PowerShell

param (
[Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)]
[Alias('PSPath')]
[string] $LiteralPath
)

Get-ChildItem "E:\*.txt" | Test2 -LiteralPath { $_ ; "`n`t";


$_.FullName + ".bak" }
Get-ChildItem "E:\*.txt" | Test2

El cmdlet Get-ChildItem (alias Dir ) agrega al objeto y devuelve un elemento


NoteProperty nuevo de tipo string , denominado PSPath.

12.3.2 AllowEmptyCollection (atributo)


Este atributo se usa en un parámetro de script para permitir una colección vacía como
argumento de un parámetro obligatorio.

Considere una llamada de función Test que tiene el bloque de parámetros siguiente y a
la que se llama tal como se muestra:

PowerShell
param (
[parameter(Mandatory = $true)]
[AllowEmptyCollection()]
[string[]] $ComputerName
)

Test "Red", "Green" # $computerName has Length 2


Test "Red" # $computerName has Length 1
Test -comp @() # $computerName has Length 0

12.3.3 AllowEmptyString (atributo)


Este atributo se usa en un parámetro de script para permitir una cadena vacía como
argumento de un parámetro obligatorio.

Considere una llamada de función Test que tiene el bloque de parámetros siguiente y a
la que se llama tal como se muestra:

PowerShell

param (
[parameter(Mandatory = $true)]
[AllowEmptyString()]
[string] $ComputerName
)

Test "Red" # $computerName is "Red"


Test "" # empty string is permitted
Test -comp "" # empty string is permitted

12.3.4 AllowNull (atributo)


Este atributo se usa en un parámetro de script para permitir $null como argumento de
un parámetro obligatorio para el que no hay ninguna conversión implícita disponible.

Considere una llamada de función Test que tiene el siguiente bloque de parámetros y a
la que se llama tal como se muestra:

PowerShell

param (
[parameter(Mandatory = $true)]
[AllowNull()]
[int[]] $Values
)
Test 10, 20, 30 # $values has Length 3, values 10, 20, 30
Test 10, $null, 30 # $values has Length 3, values 10, 0, 30
Test -val $null # $values has value $null

Tenga en cuenta que el segundo caso anterior no necesita este atributo; ya hay una
conversión implícita de $null a int.

12.3.5 CmdletBinding (atributo)


Este atributo se usa en la lista de atributos del bloque de parámetros de una función para
indicar que la función actúa de forma similar a un cmdlet. En concreto, permite que las
funciones accedan a una serie de métodos y propiedades mediante la variable
$PsCmdlet, usando bloques con nombre de inicio, proceso y fin (sección 8.10.7).

Cuando este atributo está presente, los argumentos posicionales que no tienen
parámetros posicionales que coincidan provocan un error en el enlace de parámetros y
$args no está definido. (Sin este atributo, $args tomaría cualquier valor de argumento
posicional no coincidente).

Los argumentos siguientes se usan para definir las características del parámetro:

Nombre de parámetro Propósito

SupportsShouldProcess Tipo: bool. Valor predeterminado: $false


(con nombre)
Especifica si la función admite llamadas al método ShouldProcess,
que se usa para solicitar comentarios al usuario antes de que la
función haga un cambio en el sistema. Un valor $true indica que sí
las admite. Un valor $false indica que no las admite.
Nombre de parámetro Propósito

ConfirmImpact (con Tipo: cadena, valor predeterminado: "Medium"


nombre)
Especifica el nivel de impacto de la acción realizada. La llamada al
método ShouldProcess muestra un mensaje de confirmación solo
cuando el argumento ConfirmImpact es mayor o igual que el valor
de la variable de preferencia $ConfirmPreference.

Los valores posibles de este argumento son los siguientes:

None: suprime todas las solicitudes de confirmación.

Low: la acción realizada tiene un riesgo bajo de perder datos.

Medium: la acción realizada tiene un riesgo medio de perder datos.

High: la acción realizada tiene un riesgo alto de perder datos.

El valor de $ConfirmPreference se puede establecer para que solo


los cmdlets con un nivel de impacto igual o mayor puedan solicitar
confirmación antes de realizar su operación. Por ejemplo, si
$ConfirmPreference se establece en Medium, los cmdlets con un
nivel de impacto Medium o High pueden solicitar confirmación. Se
suprimen las solicitudes de cmdlets con un nivel de impacto bajo.

DefaultParameterSetName Tipo: cadena, valor predeterminado: "__AllParameterSets"


(con nombre)
Especifica el conjunto de parámetros que se va a usar si no se puede
determinar a partir de los argumentos. Vea el argumento con
nombre ParameterSetName en el atributo Parameter
([sección 12.3.7][sección 12.3.7]).

PositionalBinding (con Tipo: bool, valor predeterminado: $true


nombre)
Especifica si se admite o no el enlace posicional. El valor de este
argumento se omite si algún parámetro especifica valores no
predeterminados para los argumentos con nombre Position o
ParameterSetName en el atributo Parameter ([sección 12.3.7]
[sección 12.3.7]). De lo contrario, si el argumento es $false ningún
parámetro es posicional; si no, se asigna una posición a los
parámetros en función del orden en que se especifican los
parámetros.

Este es un ejemplo del marco para usar este atributo:

PowerShell

[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = "Low")]


param ( ... )

begin { ... }
Get-process { ... }
end { ... }

12.3.6 OutputType (atributo)


Este atributo se usa en la lista de atributos del bloque de parámetros para especificar los
tipos devueltos. Los argumentos siguientes se usan para definir las características del
parámetro:

Nombre de Propósito
parámetro

Tipo (posición 0) Tipo: string[] o matriz de literales de tipo

Una lista de los tipos de valores que se devuelven.

ParameterSetName Tipo: string[]


(con nombre)
Especifica los conjuntos de parámetros que devuelven los tipos que indican
los elementos correspondientes del parámetro Type.

Estos son algunos ejemplos del uso de este atributo:

PowerShell

[OutputType([int])] param ( ... )


[OutputType("double")] param ( ... )
[OutputType("string","string")] param ( ... )

12.3.7 Parameter (atributo)


Este atributo se usa en un parámetro de script. Los argumentos con nombre siguientes
se usan para definir las características del parámetro:

Parámetro Propósito
Parámetro Propósito

HelpMessage (con nombre) Type: cadena

Este argumento especifica un mensaje que está pensado


para incluir una breve descripción del parámetro. Este
mensaje se usa de una manera definida por la
implementación cuando se ejecuta la función o el cmdlet,
pero un parámetro obligatorio que tiene un elemento
HelpMessage no tiene un argumento correspondiente.

En el ejemplo siguiente se muestra una declaración de


parámetro que proporciona una descripción del parámetro.

parámetro ( [Parameter(Mandatory = $true,


HelpMessage = "Una matriz de nombres de equipo".)]
[string[]] $ComputerName )

Windows PowerShell: si no se proporciona un parámetro


necesario, el tiempo de ejecución solicita al usuario un valor
de parámetro. El cuadro de diálogo de la solicitud incluye el
texto HelpMessage.

Mandatory (con nombre) Tipo: bool. Valor predeterminado: $false

Este argumento especifica si el parámetro es necesario en el


conjunto de parámetros especificado (vea el argumento
ParameterSetName siguiente). Un valor $true indica que lo
es. Un valor $false indica que no lo es.

parámetro ( [Parameter(Mandatory = $true)]


[string[]] $ComputerName )

Windows PowerShell: si no se proporciona un parámetro


necesario, el tiempo de ejecución solicita al usuario un valor
de parámetro. El cuadro de diálogo de la solicitud incluye el
texto HelpMessage, si lo hay.

ParameterSetName (con nombre) Tipo: cadena, valor predeterminado: "__AllParameterSets"

Es posible escribir una sola función o cmdlet que pueda


realizar acciones diferentes para distintos escenarios. Para
ello, expone distintos grupos de parámetros en función de
la acción que quiera realizar. Estas agrupaciones de
parámetros se denominan conjuntos de parámetros.

El argumento ParameterSetName especifica el conjunto de


parámetros al que pertenece un parámetro. Este
comportamiento significa que cada conjunto de parámetros
debe tener un parámetro único que no sea miembro de
ningún otro conjunto de parámetros.
Parámetro Propósito

Para los parámetros que pertenecen a varios conjuntos de


parámetros, agregue un atributo Parameter en cada
conjunto de parámetros. Esto permite que el parámetro se
defina de forma diferente para cada conjunto de
parámetros.

Un conjunto de parámetros que contiene varios parámetros


posicionales debe definir posiciones únicas para cada
parámetro. No hay dos parámetros posicionales que
puedan especificar la misma posición.

Si no se especifica ningún conjunto de parámetros para un


parámetro, este pertenece a todos los conjuntos de
parámetros.

Cuando se definen varios conjuntos de parámetros, se usa


el argumento con nombre DefaultParameterSetName del
atributo CmdletBinding ([sección 12.3.5][sección 12.3.5])
para especificar el conjunto de parámetros predeterminado.
El tiempo de ejecución usa el conjunto de parámetros
predeterminado si no puede determinar el conjunto de
parámetros que se va a usar en función de la información
que proporciona el comando, o genera una excepción si no
se ha especificado ningún conjunto de parámetros
predeterminado.

En el ejemplo siguiente se muestra una función Test con


una declaración de parámetros de dos parámetros que
pertenecen a dos conjuntos de parámetros diferentes y un
tercer parámetro que pertenece a ambos conjuntos:

parámetro ( [Parameter(Mandatory = $true,


ParameterSetName = "Equipo")]
[string[]] $ComputerName,

[Parameter(Mandatory = $true,
ParameterSetName = "Usuario")]
[string[]] $UserName,

[Parameter(Mandatory = $true,
ParameterSetName = "Equipo")]
[Parameter(ParameterSetName = "Usuario")]
[int] $SharedParam = 5 )

if ($PsCmdlet.ParameterSetName -eq "Equipo")


{
# identificador del conjunto de parámetros "Equipo"
}
Parámetro Propósito

elseif ($PsCmdlet.ParameterSetName -eq "Usuario")


{
# identificador del conjunto de parámetros "Usuario"
}

}

Prueba -ComputerName "Marte","Venus" -SharedParam 10


Prueba -UserName "Mary","Jack"
Prueba -UserName "Mary","Jack" -SharedParam 20

Posición (con nombre) Tipo: int

Este argumento especifica la posición del parámetro en la


lista de argumentos. Si no se especifica este argumento, el
nombre del parámetro o su alias se deben especificar
explícitamente cuando se establece el parámetro. Si
ninguno de los parámetros de una función tiene posiciones,
las posiciones se asignan a cada parámetro en función del
orden en que se reciben.

En el ejemplo siguiente se muestra la declaración de un


parámetro cuyo valor debe especificarse como primer
argumento cuando se llama a la función.

parámetro ( [Parameter(Position = 0)]


[string[]] $ComputerName )
Parámetro Propósito

ValueFromPipeline (con nombre) Tipo: bool. Valor predeterminado: $false

Este argumento especifica si el parámetro acepta la entrada


de un objeto de canalización. Un valor $true indica que sí la
acepta. Un valor $false indica que no lo hace.

Especifique $true si la función o el cmdlet acceden al objeto


completo, no solo a una propiedad del objeto.

Solo un parámetro de un conjunto de parámetros puede


declarar ValueFromPipeline como $true.

En el ejemplo siguiente se muestra la declaración de


parámetro de un parámetro obligatorio, $ComputerName,
que acepta el objeto de entrada que se pasa a la función
desde la canalización.

parámetro ( [Parameter(Mandatory = $true,


ValueFromPipeline=$true)]
[string[]] $ComputerName )

Para obtener un ejemplo del uso de este parámetro junto


con el atributo Alias, vea la [sección 12.3.1][sección 12.3.1].

ValueFromPipelineByPropertyName Tipo: bool. Valor predeterminado: $false


(con nombre)
Este argumento especifica si el parámetro toma su valor de
una propiedad de un objeto de canalización que tiene el
mismo nombre o el mismo alias que este parámetro. Un
valor $true indica que sí lo hace. Un valor $false indica que
no lo hace.

Especifique $true si se cumplen las condiciones siguientes:


el parámetro tiene acceso a una propiedad del objeto
canalizado, y la propiedad tiene el mismo nombre que el
parámetro o la propiedad tiene el mismo alias que el
parámetro.

Un parámetro con ValueFromPipelineByPropertyName


establecido en $true no necesita tener un parámetro en el
mismo conjunto con ValueFromPipeline establecido en
$true.

Si una función tiene un parámetro $ComputerName y el


objeto canalizado tiene una propiedad ComputerName, el
valor de la propiedad ComputerName se asigna al
parámetro $ComputerName de la función:

parámetro ( [parameter(Mandatory = $true,


ValueFromPipelineByPropertyName = $true)]
Parámetro Propósito

[string[]] $ComputerName )

Varios parámetros de un conjunto de parámetros pueden


definir ValueFromPipelineByPropertyName como $true.
Aunque un único objeto de entrada no se puede enlazar a
varios parámetros, las distintas propiedades de ese objeto
de entrada se pueden enlazar a parámetros diferentes.

Al enlazar un parámetro con una propiedad de un objeto


de entrada, el entorno en tiempo de ejecución busca en
primer lugar una propiedad con el mismo nombre que el
parámetro. Si esta propiedad no existe, el entorno en
tiempo de ejecución busca alias para ese parámetro, en su
orden de declaración, y selecciona el primer alias de este
tipo para el que existe una propiedad.

función Process-Date
{
param(
[Parameter(ValueFromPipelineByPropertyName=$true)]
[int]$Year,

[Parameter(ValueFromPipelineByPropertyName=$true)]
[int]$Month,

[Parameter(ValueFromPipelineByPropertyName=$true)]
[int]$Day
)

proceso { … }
}

Get-Date | Process-Date
Parámetro Propósito

ValueFromRemainingArguments Tipo: bool. Valor predeterminado: $false


(con nombre)
Este argumento especifica si el parámetro acepta todos los
argumentos restantes que no están enlazados a los
parámetros de la función. Un valor $true indica que sí lo
hace. Un valor $false indica que no lo hace.

En el ejemplo siguiente se muestra un parámetro $others


que acepta todos los argumentos restantes del objeto de
entrada que se pasa a la función Test:

parámetro ( [parameter(Mandatory = $true)][int] $p 1,


[parameter(Mandatory = $true)][int] $p2,
[parameter(ValueFromRemainingArguments = $true)]
[string[]] $others )

La prueba 10 20 # $others tiene longitud 0


La prueba 10 20 30 40 # $others tiene longitud 2,
valor 30,40

Una implementación también puede definir otros atributos.

También se proporcionan los atributos siguientes:

HelpMessageBaseName: especifica la ubicación donde residen los identificadores


de recursos. Por ejemplo, este parámetro podría especificar un ensamblado de
recursos que contenga mensajes de Ayuda que se van a localizar.
HelpMessageResourceId: especifica el identificador de recursos para un mensaje
de Ayuda.

12.3.8 PSDefaultValue (atributo)


Este atributo se usa en un parámetro de script para proporcionar información adicional
sobre el parámetro. El atributo se usa de una manera definida por la implementación.
Los argumentos siguientes se usan para definir las características del parámetro:

Nombre Propósito
de
parámetro
Nombre Propósito
de
parámetro

Help (con Type: cadena


nombre)
Este argumento especifica un mensaje que está pensado para incluir una breve
descripción del valor predeterminado de un parámetro. Este mensaje se usa de una
manera definida por la implementación.

Windows PowerShell: el mensaje se usa como parte de la descripción del parámetro


para el tema de ayuda que muestra el cmdlet [Get-Help]
(xref:Microsoft.PowerShell.Core.Get-Help).

Value (con Tipo: object


nombre)
Este argumento especifica un valor que está pensado para ser el valor
predeterminado de un parámetro. El valor se usa de una manera definida por la
implementación.

Windows PowerShell: el valor se usa como parte de la descripción del parámetro


para el tema de ayuda que muestra el cmdlet [Get-Help]
(xref:Microsoft.PowerShell.Core.Get-Help) cuando no se especifica la propiedad
Help.

12.3.9 SupportsWildcards (atributo)


Este atributo se usa en un parámetro de script para proporcionar información adicional
sobre el parámetro. El atributo se usa de una manera definida por la implementación.

Este atributo se usa como parte de la descripción del parámetro para el tema de ayuda
que muestra el cmdlet Get-Help.

12.3.10 ValidateCount (atributo)


Este atributo se usa en un parámetro de script para especificar el número mínimo y
máximo de valores de argumento que el parámetro puede aceptar. Los argumentos
siguientes se usan para definir las características del parámetro:

Nombre de Propósito
parámetro

MinLength Tipo: int


(posición 0)
Este argumento especifica el número mínimo de valores de argumento
permitidos.
Nombre de Propósito
parámetro

MaxLength Tipo: int


(posición 1)
Este argumento especifica el número máximo de valores de argumento
permitidos.

Si este atributo no existe, la lista de valores de argumento correspondiente del


parámetro puede tener cualquier longitud.

Considere una llamada de función Test que tiene el siguiente bloque de parámetros y a
la que se llama tal como se muestra:

PowerShell

param (
[ValidateCount(2, 5)]
[int[]] $Values
)

Temp 10, 20, 30


Temp 10 # too few argument values
Temp 10, 20, 30, 40, 50, 60 # too many argument values

[ValidateCount(3, 4)]$Array = 1..3


$Array = 10 # too few argument values
$Array = 1..100 # too many argument values

12.3.11 ValidateLength (atributo)


Este atributo se usa en un parámetro de script o variable para especificar la longitud
mínima y máxima del argumento del parámetro, que debe tener una cadena de tipo.
Los argumentos siguientes se usan para definir las características del parámetro:

Nombre de parámetro Propósito

MinLength (posición 0) Tipo: int

Este argumento especifica el número mínimo de caracteres permitidos.

MaxLength (posición 1) Tipo: int

Este argumento especifica el número máximo de caracteres permitidos.

Si este atributo no existe, el argumento correspondiente del parámetro puede tener


cualquier longitud.
Considere una llamada de función Test que tiene el siguiente bloque de parámetros y a
la que se llama tal como se muestra:

PowerShell

param ( [parameter(Mandatory = $true)]


[ValidateLength(3,6)]
[string[]] $ComputerName )

Test "Thor","Mars" # length is ok


Test "Io","Mars" # "Io" is too short
Test "Thor","Jupiter" # "Jupiter" is too long

12.3.12 ValidateNotNull (atributo)


Este atributo se usa en un parámetro de script o variable para especificar que el
argumento del parámetro no puede ser $null o una colección que contenga un
elemento con valores NULL.

Considere una llamada de función Test que tiene el bloque de parámetros siguiente y a
la que se llama tal como se muestra:

PowerShell

param (
[ValidateNotNull()]
[string[]] $Names
)

Test "Jack", "Jill" # ok


Test "Jane", $null # $null array element value not allowed
Test $null # null array not allowed

[ValidateNotNull()]$Name = "Jack" # ok
$Name = $null # null value not allowed

12.3.13 ValidateNotNullOrEmpty (atributo)


Este atributo se usa en un parámetro de script o variable para especificar que el
argumento del parámetro no puede ser $null, una cadena vacía o una matriz vacía, o
una colección que contiene un elemento de cadena vacía o con valores $null.

Considere una llamada de función Test que tiene el bloque de parámetros siguiente y a
la que se llama tal como se muestra:
PowerShell

param (
[ValidateNotNullOrEmpty()]
[string[]] $Names
)

Test "Jack", "Jill" # ok


Test "Mary", "" # empty string not allowed
Test "Jane", $null # $null array element value not allowed
Test $null # null array not allowed
Test @() # empty array not allowed

[ValidateNotNullOrEmpty()]$Name = "Jack" # ok
$Name = "" # empty string not allowed
$Name = $null # null value not allowed

12.3.14 ValidatePattern (atributo)


Este atributo se usa en un parámetro de script o variable a fin de especificar una
expresión regular para que coincida con el patrón del argumento del parámetro. Los
argumentos siguientes se usan para definir las características del parámetro:

Nombre de parámetro Propósito

RegexString Escriba: String


(posición 0)
Expresión regular que se usa para validar el argumento del parámetro.

Options (con nombre) Tipo: Regular-Expression-Option

Vea la [sección 4.2.6.4][sección 4.2.6.4] para obtener los valores


permitidos.

Si el argumento es una colección, cada elemento de la colección debe coincidir con el


patrón.

Considere una llamada de función Test que tiene el bloque de parámetros siguiente y a
la que se llama tal como se muestra:

PowerShell

param (
[ValidatePattern('\^[A-Z][1-5][0-9]$')]
[string] $Code,

[ValidatePattern('\^(0x|0X)([A-F]|[a-f]|[0-9])([A-F]|[a-f]|[0-9])$')]
[string] $HexNum,
[ValidatePattern('\^[+|-]?[1-9]$')]
[int] $Minimum
)

Test -c A12 # matches pattern


Test -c A63 # does not match pattern

Test -h 0x4f # matches pattern


Test -h "0XB2" # matches pattern
Test -h 0xK3 # does not match pattern

Test -m -4 # matches pattern


Test -m "+7" # matches pattern
Test -m -12 # matches pattern, but is too long

[ValidatePattern('\^[a-z][a-z0-9]\*$')]$ident = "abc"
$ident = "123" # does not match pattern

12.3.15 ValidateRange (atributo)


Este atributo se usa en un parámetro de script o variable para especificar los valores
máximos y mínimos del argumento del parámetro. Los argumentos siguientes se usan
para definir las características del parámetro:

Nombre de parámetro Propósito

MinRange (posición 0) Tipo: object

Este argumento especifica el valor mínimo permitido.

MaxRange (posición 1) Tipo: object

Este argumento especifica el valor máximo permitido.

Si este atributo no existe, no hay ninguna restricción de intervalo.

Considere una llamada de función Test1 que tiene el bloque de parámetros siguiente y
a la que se llama tal como se muestra:

PowerShell

param (
[parameter(Mandatory = $true)]
[ValidateRange(1, 10)]
[int] $StartValue
)

Test1 2
Test1 -st 7
Test1 -3 # value is too small
Test1 12 # value is too large

Considere una llamada de función Test2 que tiene el bloque de parámetros y las
llamadas siguientes:

PowerShell

param (
[parameter(Mandatory = $true)]
[ValidateRange("b", "f")]
[string] $Name
)

Test2 "Bravo" # ok
Test2 "Alpha" # value compares less than the minimum
Test2 "Hotel" # value compares greater than the maximum

Considere una llamada de función Test3 que tiene el bloque de parámetros siguiente y
a la que se llama tal como se muestra:

PowerShell

param (
[parameter(Mandatory = $true)]
[ValidateRange(0.002, 0.003)]
[double] $Distance
)

Test3 0.002
Test3 0.0019 # value is too small
Test3 "0.005" # value is too large

[ValidateRange(13, 19)]$teenager = 15
$teenager = 20 # value is too large

12.3.16 ValidateScript (atributo)


Este atributo se usa en un parámetro de script o variable para especificar un script que
se va a usar para validar el argumento del parámetro.

El argumento de la posición 1 es una expresión de bloque de script.

Considere una llamada de función Test que tiene el bloque de parámetros siguiente y a
la que se llama tal como se muestra:

PowerShell
param (
[Parameter(Mandatory = $true)]
[ValidateScript( { ($_ -ge 1 -and $_ -le 3) -or ($_ -ge 20) })]
[int] $Count
)

Test 2 # ok, valid value


Test 25 # ok, valid value
Test 5 # invalid value
Test 0 # invalid value

[ValidateScript({$_.Length --gt 7})]$password = "password" # ok


$password = "abc123" # invalid value

12.3.17 ValidateSet (atributo)


Este atributo se usa en un parámetro de script o variable a fin de especificar un conjunto
de valores válidos para el argumento del parámetro. Los argumentos siguientes se usan
para definir las características del parámetro:

Nombre de Propósito
parámetro

ValidValues Tipo: string[]


(posición 0)
Conjunto de valores válidos.

IgnoreCase (con Tipo: bool, valor predeterminado: $true


nombre)
Especifica si se debe omitir el uso de mayúsculas y minúsculas para los
parámetros de tipo string.

Si el parámetro tiene un tipo de matriz, cada elemento de la matriz de argumentos


correspondiente debe coincidir con un elemento del conjunto de valores.

Considere una llamada de función Test que tiene el bloque de parámetros siguiente y a
la que se llama tal como se muestra:

PowerShell

param ( [ValidateSet("Red", "Green", "Blue")]


[string] $Color,

[ValidateSet("up", "down", "left", "right", IgnoreCase =


$false)]
[string] $Direction

)
Test -col "RED" # case is ignored, is a member of the set
Test -col "white" # case is ignored, is not a member of the set

Test -dir "up" # case is not ignored, is a member of the set


Test -dir "Up" # case is not ignored, is not a member of the set

[ValidateSet(("Red", "Green", "Blue")]$color = "RED" # ok, case is ignored


$color = "Purple" # case is ignored, is not a member of the set
13. Cmdlets
Artículo • 10/03/2022

Un cmdlet es un comando de una sola característica que manipula objetos en


PowerShell. Los cmdlets se pueden reconocer por su formato de nomenclatura, un
verbo y un nombre separados por un guión ( - ), como Get-Help , Get-Process y Start-
Service . Un patrón de verbo es un verbo expresado con caracteres comodín, como en

W* . Un patrón de nombre es un nombre expresado con caracteres comodín, como en

evento.

Los cmdlets deben ser simples y estar diseñados para usarse en combinación con otros
cmdlets. Por ejemplo, los cmdlets Get solo deben recuperar datos, los cmdlets Set solo
deben establecer o cambiar datos, los cmdlets Format solo deben dar formato a los
datos y los cmdlets Out solo deben dirigir la salida a un destino especificado.

Para cada cmdlet, proporcione un archivo de ayuda al que se pueda acceder escribiendo
lo siguiente:

get-help *cmdlet-name* -detailed

La vista detallada del archivo de ayuda del cmdlet debe incluir una descripción del
cmdlet, la sintaxis del comando, descripciones de los parámetros y un ejemplo que
ilustre el uso del cmdlet.

Los cmdlets se usan de forma similar a los comandos y utilidades del sistema operativo.
Los comandos de PowerShell no distinguen entre mayúsculas y minúsculas.

7 Nota

Nota del editor: El documento original contiene una lista de cmdlets con
descripciones, diagramas de sintaxis, definiciones de parámetros y ejemplos. Esta
información está incompleta y desactualizada. Para obtener información actual
sobre cmdlets, consulte la sección Referencia de la Documentación de PowerShell.

13.1 Parámetros comunes


Los parámetros comunes son un conjunto de parámetros de cmdlets que se pueden usar
con cualquier cmdlet. Se implementan mediante el propio entorno de ejecución de
PowerShell, no lo hace el desarrollador del cmdlet, y están disponibles automáticamente
para cualquier cmdlet o función que use el atributo Parameter (§12.3.7) o el atributo
CmdletBinding (§12.3.5).

Aunque cualquier cmdlet acepta los parámetros comunes, es posible que no tengan
semántica para ese cmdlet. Por ejemplo, si un cmdlet no genera ninguna salida
detallada, el uso del parámetro común Verbose no tiene ningún efecto.

Varios parámetros comunes invalidan los valores predeterminados o las preferencias del
sistema que se pueden establecer mediante variables de preferencia (§2.3.2.3). A
diferencia de las variables de preferencia, los parámetros comunes solo afectan a los
comandos en los que se usan.

7 Nota

Nota del editor: El documento original contiene una lista de parámetros comunes.
Esta información está incompleta y desactualizada. Para obtener más información,
consulte about_CommonParameters.
A. Ayuda basada en comentarios
Artículo • 16/03/2022

PowerShell proporciona un mecanismo para que los programadores documenten sus


scripts mediante directivas de comentarios especiales. Los comentarios que usan esta
sintaxis se denominan comentarios de ayuda. El cmdlet Get-Help genera documentación
a partir de estas directivas.

A.1 Introducción
Un comentario de ayuda contiene una directiva de ayuda con el formato .nombre
seguido en una o varias líneas posteriores por el texto del contenido de ayuda. El
comentario de ayuda puede constar de una serie comentarios de una sola línea o de un
comentario delimitado (sección 2.2.3). El conjunto de comentarios que comprende la
documentación de una sola entidad se denomina tema de ayuda.

Por ejemplo,

PowerShell

# <help-directive-1>
# <help-content-1>
...

# <help-directive-n>
# <help-content-n>

or

PowerShell

<#
<help-directive-1>
<help-content-1>
...

<help-directive-n>
<help-content-n>
#>

Todas las líneas de un tema de ayuda deben ser contiguas. Si un tema de ayuda sigue
un comentario que no forma parte de ese tema, debe haber al menos una línea en
blanco entre los dos.
Las directivas pueden aparecer en cualquier orden y algunas de estas pueden aparecer
varias veces.

En los nombres de directiva no se distingue mayúsculas de minúsculas.

Al documentar una función, los temas de ayuda pueden aparecer en una de estas tres
ubicaciones:

Inmediatamente antes de la definición de función, sin más de una línea en blanco


entre la última línea de la ayuda de la función y la línea que contiene la instrucción
de función.
Dentro del cuerpo de la función inmediatamente después del corchete de
apertura.
Dentro del cuerpo de la función inmediatamente anterior al corchete de cierre.

Al documentar un archivo de script, los temas de ayuda pueden aparecer en una de


estas dos ubicaciones:

Al principio del archivo de script, opcionalmente precedido de comentarios y


líneas en blanco solamente. Si el primer elemento del script después de la ayuda
es una definición de función, debe haber al menos dos líneas en blanco entre el
final de la ayuda del script y esa declaración de función. De lo contrario, la ayuda
se interpretará como que se aplica a la función en lugar del archivo de script.
Al final del archivo de script.

A.2 Directivas de ayuda

A.2.1 .DESCRIPTION
Sintaxis:

Syntax

.DESCRIPTION

Descripción:

Esta directiva permite una descripción detallada de la función o el script. (La directiva
.SYNOPSIS (sección A.2.11) está pensada para obtener una breve descripción). Esta

directiva solo se puede usar una vez en cada tema.

Ejemplos:
PowerShell

<#
.DESCRIPTION
Computes Base to the power Exponent. Supports non-negative integer
powers only.
#>

A.2.2 .EXAMPLE
Sintaxis:

Syntax

.EXAMPLE

Descripción:

Esta directiva permite mostrar un ejemplo de uso de comandos.

Si esta directiva se produce varias veces, cada bloque de contenido de ayuda asociado
se muestra como un ejemplo independiente.

Ejemplos:

PowerShell

<#
.EXAMPLE
Get-Power 3 4
81

.EXAMPLE
Get-Power -Base 3 -Exponent 4
81
#>

A.2.3 .EXTERNALHELP
Sintaxis:

Syntax

.EXTERNALHELP <XMLHelpFilePath>
Descripción:

Esta directiva especifica la ruta de acceso a un archivo de ayuda basado en XML para el
script o la función.

Aunque la ayuda basada en comentarios es más fácil de implementar, la ayuda basada


en XML es necesaria si se requiere un control más preciso sobre el contenido de ayuda
o si los temas de ayuda se van a traducir a varios idiomas. Esta especificación no define
los detalles de la ayuda basada en XML.

Ejemplos:

PowerShell

<#
.ExternalHelp C:\MyScripts\Update-Month-Help.xml
#>

A.2.4 .FORWARDHELPCATEGORY
Sintaxis:

Syntax

.FORWARDHELPCATEGORY <Category>

Descripción:

Especifica la categoría de ayuda del elemento en ForwardHelpTargetName


(sección A.2.5). Los valores válidos son Alias, All, Cmdlet, ExternalScript, FAQ, Filter,
Function, General, Glossary, HelpFile, Provider y ScriptCommand. Use esta directiva
para evitar conflictos cuando haya comandos con el mismo nombre.

Ejemplos:

Vea la sección A.2.5.

A.2.5 .FORWARDHELPTARGETNAME
Sintaxis:

Syntax

.FORWARDHELPTARGETNAME <Command-Name>
Descripción:

Redirige al tema de ayuda que especifica <Command-Name> .

Ejemplos:

PowerShell

function Help {
<#
.FORWARDHELPTARGETNAME Get-Help
.FORWARDHELPCATEGORY Cmdlet
#>
...
}

El comando Get-Help help se trata más bien como si fuera Get-Help Get-Help .

A.2.6 .INPUTS
Sintaxis:

Syntax

.INPUTS

Descripción:

La canalización se puede usar para canalizar uno o varios objetos a un script o función.
Esta directiva se usa para describir estos objetos y sus tipos.

Si esta directiva se produce varias veces, cada bloque de contenido de ayuda asociado
se recopila en la única entrada de documentación, en el orden léxico de las directivas.

Ejemplos:

PowerShell

<#
.INPUTS
None. You cannot pipe objects to Get-Power.

.INPUTS
For the Value parameter, one or more objects of any kind can be written
to the pipeline. However, the object is converted to a string before it
is added to the item.
#>
function Process-Thing {
param ( ...
[Parameter(ValueFromPipeline=$true)]
[object[]]$Value,
...
)
...
}

A.2.7 .LINK
Sintaxis:

Syntax

.LINK

Descripción:

Esta directiva especifica el nombre de un tema relacionado.

Si esta directiva se produce varias veces, cada bloque de contenido de ayuda asociado
se recopila en la única entrada de documentación, en el orden léxico de las directivas.

El contenido de la directiva Link también puede incluir un URI en una versión en línea
del mismo tema de ayuda. La versión en línea se abre cuando Get-Help se invoca con el
parámetro Online. El URI debe comenzar por "http" o "https".

Ejemplos:

PowerShell

<#
.LINK
Online version: http://www.acmecorp.com/widget.html

.LINK
Set-ProcedureName
#>

A.2.8 .NOTES
Sintaxis:

Syntax
.NOTES

Descripción:

Esta directiva permite proporcionar información adicional sobre la función o el script.


Esta directiva solo se puede usar una vez en cada tema.

Ejemplos:

PowerShell

<#
.Notes
*arbitrary text goes here*
#>

A.2.9 .OUTPUTS
Sintaxis:

Syntax

.OUTPUTS

Descripción:

Esta directiva se usa para describir los objetos que genera un comando.

Si esta directiva se produce varias veces, cada bloque de contenido de ayuda asociado
se recopila en la única entrada de documentación, en el orden léxico de las directivas.

Ejemplos:

PowerShell

<#
.OUTPUTS
double - Get-Power returns Base to the power Exponent.

.OUTPUTS
None unless the -PassThru switch parameter is used.
#>

A.2.10 .PARAMETER
Sintaxis:

Syntax

.PARAMETER <Parameter-Name>

Descripción:

Esta directiva permite una descripción detallada del parámetro especificado. Esta
directiva se puede usar una vez para cada parámetro. Las directivas de parámetros
pueden aparecer en cualquier orden en el bloque de comentarios, pero el orden en el
que sus parámetros correspondientes se definen realmente en el origen determina el
orden en que los parámetros y sus descripciones aparecen en la documentación
resultante.

Un formato alternativo implica colocar un comentario de descripción de parámetro


inmediatamente antes de la declaración del nombre de la variable de parámetro
correspondiente. Si el origen contiene un comentario de descripción de parámetro y
una directiva Parameter, se usa la descripción asociada a la directiva Parameter.

Ejemplos:

PowerShell

<#
.PARAMETER Base
The integer value to be raised to the Exponent-th power.

.PARAMETER Exponent
The integer exponent to which Base is to be raised.
#>

function Get-Power {
param ([long]$Base, [int]$Exponent)
...
}

function Get-Power {
param ([long]
# The integer value to be raised to the Exponent-th power.
$Base,
[int]
# The integer exponent to which Base is to be raised.
$Exponent
)
...
}
A.2.11 .SYNOPSIS
Sintaxis:

PowerShell

.SYNOPSIS

Descripción:

Esta directiva permite obtener una breve descripción de la función o el script. (La
directiva .DESCRIPTION (sección A.2.1) está pensada para obtener una descripción
detallada). Esta directiva solo se puede usar una vez en cada tema.

Ejemplos:

PowerShell

<#
.SYNOPSIS
Computes Base to the power Exponent.
#>
B. Gramática
Artículo • 10/03/2022

Este apéndice contiene resúmenes de las gramáticas léxicas y sintácticas que se


encuentran en el documento principal.

 Sugerencia

La notación ~opt~ en las definiciones de sintaxis indica que la entidad léxica es


opcional en la sintaxis.

B.1 Gramática léxica


Syntax

input:
input-elements~opt~ signature-block~opt~

input-elements:
input-element
input-elements input-element

input-element:
whitespace
comment
token

signature-block:
signature-begin signature signature-end

signature-begin:
new-line-character # SIG # Begin signature block new-line-character

signature:
base64 encoded signature blob in multiple single-line-comments

signature-end:
new-line-character # SIG # End signature block new-line-character

B1.1 Terminadores de línea


Syntax
new-line-character:
Carriage return character (U+000D)
Line feed character (U+000A)
Carriage return character (U+000D) followed by line feed character
(U+000A)

new-lines:
new-line-character
new-lines new-line-character

B.1.2 Comentarios
Syntax

comment:
single-line-comment
requires-comment
delimited-comment

single-line-comment:
# input-characters~opt~

input-characters:
input-character
input-characters input-character

input-character:
Any Unicode character except a new-line-character

requires-comment:
#requires whitespace command-arguments

dash:
- (U+002D)
EnDash character (U+2013)
EmDash character (U+2014)
Horizontal bar character (U+2015)

dashdash:
dash dash

delimited-comment:
<# delimited-comment-text~opt~ hashes >

delimited-comment-text:
delimited-comment-section
delimited-comment-text delimited-comment-section

delimited-comment-section:
>
hashes~opt~ not-greater-than-or-hash
hashes:
#
hashes #

not-greater-than-or-hash:
Any Unicode character except > or #

B.1.3 Espacio en blanco


Syntax

whitespace:
Any character with Unicode class Zs, Zl, or Zp
Horizontal tab character (U+0009)
Vertical tab character (U+000B)
Form feed character (U+000C)
` (The backtick character U+0060) followed by new-line-character

B.1.4 Tokens
Syntax

token:
keyword
variable
command
command-parameter
command-argument-token
integer-literal
real-literal
string-literal
type-literal
operator-or-punctuator

B.1.5 Palabras clave


Syntax

keyword: one of
begin break catch class
continue data define do
dynamicparam else elseif end
exit filter finally for
foreach from function if
in inlinescript parallel param
process return switch throw
trap try until using
var while workflow

B.1.6 Variables
Syntax

variable:
$$
$?
$^
$ variable-scope~opt~ variable-characters
@ variable-scope~opt~ variable-characters
braced-variable

braced-variable:
${ variable-scope~opt~ braced-variable-characters }

variable-scope:
global:
local:
private:
script:
using:
workflow:
variable-namespace

variable-namespace:
variable-characters :

variable-characters:
variable-character
variable-characters variable-character

variable-character:
A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nd
_ (The underscore character U+005F)
?

braced-variable-characters:
braced-variable-character
braced-variable-characters braced-variable-character

braced-variable-character:
Any Unicode character except
} (The closing curly brace character U+007D)
` (The backtick character U+0060)
escaped-character

escaped-character:
` (The backtick character U+0060) followed by any Unicode character
B.1.7 Comandos
Syntax

generic-token:
generic-token-parts

generic-token-parts:
generic-token-part
generic-token-parts generic-token-part

generic-token-part:
expandable-string-literal
verbatim-here-string-literal
variable
generic-token-char

generic-token-char:
Any Unicode character except
{ } ( ) ; , | & $
` (The backtick character U+0060)
double-quote-character
single-quote-character
whitespace
new-line-character
escaped-character

generic-token-with-subexpr-start:
generic-token-parts $(

B.1.8 Parámetros
Syntax

command-parameter:
dash first-parameter-char parameter-chars colon~opt~

first-parameter-char:
A Unicode character of classes Lu, Ll, Lt, Lm, or Lo
_ (The underscore character U+005F)
?

parameter-chars:
parameter-char
parameter-chars parameter-char

parameter-char:
Any Unicode character except
{ } ( ) ; , | & . [
colon
whitespace
new-line-character

colon:
: (The colon character U+003A)

verbatim-command-argument-chars:
verbatim-command-argument-part
verbatim-command-argument-chars verbatim-command-argument-part

verbatim-command-argument-part:
verbatim-command-string
& non-ampersand-character
Any Unicode character except
|
new-line-character

non-ampersand-character:
Any Unicode character except &

verbatim-command-string:
double-quote-character non-double-quote-chars
double-quote-character

non-double-quote-chars:
non-double-quote-char
non-double-quote-chars non-double-quote-char

non-double-quote-char:
Any Unicode character except
double-quote-character

B.1.9 Literales
Syntax

literal:
integer-literal
real-literal
string-literal

B1.9.1 Literales enteros

Syntax

integer-literal:
decimal-integer-literal
hexadecimal-integer-literal
decimal-integer-literal:
decimal-digits numeric-type-suffix~opt~ numeric-multiplier~opt~

decimal-digits:
decimal-digit
decimal-digit decimal-digits

decimal-digit: one of
0 1 2 3 4 5 6 7 8 9

numeric-type-suffix:
long-type-suffix
decimal-type-suffix

hexadecimal-integer-literal:
0x hexadecimal-digits long-type-suffix~opt~
numeric-multiplier~opt~

hexadecimal-digits:
hexadecimal-digit
hexadecimal-digit decimal-digits

hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9 a b c d e f

long-type-suffix:
l

numeric-multiplier: one of
kb mb gb tb pb

B1.9.2 Literales reales

Syntax

real-literal:
decimal-digits . decimal-digits exponent-part~opt~ decimal-type-
suffix~opt~ numeric-multiplier~opt~
. decimal-digits exponent-part~opt~ decimal-type-suffix~opt~ numeric-
multiplier~opt~
decimal-digits exponent-part decimal-type-suffix~opt~ numeric-
multiplier~opt~

exponent-part:
e sign~opt~ decimal-digits

sign: one of
+
dash

decimal-type-suffix:
d
l

B.1.9.3 Literales de cadena

Syntax

string-literal:
expandable-string-literal
expandable-here-string-literal
verbatim-string-literal
verbatim-here-string-literal

expandable-string-literal:
double-quote-character expandable-string-characters~opt~ dollars~opt~
double-quote-character

double-quote-character:
" (U+0022)
Left double quotation mark (U+201C)
Right double quotation mark (U+201D)
Double low-9 quotation mark (U+201E)

expandable-string-characters:
expandable-string-part
expandable-string-characters
expandable-string-part

expandable-string-part:
Any Unicode character except
$
double-quote-character
` (The backtick character U+0060)
braced-variable
$ Any Unicode character except
(
{
double-quote-character
` (The backtick character U+0060)*
$ escaped-character
escaped-character
double-quote-character double-quote-character

dollars:
$
dollars $

expandable-here-string-literal:
@ double-quote-character whitespace~opt~ new-line-character
expandable-here-string-characters~opt~ new-line-character double-
quote-character @
expandable-here-string-characters:
expandable-here-string-part
expandable-here-string-characters expandable-here-string-part

expandable-here-string-part:
Any Unicode character except
$
new-line-character
braced-variable
$ Any Unicode character except
(
new-line-character
$ new-line-character Any Unicode character except double-quote-char
$ new-line-character double-quote-char Any Unicode character except @
new-line-character Any Unicode character except double-quote-char
new-line-character double-quote-char Any Unicode character except @

expandable-string-with-subexpr-start:
double-quote-character expandable-string-chars~opt~ $(

expandable-string-with-subexpr-end:
double-quote-char

expandable-here-string-with-subexpr-start:
@ double-quote-character whitespace~opt~ new-line-character expandable-
here-string-chars~opt~ $(

expandable-here-string-with-subexpr-end:
new-line-character double-quote-character @

verbatim-string-literal:
single-quote-character verbatim-string-characters~opt~ single-quote-char

single-quote-character:
' (U+0027)
Left single quotation mark (U+2018)
Right single quotation mark (U+2019)
Single low-9 quotation mark (U+201A)
Single high-reversed-9 quotation mark (U+201B)

verbatim-string-characters:
verbatim-string-part
verbatim-string-characters verbatim-string-part

verbatim-string-part:
*Any Unicode character except* single-quote-character
single-quote-character single-quote-character

verbatim-here-string-literal:
@ single-quote-character whitespace~opt~ new-line-character
verbatim-here-string-characters~opt~ new-line-character
single-quote-character *@*

verbatim-*here-string-characters:
verbatim-here-string-part
verbatim-here-string-characters verbatim-here-string-part

verbatim-here-string-part:
Any Unicode character except* new-line-character
new-line-character Any Unicode character except single-quote-character
new-line-character single-quote-character Any Unicode character except
@

B.1.10 Nombres simples


Syntax

simple-name:
simple-name-first-char simple-name-chars

simple-name-first-char:
A Unicode character of classes Lu, Ll, Lt, Lm, or Lo
_ (The underscore character U+005F)

simple-name-chars:
simple-name-char
simple-name-chars simple-name-char

simple-name-char:
A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nd
_ (The underscore character U+005F)

B.1.11 Nombres de tipo


Syntax

type-name:
type-identifier
type-name . type-identifier

type-identifier:
type-characters

type-characters:
type-character
type-characters type-character

type-character:
A Unicode character of classes Lu, Ll, Lt, Lm, Lo, or Nd
_ (The underscore character U+005F)

array-type-name:
type-name [
generic-type-name:
type-name [

B1.12 Operadores y signos de puntuación


Syntax

operator-or-punctuator: one of
{ } [ ] ( ) @( @{ $( ;
&& || & | , ++ .. :: .
! * / % +
dash dashdash
dash and dash band dash bnot dash bor
dash bxor dash not dash or dash xor
assignment-operator
merging-redirection-operator
file-redirection-operator
comparison-operator
format-operator

assignment-operator: one of
= dash = += *= /= %=

file-redirection-operator: one of
> >> 2> 2>> 3> 3>> 4> 4>>
5> 5>> 6> 6>> *> *>> <

merging-redirection-operator: one of
*>&1 2>&1 3>&1 4>&1 5>&1 6>&1
*>&2 1>&2 3>&2 4>&2 5>&2 6>&2

comparison-operator: one of
dash as dash ccontains dash ceq
dash cge dash cgt dash cle
dash clike dash clt dash cmatch
dash cne dash cnotcontains dash cnotlike
dash cnotmatch dash contains dash creplace
dash csplit dash eq dash ge
dash gt dash icontains dash ieq
dash ige dash igt dash ile
dash ilike dash ilt dash imatch
dash in dash ine dash inotcontains
dash inotlike dash inotmatch dash ireplace
dash is dash isnot dash isplit
dash join dash le dash like
dash lt dash match dash ne
dash notcontains dash notin dash notlike
dash notmatch dash replace dash shl*
dash shr dash split

format-operator:
dash f
B.2 Gramática sintáctica

B.2.1 Conceptos básicos


Syntax

script-file:
script-block

module-file:
script-block

interactive-input:
script-block

data-file:
statement-list

B.2.2 Instrucciones
Syntax

script-block:
param-block~opt~ statement-terminators~opt~ script-block-body~opt~

param-block:
new-lines~opt~ attribute-list~opt~ new-lines~opt~ param new-lines~opt~
( parameter-list~opt~ new-lines~opt~ )

parameter-list:
script-parameter
parameter-list new-lines~opt~ , script-parameter

script-parameter:
new-lines~opt~ attribute-list~opt~ new-lines~opt~ variable script-
parameter-default~opt~

script-parameter-default:
new-lines~opt~ = new-lines~opt~ expression

script-block-body:
named-block-list
statement-list

named-block-list:
named-block
named-block-list named-block
named-block:
block-name statement-block statement-terminators~opt~

block-name: one of
dynamicparam begin process end

statement-block:
new-lines~opt~ { statement-list~opt~ new-lines~opt~ }

statement-list:
statement
statement-list statement

statement:
if-statement
label~opt~ labeled-statement
function-statement
flow-control-statement statement-terminator
trap-statement
try-statement
data-statement
inlinescript-statement
parallel-statement
sequence-statement
pipeline statement-terminator

statement-terminator:
;
new-line-character

statement-terminators:
statement-terminator
statement-terminators statement-terminator

if-statement:
if new-lines~opt~ ( new-lines~opt~ pipeline new-lines~opt~ ) statement-
block
elseif-clauses~opt~ else-clause~opt~

elseif-clauses:
elseif-clause
elseif-clauses elseif-clause

elseif-clause:
new-lines~opt~ elseif new-lines~opt~ ( new-lines~opt~ pipeline new-
lines~opt~ ) statement-block

else-clause:
new-lines~opt~ else statement-block

labeled-statement:
switch-statement
foreach-statement
for-statement
while-statement
do-statement

switch-statement:
switch new-lines~opt~ switch-parameters~opt~ switch-condition switch-
body

switch-parameters:
switch-parameter
switch-parameters switch-parameter

switch-parameter:
-regex
-wildcard
-exact
-casesensitive
-parallel

switch-condition:
( new-lines~opt~ pipeline new-lines~opt~ )
-file new-lines~opt~ switch-filename

switch-filename:
command-argument
primary-expression

switch-body:
new-lines~opt~ { new-lines~opt~ switch-clauses }

switch-clauses:
switch-clause
switch-clauses switch-clause

switch-clause:
switch-clause-condition statement-block statement-terimators~opt~

switch-clause-condition:
command-argument
primary-expression

foreach-statement:
foreach new-lines~opt~ foreach-parameter~opt~ new-lines~opt~
( new-lines~opt~ variable new-lines~opt~ in new-lines~opt~ pipeline
new-lines~opt~ ) statement-block

foreach-parameter:
-parallel

for-statement:
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~ statement-terminator
new-lines~opt~ for-condition~opt~ statement-terminator
new-lines~opt~ for-iterator~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~ statement-terminator
new-lines~opt~ for-condition~opt~
new-lines~opt~ ) statement-block
for new-lines~opt~ (
new-lines~opt~ for-initializer~opt~
new-lines~opt~ ) statement-block

for-initializer:
pipeline

for-condition:
pipeline

for-iterator:
pipeline

while-statement:
while new-lines~opt~ ( new-lines~opt~ while-condition new-lines~opt~ )
statement-block

do-statement:
do statement-block new-lines~opt~ while new-lines~opt~ ( while-condition
new-lines~opt~ )
do statement-block new-lines~opt~ until new-lines~opt~ ( while-condition
new-lines~opt~ )

while-condition:
new-lines~opt~ pipeline

function-statement:
function new-lines~opt~ function-name function-parameter-
declaration~opt~ { script-block }
filter new-lines~opt~ function-name function-parameter-declaration~opt~
{ script-block }
workflow new-lines~opt~ function-name function-parameter-
declaration~opt~ { script-block }

function-name:
command-argument

function-parameter-declaration:
new-lines~opt~ ( parameter-list new-lines~opt~ )

flow-control-statement:
break label-expression~opt~
continue label-expression~opt~
throw pipeline~opt~
return pipeline~opt~
exit pipeline~opt~

label-expression:
simple-name
unary-expression

trap-statement:
trap new-lines~opt~ type-literal~opt~ new-lines~opt~ statement-block

try-statement:
try statement-block catch-clauses
try statement-block finally-clause
try statement-block catch-clauses finally-clause

catch-clauses:
catch-clause
catch-clauses catch-clause

catch-clause:
new-lines~opt~ catch catch-type-list~opt~ statement-block

catch-type-list:
new-lines~opt~ type-literal
catch-type-list new-lines~opt~ , new-lines~opt~ type-literal

finally-clause:
new-lines~opt~ finally statement-block

data-statement:
data new-lines~opt~ data-name data-commands-allowed~opt~
statement-block

data-name:
simple-name

data-commands-allowed:
new-lines~opt~ -supportedcommand data-commands-list

data-commands-list:
new-lines~opt~ data-command
data-commands-list , new-lines~opt~ data-command

data-command:
command-name-expr

inlinescript-statement:
inlinescript statement-block

parallel-statement:
parallel statement-block

sequence-statement:
sequence statement-block

pipeline:
assignment-expression
expression redirections~opt~ pipeline-tail~opt~
command verbatim-command-argument~opt~ pipeline-tail~opt~

assignment-expression:
expression assignment-operator statement
pipeline-tail:
| new-lines~opt~ command
| new-lines~opt~ command pipeline-tail

command:
command-name command-elements~opt~
command-invocation-operator command-module~opt~ command-name-expr
command-elements~opt~

command-invocation-operator: one of
& .

command-module:
primary-expression

command-name:
generic-token
generic-token-with-subexpr

generic-token-with-subexpr:
No whitespace is allowed between ) and command-name.
generic-token-with-subexpr-start statement-list~opt~ ) command-name

command-name-expr:
command-name
primary-expression

command-elements:
command-element
command-elements command-element

command-element:
command-parameter
command-argument
redirection

command-argument:
command-name-expr

verbatim-command-argument:
--% verbatim-command-argument-chars

redirections:
redirection
redirections redirection

redirection:
merging-redirection-operator
file-redirection-operator redirected-file-name

redirected-file-name:
command-argument
primary-expression
B.2.3 Expresiones
Syntax

expression:
logical-expression

logical-expression:
bitwise-expression
logical-expression -and new-lines~opt~ bitwise-expression
logical-expression -or new-lines~opt~ bitwise-expression
logical-expression -xor new-lines~opt~ bitwise-expression

bitwise-expression:
comparison-expression
bitwise-expression -band new-lines~opt~ comparison-expression
bitwise-expression -bor new-lines~opt~ comparison-expression
bitwise-expression -bxor new-lines~opt~ comparison-expression

comparison-expression:
additive-expression
comparison-expression comparison-operator new-lines~opt~
additive-expression

additive-expression:
multiplicative-expression
additive-expression + new-lines~opt~ multiplicative-expression
additive-expression dash new-lines~opt~ multiplicative-expression

multiplicative-expression:
format-expression
multiplicative-expression \ new-lines~opt~ format-expression
multiplicative-expression / new-lines~opt~ format-expression
multiplicative-expression % new-lines~opt~ format-expression

format-expression:
range-expression
format-expression format-operator new-lines~opt~ range-expression

range-expression:
array-literal-expression
range-expression .. new-lines~opt~ array-literal-expression

array-literal-expression:
unary-expression
unary-expression , new-lines~opt~ array-literal-expression

unary-expression:
primary-expression
expression-with-unary-operator

expression-with-unary-operator:
, new-lines~opt~ unary-expression
-not new-lines~opt~ unary-expression
! new-lines~opt~ unary-expression
-bnot new-lines~opt~ unary-expression
+ new-lines~opt~ unary-expression
dash new-lines~opt~ unary-expression
pre-increment-expression
pre-decrement-expression
cast-expression
-split new-lines~opt~ unary-expression
-join new-lines~opt~ unary-expression

pre-increment-expression:
++ new-lines~opt~ unary-expression

pre-decrement-expression:
dashdash new-lines~opt~ unary-expression

cast-expression:
type-literal unary-expression

attributed-expression:
type-literal variable

primary-expression:
value
member-access
element-access
invocation-expression
post-increment-expression
post-decrement-expression

value:
parenthesized-expression
sub-expression
array-expression
script-block-expression
hash-literal-expression
literal
type-literal
variable

parenthesized-expression:
( new-lines~opt~ pipeline new-lines~opt~ )

sub-expression:
$( new-lines~opt~ statement-list~opt~ new-lines~opt~ )

array-expression:
@( new-lines~opt~ statement-list~opt~ new-lines~opt~ )

script-block-expression:
{ new-lines~opt~ script-block new-lines~opt~ }

hash-literal-expression:
@{ new-lines~opt~ hash-literal-body~opt~ new-lines~opt~ }
hash-literal-body:
hash-entry
hash-literal-body statement-terminators hash-entry

hash-entry:
key-expression = new-lines~opt~ statement

key-expression:
simple-name
unary-expression

post-increment-expression:
primary-expression ++

post-decrement-expression:
primary-expression dashdash

member-access: Note no whitespace is allowed after


primary-expression.
primary-expression . member-name
primary-expression :: member-name

element-access: Note no whitespace is allowed between primary-expression and


[.
primary-expression [ new-lines~opt~ expression new-lines~opt~ ]

invocation-expression: Note no whitespace is allowed after


primary-expression.
primary-expression . member-name argument-list
primary-expression :: member-name argument-list

argument-list:
( argument-expression-list~opt~ new-lines~opt~ )

argument-expression-list:
argument-expression
argument-expression new-lines~opt~ , argument-expression-list

argument-expression:
new-lines~opt~ logical-argument-expression

logical-argument-expression:
bitwise-argument-expression
logical-argument-expression -and new-lines~opt~ bitwise-argument-
expression
logical-argument-expression -or new-lines~opt~ bitwise-argument-
expression
logical-argument-expression -xor new-lines~opt~ bitwise-argument-
expression

bitwise-argument-expression:
comparison-argument-expression
bitwise-argument-expression -band new-lines~opt~ comparison-argument-
expression
bitwise-argument-expression -bor new-lines~opt~ comparison-argument-
expression
bitwise-argument-expression -bxor new-lines~opt~ comparison-argument-
expression

comparison-argument-expression:
additive-argument-expression
comparison-argument-expression comparison-operator
new-lines~opt~ additive-argument-expression

additive-argument-expression:
multiplicative-argument-expression
additive-argument-expression + new-lines~opt~ multiplicative-
argument-expression
additive-argument-expression dash new-lines~opt~ multiplicative-
argument-expression

multiplicative-argument-expression:
format-argument-expression
multiplicative-argument-expression \ new-lines~opt~ format-argument-
expression
multiplicative-argument-expression / new-lines~opt~ format-argument-
expression
multiplicative-argument-expression % new-lines~opt~ format-argument-
expression

format-argument-expression:
range-argument-expression
format-argument-expression format-operator new-lines~opt~ range-
argument-expression

range-argument-expression:
unary-expression
range-expression .. new-lines~opt~ unary-expression

member-name:
simple-name
string-literal
string-literal-with-subexpression
expression-with-unary-operator
value

string-literal-with-subexpression:
expandable-string-literal-with-subexpr
expandable-here-string-literal-with-subexpr

expandable-string-literal-with-subexpr:
expandable-string-with-subexpr-start statement-list~opt~ )
expandable-string-with-subexpr-characters expandable-string-with-
subexpr-end
expandable-here-string-with-subexpr-start statement-list~opt~ )
expandable-here-string-with-subexpr-characters
expandable-here-string-with-subexpr-end

expandable-string-with-subexpr-characters:
expandable-string-with-subexpr-part
expandable-string-with-subexpr-characters expandable-string-with-
subexpr-part

expandable-string-with-subexpr-part:
sub-expression
expandable-string-part

expandable-here-string-with-subexpr-characters:
expandable-here-string-with-subexpr-part
expandable-here-string-with-subexpr-characters expandable-here-string-
with-subexpr-part

expandable-here-string-with-subexpr-part:
sub-expression
expandable-here-string-part

type-literal:
[ type-spec ]

type-spec:
array-type-name new-lines~opt~ dimension~opt~ ]
generic-type-name new-lines~opt~ generic-type-arguments ]
type-name

dimension:
,
dimension ,

generic-type-arguments:
type-spec new-lines~opt~
generic-type-arguments , new-lines~opt~ type-spec

B.2.4 Atributos
Syntax

attribute-list:
attribute
attribute-list new-lines~opt~ attribute

attribute:
[ new-lines~opt~ attribute-name ( attribute-arguments new-lines~opt~ )
new-lines~opt~ ]
type-literal

attribute-name:
type-spec

attribute-arguments:
attribute-argument
attribute-argument new-lines~opt~ , attribute-arguments
attribute-argument:
new-lines~opt~ expression
new-lines~opt~ simple-name
new-lines~opt~ simple-name = new-lines~opt~ expression
C. Referencias
Artículo • 10/03/2022

ANSI/IEEE 754-2008, Aritmética de punto flotante binario para sistemas de


microprocesadores.

ECMA-334, Especificación del lenguaje C# , 4.ª edición (junio de 2006), http://www.ecma-


international.org/publications/standards/Ecma-334.htm . [Esta publicación de la Ecma
también se aprobó como ISO/IEC 23270:2006.]

Especificaciones básicas de The Open Group: Coincidencia de patrones, IEEE Std 1003.1,
edición de 2004.
http://www.opengroup.org/onlinepubs/000095399/utilities/xcu_chap02.html#tag_02_13
_01

Especificaciones básicas de The Open Group: Expresiones regulares, IEEE Std 1003.1,
edición de 2004.
http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap09.html .

Informe técnico TR/84 de la Ecma, Common Language Infrastructure (CLI): información


derivada del archivo XML de la partición IV, 4.ª edición (junio de 2006),
http://www.ecma-international.org/publications/techreports/E-TR-084.htm . Este
informe técnico también se publicó como ISO/IEC TR 23272:2006.

ISO 639-1, Códigos para la representación de nombres de idiomas - Parte 1: Código


Alpha-2.

ISO 3166-1, Códigos para la representación de nombres de países y sus subdivisiones -


Parte 1: Códigos de países.

ISO/IEC 10646-1/AMD1:1996, enmienda 1 de ISO/IEC 10646-1:1993, Formato de


transformación para 16 planos del grupo 00 (UTF-16) .

Estándar Unicode, edición 5.2. The Unicode Consortium,


http://www.unicode.org/standard/standard.html .
Windows PowerShell
Artículo • 27/09/2021

Actualizado: 8 de julio de 2013

®Windows PowerShell es un shell de línea de comandos basado en tareas y un lenguaje


de scripting diseñado especialmente para la administración del sistema. Basado en el
.NET Framework, Windows PowerShell ayuda a los profesionales de IT y a los usuarios
avanzados a controlar y automatizar la administración del sistema operativo Windows y
las aplicaciones que se ejecutan en ® Windows.

Los documentos publicados aquí están escritos principalmente para desarrolladores de


aplicaciones de cmdlets, proveedores y host que requieren información de referencia
sobre las API proporcionadas por Windows PowerShell. Sin embargo, los
administradores del sistema también pueden encontrar útil la información
proporcionada por estos documentos.

Para obtener la información básica necesaria para empezar a usar Windows PowerShell,
vea Tareas iniciales con Windows PowerShell .

Windows PowerShell Documentos


Instalación del SDK Windows PowerShell Proporciona información sobre cómo
instalar el SDK Windows PowerShell.

Escribir un Windows PowerShell módulo Proporciona información para


administradores, desarrolladores de scripts y desarrolladores de cmdlets que
necesitan empaquetar y distribuir sus Windows PowerShell soluciones.

Escribir un cmdlet Windows PowerShell Proporciona información para diseñar e


implementar cmdlets.

Escribir un proveedor Windows PowerShell trabajo Proporciona información para


diseñar e implementar Windows PowerShell proveedores. Le ayudará a
comprender cómo funcionan Windows PowerShell proveedores de servicios y
proporciona código de ejemplo que puede usar para empezar a diseñar o escribir
sus propios proveedores.

Escribir una aplicación Windows PowerShell host Proporciona información que


pueden usar los administradores de programas que diseñan aplicaciones host y los
desarrolladores que las implementan. La aplicación host puede definir el espacio
de ejecución donde se ejecutan los comandos, abrir sesiones en un equipo local o
remoto e invocar los comandos de forma sincrónica o asincrónica en función de
las necesidades de la aplicación.

Escribir un archivo de formato de PowerShell Proporciona información para la


creación de archivos de formato, que controlan el formato de presentación de los
objetos devueltos por comandos (cmdlets, funciones y scripts).

Windows PowerShell referencia Proporciona contenido de referencia para las API


que se usan para escribir cmdlets, proveedores y aplicaciones host, así como otras
API compatibles.
Instalar el SDK de Windows PowerShell
Artículo • 25/09/2021

Se aplica a: Windows PowerShell 2.0, Windows PowerShell 3.0

En el siguiente tema se describe cómo instalar PowerShell SDK en distintas versiones de


Windows.

Instalar el SDK de Windows PowerShell 3.0 para


Windows 8 y Windows Server 2012
Windows PowerShell 3.0 se instala automáticamente con Windows 8 y Windows Server
2012. Además, puede descargar e instalar los ensamblados de referencia para Windows
PowerShell 3.0 como parte de Windows 8 SDK. Estos ensamblados le permiten escribir
cmdlets, proveedores y programas host para Windows PowerShell 3.0. Al instalar
Windows SDK para Windows 8, los ensamblados de Windows PowerShell se instalan
automáticamente en la carpeta de ensamblados de referencia, en \Program Files
(x86)\Reference Assemblies\Microsoft\WindowsPowerShell\3.0 . Para obtener más

información, consulte el sitio de descarga del SDK de Windows 8. Windows PowerShell


ejemplos de código también están disponibles en el repositorio powershell-sdk-
samples.

Instalar el SDK de Windows PowerShell 3.0 para


Windows 7 y Windows Server 2008 R2
Windows 7 y Windows Server 2008 R2 tienen instalado automáticamente PowerShell
2.0. Además, puede instalar PowerShell 3.0 en estos sistemas. También puede instalar el
SDK de Windows 8 en Windows 7 y Windows Server 2008 R2 como se describió
anteriormente.

Instalar el SDK de Windows PowerShell 2.0 para


Windows 7, Vista, XP, Server 2003 y Server
2008
El SDK de Windows PowerShell 2.0 proporciona los ensamblados de referencia
necesarios para escribir cmdlets, proveedores y aplicaciones host, así como código de
ejemplo en C# que se puede usar como punto de partida para comenzar a escribir
código.

Ensamblados de referencia
Los ensamblados de referencia se instalan de forma predeterminada en la siguiente
ubicación: c:\Program Files\Reference Assemblies\Microsoft\WindowsPowerShell\V1.0 .

7 Nota

El código compilado con los ensamblados de Windows PowerShell 2.0 no puede


cargarse en instalaciones de Windows PowerShell 1.0. Sin embargo, el código
compilado con los ensamblados de Windows PowerShell 1.0 sí puede cargarse en
las instalaciones de Windows PowerShell 2.0.

Ejemplos
Los ejemplos de código se instalan de forma predeterminada en la siguiente ubicación:
C:\Program Files\Microsoft SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\ . En
las secciones siguientes, se proporciona una breve descripción de lo que hace cada
ejemplo.

Ejemplos de cmdlet

GetProcessSample01: muestra cómo escribir un cmdlet simple que obtiene todos


los procesos en el equipo local.
GetProcessSample02: muestra cómo agregar parámetros al cmdlet . El cmdlet
toma uno o más nombres de proceso y devuelve los procesos coincidentes.
GetProcessSample03: muestra cómo agregar parámetros que aceptan entradas de
la canalización.
GetProcessSample04: muestra cómo controlar los errores de no terminación.
GetProcessSample05: muestra cómo mostrar una lista de procesos especificados.
SelectObject: muestra cómo escribir un filtro para seleccionar solo determinados
objetos.
SelectString: muestra cómo buscar en archivos los patrones especificados.
StopProcessSample01: muestra cómo implementar un parámetro PassThru y cómo
solicitar comentarios del usuario mediante llamadas a los métodos ShouldProcess
y ShouldContinue. Los usuarios especifican el parámetro PassThru cuando quieren
forzar al cmdlet a devolver un objeto.
StopProcessSample02: muestra cómo detener un proceso específico.
StopProcessSample03: muestra cómo declarar alias para parámetros y cómo
admitir caracteres comodín.
StopProcessSample04: muestra cómo declarar conjuntos de parámetros, el objeto
que el cmdlet toma como entrada y cómo especificar el conjunto de parámetros
predeterminado que se va a usar.

Ejemplos de comunicación remota


RemoteRunspace01: muestra cómo crear un espacio de ejecución remoto que se
usa para establecer una conexión remota.
RemoteRunspacePool01: muestra cómo construir un grupo de espacio de
ejecución remoto y cómo ejecutar varios comandos simultáneamente mediante
este grupo.
Serialización01: muestra cómo mirar una clase .NET existente y asegurarse de que
la información de las propiedades públicas seleccionadas de esta clase se conserva
en la serialización o deserialización.
Serialización02: muestra cómo mirar una clase .NET existente y asegurarse de que
la información de la instancia de esta clase se conserva en la serialización o
deserialización cuando la información no está disponible en las propiedades
públicas de la clase.
Serialización03: muestra cómo mirar una clase .NET existente y asegurarse de que
las instancias de esta clase y de las clases derivadas se deserializan (rehidraten) en
objetos .NET activos.

Ejemplos de eventos

Event01: muestra cómo crear un cmdlet para el registro de eventos derivando de


ObjectEventRegistrationBase.
Event02: muestra cómo recibir notificaciones de eventos Windows PowerShell
generados en equipos remotos. Usa el evento PSEventReceived que se expone a
través de la clase Runspace.

Ejemplos de aplicación host


Runspace01: muestra cómo usar la clase de PowerShell para ejecutar el Get-
Process cmdlet de forma sincrónica. El Get-Process cmdlet devuelve objetos
Process para cada proceso que se ejecuta en el equipo local.
Runspace02: muestra cómo usar la clase de PowerShell para ejecutar los Get-
Process Sort-Object cmdlets y de forma sincrónica. El cmdlet devuelve objetos
Process para cada proceso que se ejecuta en el equipo local y ordena los objetos
Get-Process en función de su propiedad Sort-Object Id. Los resultados de estos

comandos se muestran mediante un control DataGridView.


Runspace03: muestra cómo usar la clase de PowerShell para ejecutar un script de
forma sincrónica y cómo controlar los errores de no terminación. El script recibe
una lista de nombres de procesos y después los recupera. Los resultados del script,
incluidos los errores de no terminación generados al ejecutarlo, se muestran en
una ventana de consola.
Runspace04: muestra cómo usar la clase de PowerShell para ejecutar comandos y
cómo detectar los errores de terminación que se producen al ejecutar los
comandos. Se ejecutan dos comandos; al último, se le pasa un argumento de
parámetro que no es válido. Como resultado, no se devuelve ningún objeto y se
produce un error de terminación.
Runspace05: muestra cómo agregar un complemento a un objeto
InitialSessionState para que el cmdlet del complemento esté disponible cuando se
abra el espacio de ejecución. El complemento proporciona un cmdlet Get-Proc
(definido por el ejemplo GetProcessSample01) que se ejecuta sincrónicamente
mediante un objeto de PowerShell.
Runspace06: muestra cómo agregar un módulo a un objeto InitialSessionState
para que el módulo se cargue cuando se abra el espacio de ejecución. El módulo
proporciona un cmdlet Get-Proc (definido por el ejemplo GetProcessSample02)
que se ejecuta sincrónicamente mediante un objeto de PowerShell.
Runspace07: muestra cómo crear un espacio de ejecución y, a continuación, usar
ese espacio de ejecución para ejecutar dos cmdlets de forma sincrónica mediante
un objeto de PowerShell.
Runspace08: muestra cómo agregar comandos y argumentos a la canalización de
un objeto de PowerShell y cómo ejecutar los comandos sincrónicamente.
Runspace09: muestra cómo agregar un script a la canalización de un objeto de
PowerShell y cómo ejecutar el script de forma asincrónica. Los eventos se usan
para controlar la salida del script.
Runspace10: muestra cómo crear un estado de sesión inicial predeterminado,
cómo agregar un cmdlet a InitialSessionState, cómo crear un espacio de ejecución
que usa el estado de sesión inicial y cómo ejecutar el comando mediante un
objeto de PowerShell.
Runspace11: muestra cómo usar la clase ProxyCommand para crear un comando
proxy que llama a un cmdlet existente, pero restringe el conjunto de parámetros
disponibles. El comando de proxy se agrega entonces a un estado de sesión inicial
que se usa para crear un espacio de ejecución restringido. Esto significa que el
usuario puede tener acceso a la funcionalidad del cmdlet solo mediante el
comando de proxy.
PowerShell01: muestra cómo crear un espacio de ejecución restringido mediante
un objeto InitialSessionState.
PowerShell02: muestra cómo usar un grupo de espacios de ejecución para ejecutar
varios comandos simultáneamente.

Ejemplos de host

Host01: muestra cómo implementar una aplicación host que usa un host
personalizado. En este ejemplo se crea un espacio de ejecución que usa el host
personalizado y, a continuación, se usa la API de PowerShell para ejecutar un script
que llama a exit . La aplicación host examina después la salida del script e
imprime los resultados.
Host02: muestra cómo escribir una aplicación host que usa el entorno de ejecución
Windows PowerShell junto con una implementación de host personalizada. La
aplicación host establece la referencia cultural del host en alemán, ejecuta el
cmdlet y muestra los resultados como los vería mediante pwrsh.exe y, a
continuación, imprime los datos y la hora actuales en Get-Process alemán.
Host03: muestra cómo compilar una aplicación host interactiva basada en consola
que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola.
Host04: muestra cómo compilar una aplicación host interactiva basada en consola
que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola. Esta aplicación host también
permite mostrar avisos para que el usuario pueda especificar varias opciones.
Host05: muestra cómo compilar una aplicación host interactiva basada en consola
que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola. Esta aplicación host también
admite llamadas a equipos remotos mediante Enter-PsSession Exit-PsSession los
cmdlets y .
Host06: muestra cómo compilar una aplicación host interactiva basada en consola
que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola. Además, este ejemplo utiliza
las API de Tokenizer para especificar el color del texto que el usuario ha escrito.

Ejemplos de proveedor

AccessDBProviderSample01: muestra cómo declarar una clase de proveedor que


deriva directamente de la clase CmdletProvider. Se incluye aquí solo por
cuestiones de integridad.
AccessDBProviderSample02: muestra cómo sobrescribir los métodos NewDrive y
RemoveDrive para admitir llamadas a New-PSDrive Remove-PSDrive los cmdlets y .
La clase de proveedor de este ejemplo se deriva de la clase DriveCmdletProvider.

AccessDBProviderSample03: muestra cómo sobrescribir los métodos GetItem y


SetItem para admitir llamadas a Get-Item Set-Item los cmdlets y . La clase de
proveedor de este ejemplo se deriva de la clase ItemCmdletProvider.

AccessDBProviderSample04: muestra cómo sobrescribir métodos de contenedor


para admitir llamadas a los Copy-Item Get-ChildItem New-Item cmdlets , , Remove-
Item y . Estos métodos deberían implementarse cuando el almacén de datos
contengan elementos que son contenedores. Un contenedor es un grupo de
elementos secundarios con un elemento primario común. La clase de proveedor
de este ejemplo se deriva de la clase ItemCmdletProvider.

AccessDBProviderSample05: muestra cómo sobrescribir métodos de contenedor


para admitir llamadas a Move-Item Join-Path los cmdlets y . Estos métodos
deberían implementarse cuando el usuario necesite mover elementos dentro de
un contenedor y si el almacén de datos tiene contenedores anidados. La clase de
proveedor de este ejemplo se deriva de la clase NavigationCmdletProvider.

AccessDBProviderSample06: muestra cómo sobrescribir métodos de contenido


para admitir llamadas a los Clear-Content Get-Content cmdlets , Set-Content y .
Estos métodos deberían implementarse cuando el usuario necesite administrar el
contenido de los elementos en el almacén de datos. La clase de proveedor de este
ejemplo se deriva de la clase NavigationCmdletProvider; también se implementa la
interfaz IContentCmdletProvider.
Referencia de Windows PowerShell
Artículo • 24/09/2021

Windows PowerShell es un entorno conectado .NET Framework Microsoft diseñado para


la automatización administrativa. Windows PowerShell proporciona un nuevo enfoque
para crear comandos, crear soluciones y crear herramientas gráficas de administración
basadas en la interfaz de usuario.

Windows PowerShell permite a un administrador del sistema automatizar la


administración de recursos del sistema mediante la ejecución de comandos
directamente o a través de scripts.

Audiencia de los desarrolladores


El kit Windows PowerShell Software Development Kit (SDK) está escrito para
desarrolladores de comandos que requieren información de referencia sobre las API
proporcionadas por Windows PowerShell. Los desarrolladores de Windows PowerShell
para crear comandos y proveedores que amplían las tareas que puede realizar Windows
PowerShell.

Windows PowerShell Recursos


Además del SDK de Windows PowerShell, los siguientes recursos proporcionan más
información.

Tareas iniciales con Windows PowerShell Proporciona una introducción a Windows


PowerShell: el lenguaje, los cmdlets, los proveedores y el uso de objetos .

Escribir un Windows PowerShell módulo Proporciona información y ejemplos para


administradores, desarrolladores de scripts y desarrolladores de cmdlets que necesitan
empaquetar y distribuir sus soluciones de Windows PowerShell mediante Windows
PowerShell módulos.

Escritura de un Windows PowerShell cmdlet Proporciona información y ejemplos de


código para los administradores de programas que diseñan cmdlets y para los
desarrolladores que implementan código de cmdlet.

Windows PowerShell Team Blog El mejor recurso para aprender y colaborar con otros
Windows PowerShell usuarios. Lea el blog del Equipo de Windows PowerShell y únase al
Foro de usuarios de Windows PowerShell (microsoft.public.windows.powershell). Use
Windows Live Search para buscar en otros blogs y recursos de Windows PowerShell. A
continuación, a medida que desarrolle sus conocimientos, contribuya libremente con
sus ideas.

Explorador de módulos de PowerShell Proporciona las versiones más recientes de los


temas de Ayuda de la línea de comandos.

Bibliotecas de clases
System.Management.Automation Este espacio de nombres es el espacio de nombres
raíz Windows PowerShell. Contiene las clases, enumeraciones e interfaces necesarias
para implementar cmdlets personalizados. En concreto, la clase
System.Management.Automation.Cmdlet es la clase base de la que se deben derivar
todas las clases de cmdlet. Para obtener más información sobre los cmdlets, vea.

System.Management.Automation.Provider Este espacio de nombres contiene las clases,


enumeraciones e interfaces necesarias para implementar un proveedor Windows
PowerShell cliente. En concreto, la clase
System.Management.Automation.Provider.Cmdletprovider es la clase base de la que se
deben derivar todas las Windows PowerShell de proveedor.

Microsoft.PowerShell.Commands Este espacio de nombres contiene las clases de los


cmdlets y proveedores implementados por Windows PowerShell. Del mismo modo, se
recomienda crear un valor de YourName. Espacio de nombres de comandos para los
cmdlets que implemente.

System.Management.Automation.Host Este espacio de nombres contiene las clases,


enumeraciones e interfaces que usa el cmdlet para definir la interacción entre el usuario
y Windows PowerShell.

System.Management.Automation.Internal Este espacio de nombres contiene las clases


base usadas por otras clases de espacio de nombres. Por ejemplo, la clase
System.Management.Automation.Internal.Cmdletmetadataattribute es la clase base para
la clase System.Management.Automation.CmdletAttribute.

System.Management.Automation.Runspaces Este espacio de nombres contiene las


clases, enumeraciones e interfaces que se usan para crear un espacio Windows
PowerShell ejecución. En este contexto, el espacio Windows PowerShell ejecución es el
contexto en el que una o varias Windows PowerShell canalizaciones invocan cmdlets. Es
decir, los cmdlets funcionan en el contexto de un espacio Windows PowerShell
ejecución. Para obtener más información sobre los espacios de ejecución de Windows
PowerShell, vea Windows PowerShell Runspaces.
Novedades
Artículo • 27/09/2021

Windows PowerShell 2.0 proporciona las siguientes características nuevas para su uso al
escribir cmdlets, proveedores y aplicaciones host.

Módulos
Ahora puede empaquetar y distribuir soluciones Windows PowerShell mediante
módulos. Los módulos permiten particionar, organizar y abstraer el código Windows
PowerShell en unidades reutilizables independientes. Para obtener más información
sobre los módulos, vea Escribir un Windows PowerShell módulo.

La clase de PowerShell
La clase de PowerShell proporciona una solución más sencilla para crear aplicaciones,
denominadas aplicaciones host, que ejecutan comandos mediante programación. Esta
clase permite crear una canalización de comandos, especificar el espacio de ejecución
que se usa para ejecutar los comandos y especificar la invocación de los comandos de
forma sincrónica o asincrónica.

La clase RunspacePool
Los grupos de espacios de ejecución permiten crear varios espacios de ejecución
mediante una sola llamada. El método CreateRunspacePool proporciona varias
sobrecargas que se pueden usar para crear espacios de ejecución que tienen las mismas
características, como el mismo host, el estado de sesión inicial y la información de
conexión.

La clase InitialSessionState
La clase InitialSessionState permite crear una configuración de estado de sesión que se
usa cuando se abre un espacio de ejecución. Puede crear una configuración
personalizada, una configuración predeterminada que incluya los comandos
proporcionados por mshshort y una configuración cuyos comandos estén restringidos
en función de las funcionalidades de la sesión.
Espacios de ejecución remotos
Ahora puede crear espacios de ejecución que se pueden abrir en equipos remotos, lo
que le permite ejecutar comandos en el equipo remoto y recopilar los resultados
localmente. Para crear un espacio de ejecución remoto, debe especificar información
sobre la conexión remota al crear el espacio de ejecución. Consulte los métodos
CreateRunspace y CreateRunspacePool para obtener ejemplos. La información de
conexión se define mediante la clase RunspaceConnectionInfo.

Elementos de espacio de ejecución privado


Ahora puede crear espacios de ejecución cuyos elementos son públicos o privados. Esto
le permite crear espacios de ejecución cuyos elementos están disponibles para el
espacio de ejecución, pero no están disponibles para el usuario. Consulte la clase
ConstrainedSessionStateEntry para averiguar qué elementos del espacio de ejecución se
pueden convertir en privados.

Modos de subprocesamiento de espacio de


ejecución y estado de apartamento
Ahora puede especificar cómo se crean y usan los subprocesos al ejecutar comandos en
un espacio de ejecución. Vea las propiedades
System.Management.Automation.Runspaces.Runspace.ThreadOptions y
System.Management.Automation.Runspaces.RunspacePool.ThreadOptions.

Ahora puede obtener el estado de apartamento de los subprocesos que se usan para
ejecutar comandos en un espacio de ejecución. Vea las propiedades
System.Management.Automation.Runspaces.Runspace.ApartmentState y
System.Management.Automation.Runspaces.RunspacePool.ApartmentState.

Cmdlets de transacción
Ahora puede crear cmdlets que se pueden usar dentro de una transacción. Cuando se
usa un cmdlet en una transacción, sus acciones son temporales y pueden ser aceptadas
o rechazadas por los cmdlets de transacción proporcionados por Windows PowerShell.

Para obtener más información sobre las transacciones, vea Cómo admitir transacciones.

Proveedor de transacciones
Ahora puede crear proveedores que se pueden usar dentro de una transacción. De
forma similar a los cmdlets, cuando se usa un proveedor en una transacción, sus
acciones son temporales y los cmdlets de transacción que proporcionan los cmdlets de
transacción pueden aceptar o rechazar Windows PowerShell.

Para obtener más información sobre cómo especificar compatibilidad para la


transacción dentro de una clase de proveedor, vea la propiedad
System.Management.Automation.Provider.CmdletProviderAttribute.ProviderCapabilities.

Cmdlets de trabajo
Ahora puede escribir cmdlets que puedan realizar su acción como un trabajo. Estos
trabajos se ejecutan en segundo plano sin interactuar con la sesión actual. Para obtener
más información sobre cómo Windows PowerShell trabajos, vea Trabajos en segundo
plano.

Tipos de salida de cmdlets


Ahora puede especificar los tipos .NET Framework que devuelven los cmdlets
declarando el atributo OutputType al escribir los cmdlets. Esto permitirá que otros
usuarios determinen qué tipo de objetos devuelve un cmdlet al mirar la propiedad
OutputType del cmdlet.

Compatibilidad con eventos


Ahora puede escribir cmdlets que agreguen y consuman eventos. Consulte la clase
PSEvent.

Comandos de proxy
Ahora puede escribir comandos de proxy que se pueden usar para ejecutar otro
comando. Un comando de proxy permite controlar qué funcionalidad del cmdlet de
origen está disponible para el usuario. Por ejemplo, puede crear un comando de proxy
que quite un parámetro proporcionado por el comando de origen. Consulte la clase
ProxyCommand.

Mensajes de varias opciones


Ahora puede escribir aplicaciones que puedan proporcionar avisos que permitan al
usuario seleccionar varias opciones. Vea la interfaz
IHostUISupportsMultipleChoiceSelection.

Sesiones interactivas
Ahora puede escribir aplicaciones que puedan iniciar y detener una sesión interactiva en
un equipo remoto. Vea la interfaz IHostSupportsInteractiveSession.

Ayuda de cmdlets personalizados para


proveedores
Ahora puede crear temas de Ayuda personalizados para los cmdlets del proveedor. Los
temas de ayuda de cmdlets personalizados pueden explicar cómo funciona el cmdlet en
la ruta de acceso del proveedor y documentar características especiales, incluidos los
parámetros dinámicos que el proveedor agrega al cmdlet.
Información general del cmdlet
Artículo • 27/09/2021

Un cmdlet es un comando ligero que se usa en el entorno de PowerShell. El tiempo de


ejecución de PowerShell invoca estos cmdlets en el contexto de los scripts de
automatización que se proporcionan en la línea de comandos. El tiempo de ejecución
de PowerShell también los invoca mediante programación a través de las API de
PowerShell.

Cmdlets
Los cmdlets realizan una acción y suelen devolver un objeto de Microsoft .NET al
comando siguiente en la canalización. Un cmdlet es un único comando que participa en
la semántica de canalización de PowerShell. Aquí se incluyen cmdlets binarios (C#),
funciones de script avanzadas, CDXML y flujos de trabajo.

En esta documentación del SDK se describe cómo crear cmdlets binarios escritos en C#.
Para obtener información sobre los cmdlets basados en scripts, consulte:

about_Functions_Advanced
about_Functions_CmdletBindingAttribute
about_Functions_Advanced_Methods

Para crear un cmdlet binario, debe implementar una clase de cmdlet que derive de una
de las dos clases base de cmdlet especializadas. La clase derivada debe:

Declare un atributo que identifique la clase derivada como un cmdlet.


Defina las propiedades públicas que se decoran con atributos que identifican las
propiedades públicas como parámetros de cmdlet.
Invalide uno o varios de los métodos de procesamiento de entrada para procesar
registros.

Puede cargar el ensamblado que contiene la clase directamente mediante el cmdlet


Import-Module o puede crear una aplicación host que cargue el ensamblado mediante
la API System.Management.Automation.Runspaces.Initialsessionstate. Ambos métodos
proporcionan acceso mediante programación y de línea de comandos a la funcionalidad
del cmdlet .

Términos del cmdlet


Los siguientes términos se usan con frecuencia en la documentación del cmdlet de
PowerShell:

Atributo de cmdlet
Atributo de .NET que se usa para declarar una clase de cmdlet como cmdlet. Aunque
PowerShell usa otros atributos que son opcionales, se requiere el atributo Cmdlet. Para
obtener más información sobre este atributo, vea Declaración de atributo de cmdlet.

Parámetro del cmdlet


Propiedades públicas que definen los parámetros que están disponibles para el usuario
o para la aplicación que ejecuta el cmdlet. Los cmdlets pueden tener parámetros
obligatorios, con nombre, posicionales y modificadores. Los parámetros switch permiten
definir parámetros que se evalúan solo si los parámetros se especifican en la llamada.
Para obtener más información sobre los distintos tipos de parámetros, vea Parámetros
de cmdlet.

Conjunto de parámetros
Grupo de parámetros que pueden usarse en el mismo comando para realizar una acción
específica. Un cmdlet puede tener varios conjuntos de parámetros, pero cada conjunto
de parámetros debe tener al menos un parámetro que sea único. Un buen diseño de
cmdlet sugiere encarecidamente que el parámetro único también sea un parámetro
necesario. Para obtener más información sobre los conjuntos de parámetros, vea Cmdlet
Parameter Sets.

Parámetro dinámico
Parámetro que se agrega al cmdlet en tiempo de ejecución. Normalmente, los
parámetros dinámicos se agregan al cmdlet cuando otro parámetro se establece en un
valor específico. Para obtener más información sobre los parámetros dinámicos, vea
Parámetros dinámicos del cmdlet.

Métodos de procesamiento de entrada


La clase System.Management.Automation.Cmdlet proporciona los siguientes métodos
virtuales que se usan para procesar registros. Todas las clases de cmdlet derivadas
deben invalidar uno o varios de los tres primeros métodos:
System.Management.Automation.Cmdlet.BeginProcessing:se usa para
proporcionar funcionalidad opcional de procesamiento previo y único para el
cmdlet.
System.Management.Automation.Cmdlet.ProcessRecord:se usa para proporcionar
la funcionalidad de procesamiento de registro por registro para el cmdlet. Es
posible que se llame al método
System.Management.Automation.Cmdlet.ProcessRecord varias veces, o no, en
función de la entrada del cmdlet.
System.Management.Automation.Cmdlet.EndProcessing:se usa para proporcionar
una funcionalidad opcional de procesamiento posterior al procesamiento para el
cmdlet.
System.Management.Automation.Cmdlet.StopProcessing:se usa para detener el
procesamiento cuando el usuario detiene el cmdlet de forma asincrónica (por
ejemplo, presionando CTRL + C ).

Para obtener más información sobre estos métodos, vea Métodos de procesamiento de
entrada de cmdlet.

Al implementar un cmdlet, debe invalidar al menos uno de estos métodos de


procesamiento de entrada. Normalmente, ProcessRecord() es el método que se invalida
porque se llama para cada registro que procesa el cmdlet. En cambio, el método
BeginProcessing() y el método EndProcessing() se llaman una vez para realizar el
procesamiento previo o posterior de los registros. Para obtener más información sobre
estos métodos, vea Métodos de procesamiento de entrada.

Característica ShouldProcess
PowerShell permite crear cmdlets que solicitan al usuario comentarios antes de que el
cmdlet haga un cambio en el sistema. Para usar esta característica, el cmdlet debe
declarar que admite la característica al declarar el atributo Cmdlet y el cmdlet debe
llamar a los métodos ShouldProcess
System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue desde dentro de un método
de procesamiento de entrada. Para obtener más información sobre cómo admitir la
ShouldProcess funcionalidad, vea Solicitar confirmación.

Transacción
Grupo lógico de comandos que se tratan como una sola tarea. La tarea produce un
error automáticamente si se produce un error en cualquier comando del grupo y el
usuario tiene la opción de aceptar o rechazar las acciones realizadas dentro de la
transacción. Para participar en una transacción, el cmdlet debe declarar que admite
transacciones cuando se declara el atributo Cmdlet. La compatibilidad con transacciones
se introdujo en Windows PowerShell 2.0. Para obtener más información sobre las
transacciones, vea Cómo admitir transacciones.

Diferencia de los cmdlets con respecto a los


comandos
Los cmdlets difieren de los comandos de otros entornos de shell de comandos de las
maneras siguientes:

Los cmdlets son instancias de clases de .NET; no son ejecutables independientes.


Los cmdlets se pueden crear a partir de unas docenas de líneas de código.
Los cmdlets no suelen realizar su propio análisis, presentación de errores o
formato de salida. El tiempo de ejecución de PowerShell controla el análisis, la
presentación de errores y el formato de salida.
Los cmdlets procesan objetos de entrada de la canalización en lugar de secuencias
de texto, y los cmdlets suelen entregar objetos como salida a la canalización.
Los cmdlets están orientados a registros porque procesan un único objeto a la vez.

Clases base de cmdlets


Windows PowerShell admite cmdlets derivados de las dos clases base siguientes.

La mayoría de los cmdlets se basan en clases de .NET que derivan de la clase base
System.Management.Automation.Cmdlet. Derivar de esta clase permite que un
cmdlet use el conjunto mínimo de dependencias en el entorno Windows
PowerShell ejecución. lo que ofrece dos ventajas. La primera ventaja es que los
objetos de cmdlet son más pequeños y es menos probable que se ven afectados
por los cambios en el tiempo de ejecución de PowerShell. La segunda ventaja es
que, si es así, puede crear directamente una instancia del objeto de cmdlet y, a
continuación, invocarla directamente en lugar de invocarla a través del tiempo de
ejecución de PowerShell.

Los cmdlets más complejos se basan en clases .NET que derivan de la clase base
System.Management.Automation.PSCmdlet. La derivación de esta clase
proporciona mucho más acceso al entorno de ejecución de PowerShell. Este
acceso permite que el cmdlet llame a scripts, acceda a proveedores y acceda al
estado de sesión actual. (Para acceder al estado de sesión actual, obtiene y
establece las variables y preferencias de sesión). Sin embargo, derivar de esta clase
aumenta el tamaño del objeto de cmdlet y significa que el cmdlet está más
estrechamente acoplado a la versión actual del tiempo de ejecución de PowerShell.

En general, a menos que necesite el acceso extendido al entorno de ejecución de


PowerShell, debe derivar de la clase System.Management.Automation.Cmdlet. Sin
embargo, el entorno de ejecución de PowerShell tiene amplias funcionalidades de
registro para la ejecución de cmdlets. Si el modelo de auditoría depende de este
registro, puede evitar la ejecución del cmdlet desde otro cmdlet derivando de la clase
System.Management.Automation.PSCmdlet.

Atributos del cmdlet


PowerShell define varios atributos de .NET que se usan para administrar cmdlets y para
especificar la funcionalidad común que proporciona PowerShell y que podría ser
necesaria para el cmdlet. Por ejemplo, los atributos se usan para designar una clase
como un cmdlet, para especificar los parámetros del cmdlet y para solicitar la validación
de la entrada para que los desarrolladores de cmdlets no tengan que implementar esa
funcionalidad en su código de cmdlet. Para obtener más información sobre los
atributos, vea Atributos de PowerShell.

Nombres de cmdlets
PowerShell usa un par de nombres verbo y sustantivo para dar nombre a los cmdlets.
Por ejemplo, el cmdlet Get-Command incluido en PowerShell se usa para obtener todos
los cmdlets que están registrados en el shell de comandos. El verbo identifica la acción
que realiza el cmdlet y el nombre identifica el recurso en el que el cmdlet realiza la
acción.

Estos nombres se especifican cuando la clase .NET se declara como un cmdlet. Para
obtener más información sobre cómo declarar una clase .NET como un cmdlet, vea
Declaración de atributo de cmdlet.

Escribir código de cmdlet


En este documento se proporcionan dos maneras de detectar cómo se escribe el código
del cmdlet. Si prefiere ver el código sin mucha explicación, consulte Ejemplos de código
de cmdlet. Si prefiere obtener más explicaciones sobre el código, vea los temas GetProc
Tutorial, StopProc Tutorialo SelectStr Tutorial.

Para obtener más información sobre las directrices para escribir cmdlets, vea
Instrucciones de desarrollo de cmdlets.
Consulte también
Conceptos de los cmdlets de PowerShell

Escritura de un cmdlet de PowerShell

SDK de PowerShell
Conceptos del cmdlet de Windows
PowerShell
Artículo • 24/09/2021

En esta sección se describe cómo funcionan los cmdlets.

En esta sección
Esta sección incluye los temas siguientes.

Instrucciones de desarrollo de cmdlets En este tema se proporcionan instrucciones de


desarrollo que se pueden usar para generar cmdlets bien formados.

Declaración de clase de cmdlet En este tema se describe la declaración de clase de


cmdlet.

Verbos aprobados para Windows PowerShell comandos En este tema se enumeran los
verbos de cmdlet predefinidos que puede usar al declarar una clase de cmdlet.

Métodos de procesamiento de entrada de cmdlet En este tema se describen los


métodos que permiten a un cmdlet realizar operaciones de preprocesamiento,
operaciones de procesamiento de entrada y operaciones posteriores al procesamiento.

Parámetros del cmdlet En esta sección se describen los distintos tipos de parámetros
que se pueden agregar a los cmdlets.

Atributos de cmdlet En esta sección se describen los atributos que se usan para declarar
.NET Framework clases como cmdlets, declarar campos como parámetros de cmdlet y
declarar reglas de validación de entrada para parámetros.

Alias de cmdlet En este tema se describen los alias de cmdlet.

Salida del cmdlet En esta sección se describe el tipo de salida que pueden devolver los
cmdlets y cómo definir y mostrar los objetos devueltos por los cmdlets.

Registro de cmdlets En esta sección se describe cómo registrar cmdlets mediante


módulos y complementos.

Solicitud de confirmación En esta sección se describe cómo los cmdlets solicitan


confirmación a un usuario antes de realizar un cambio en el sistema.

Windows PowerShell informes de errores En esta sección se describe cómo los cmdlets
informan de errores de terminación y errores de no terminación, y se describe cómo
interpretar los registros de errores.

Trabajos en segundo plano En este tema se describe cómo los cmdlets pueden realizar
su trabajo dentro de trabajos en segundo plano que no interfieren con los comandos
que se ejecutan en la sesión actual.

Invocación de cmdlets y scripts dentro de un cmdlet En este tema se describe cómo los
cmdlets pueden invocar otros cmdlets y scripts desde sus métodos de procesamiento
de entrada.

Conjuntos de cmdlets En este tema se describe el uso de clases base para crear
conjuntos de cmdlets.

Windows PowerShell de sesión En este tema se describe Windows PowerShell de sesión.


Directrices de desarrollo del cmdlet
Artículo • 27/09/2021

En los temas de esta sección se proporcionan instrucciones de desarrollo que puede


usar para generar cmdlets bien formados. Al aprovechar la funcionalidad común
proporcionada por el entorno de ejecución de Windows PowerShell y seguir estas
directrices, puede desarrollar cmdlets sólidos con el mínimo esfuerzo y proporcionar al
usuario una experiencia coherente. Además, reducirá la carga de prueba porque la
funcionalidad común no requiere volver a probar.

En esta sección
Directrices de desarrollo necesarias

Directrices de desarrollo recomendadas encarecidamente

Directrices de desarrollo de consulta

Vea también
Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Directrices de desarrollo necesarias
Artículo • 26/09/2021

Se deben seguir las instrucciones siguientes al escribir los cmdlets. Se separan en


instrucciones para diseñar cmdlets y directrices para escribir el código del cmdlet. Si no
sigue estas directrices, los cmdlets podrían producir un error y los usuarios podrían
tener una experiencia deficiente cuando usan los cmdlets.

En este tema

Directrices de diseño
Usar solo verbos aprobados (RD01)

Nombres de cmdlet: caracteres que no se pueden usar (RD02)

Nombres de parámetros que no se pueden usar (RD03)

Solicitudes de confirmación de soporte técnico (RD04)

Parámetro Forzar compatibilidad para sesiones interactivas (RD05)

Objetos de salida de documentos (RD06)

Directrices de código
Derivar de las clases Cmdlet o PSCmdlet (RC01)

Especificar el atributo de cmdlet (RC02)

Invalidar un método de procesamiento de entrada (RC03)

Especificar el atributo OutputType (RC04)

No conservar identificadores en objetos de salida (RC05)

Controlar los errores de forma sólida (RC06)

Usar un módulo Windows PowerShell para implementar los cmdlets (RC07)

Directrices de diseño
Se deben seguir las instrucciones siguientes al diseñar cmdlets para garantizar una
experiencia de usuario coherente entre el uso de los cmdlets y otros cmdlets. Cuando
encuentre una guía de diseño que se aplique a su situación, asegúrese de ver las
directrices de código para instrucciones similares.

Usar solo verbos aprobados (RD01)


El verbo especificado en el atributo Cmdlet debe procede del conjunto reconocido de
verbos proporcionado por Windows PowerShell. No debe ser uno de los sinónimos
prohibidos. Use las cadenas constantes definidas por las enumeraciones siguientes para
especificar verbos de cmdlet:

System.Management.Automation.VerbsCommon

System.Management.Automation.VerbsCommunications

System.Management.Automation.VerbsData

System.Management.Automation.VerbsDiagnostic

System.Management.Automation.VerbsLifeCycle

System.Management.Automation.VerbsSecurity

System.Management.Automation.VerbsOther

Para obtener más información sobre los nombres de verbo aprobados, vea Verbos de
cmdlet.

Los usuarios necesitan un conjunto de nombres de cmdlet reconocibles y esperados.


Use el verbo adecuado para que el usuario pueda realizar una evaluación rápida de lo
que hace un cmdlet y detectar fácilmente las funcionalidades del sistema. Por ejemplo,
el siguiente comando de línea de comandos obtiene una lista de todos los comandos
del sistema cuyos nombres comienzan por "start": get-command start-* . Use los
nombres de los cmdlets para diferenciar los cmdlets de otros cmdlets. El sustantivo
indica el recurso en el que se realizará la operación. La propia operación se representa
mediante el verbo .

Nombres de cmdlet: caracteres que no se pueden usar


(RD02)
Cuando asigne un nombre a los cmdlets, no use ninguno de los siguientes caracteres
especiales.
Carácter Nombre

# signo de número

, coma

() paréntesis

{} ortodoncia

[] corchetes

& Ampersand

- guión Nota: el guión se puede usar para separar el verbo del sustantivo, pero no se
puede usar dentro del sustantivo ni dentro del verbo.

/ barra diagonal

\ barra diagonal inversa

$ signo de dólar

^ símbolo de intercalación

; punto y coma

: Colon

" comillas dobles

' comilla simple

<> corchetes angulares

| barra vertical

? interrogación

@ signo arroba

` back-tick (acento grave)

* asterisco

% signo de porcentaje

+ signo más

= signo igual

~ Tilde
Nombres de parámetros que no se pueden usar (RD03)
Windows PowerShell proporciona un conjunto común de parámetros para todos los
cmdlets más parámetros adicionales que se agregan en situaciones específicas. Al
diseñar sus propios cmdlets, no puede usar los siguientes nombres: Confirm, Debug,
ErrorAction, ErrorVariable, OutBuffer, OutVariable, WarningAction, WarningVariable,
WhatIf, UseTransaction y Verbose. Para obtener más información sobre estos
parámetros, vea Common Parameter Names.

Solicitudes de confirmación de soporte técnico (RD04)


Para los cmdlets que realizan una operación que modifica el sistema, deben llamar al
método System.Management.Automation.Cmdlet.ShouldProcess* para solicitar
confirmación y, en casos especiales, llamar al método
System.Management.Automation.Cmdlet.ShouldContinue*. (Solo se debe llamar al
método System.Management.Automation.Cmdlet.ShouldContinue* después de llamar al
método System.Management.Automation.Cmdlet.ShouldProcess*).

Para realizar estas llamadas, el cmdlet debe especificar que admite solicitudes de
confirmación estableciendo la SupportsShouldProcess palabra clave del atributo Cmdlet.
Para obtener más información sobre cómo establecer este atributo, vea Declaración de
atributo de cmdlet.

7 Nota

Si el atributo Cmdlet de la clase de cmdlet indica que el cmdlet admite llamadas al


método System.Management.Automation.Cmdlet.ShouldProcess* y el cmdlet no
puede realizar la llamada al método
System.Management.Automation.Cmdlet.ShouldProcess*, el usuario podría
modificar el sistema de forma inesperada.

Use el método System.Management.Automation.Cmdlet.ShouldProcess* para cualquier


modificación del sistema. Una preferencia de usuario y WhatIf el parámetro controlan el
método System.Management.Automation.Cmdlet.ShouldProcess*. Por el contrario, la
llamada a System.Management.Automation.Cmdlet.ShouldContinue* realiza una
comprobación adicional de las modificaciones potencialmente peligrosas. Este método
no está controlado por ninguna preferencia de usuario ni por el WhatIf parámetro . Si el
cmdlet llama al método System.Management.Automation.Cmdlet.ShouldContinue*,
debe tener un parámetro que omita las llamadas a estos dos métodos y que continúe
con la Force operación. Esto es importante porque permite que el cmdlet se utilice en
scripts y hosts no interactivos.

Si los cmdlets admiten estas llamadas, el usuario puede determinar si la acción se debe
realizar realmente. Por ejemplo, el cmdlet Stop-Process llama al método
System.Management.Automation.Cmdlet.ShouldContinue* antes de detener un
conjunto de procesos críticos, incluidos los procesos System, Winlogon y Spoolsv.

Para obtener más información sobre cómo admitir estos métodos, vea Solicitar
confirmación.

Parámetro Forzar compatibilidad para sesiones


interactivas (RD05)
Si el cmdlet se usa de forma interactiva, proporcione siempre un parámetro Force para
invalidar las acciones interactivas, como avisos o lectura de líneas de entrada. Esto es
importante porque permite que el cmdlet se utilice en scripts y hosts no interactivos. Un
host interactivo puede implementar los métodos siguientes.

System.Management.Automation.Host.PSHostUserInterface.Prompt*

System.Management.Automation.Host.Pshostuserinterface.PromptForChoice

System.Management.Automation.Host.Ihostuisupportsmultiplechoiceselection.Pro
mptForChoice

System.Management.Automation.Host.Pshostuserinterface.PromptForCredential*

System.Management.Automation.Host.Pshostuserinterface.ReadLine*

System.Management.Automation.Host.Pshostuserinterface.ReadLineAsSecureString
*

Objetos de salida del documento (RD06)


Windows PowerShell usa los objetos que se escriben en la canalización. Para que los
usuarios puedan aprovechar los objetos devueltos por cada cmdlet, debe documentar
los objetos que se devuelven y debe documentar para qué se usan los miembros de
esos objetos devueltos.

Directrices de código
Se deben seguir las siguientes directrices al escribir código de cmdlet. Cuando
encuentre una guía de código que se aplique a su situación, asegúrese de buscar
instrucciones similares en Las directrices de diseño.

Derivar de las clases Cmdlet o PSCmdlet (RC01)


Un cmdlet debe derivar de la clase base System.Management.Automation.Cmdlet o
System.Management.Automation.PSCmdlet. Los cmdlets que derivan de la clase
System.Management.Automation.Cmdlet no dependen del entorno Windows
PowerShell ejecución. Se pueden llamar directamente desde cualquier lenguaje .NET
Framework Microsoft. Los cmdlets que derivan de la clase
System.Management.Automation.PSCmdlet dependen del entorno Windows PowerShell
ejecución. Por lo tanto, se ejecutan dentro de un espacio de ejecución.

Todas las clases de cmdlet que implemente deben ser clases públicas. Para obtener más
información sobre estas clases de cmdlet, vea Información general sobre cmdlets.

Especificar el atributo de cmdlet (RC02)


Para que un cmdlet sea reconocido por Windows PowerShell, su .NET Framework clase
debe decorarse con el atributo Cmdlet. Este atributo especifica las siguientes
características del cmdlet.

El par verbo-y nombre que identifica el cmdlet.

Conjunto de parámetros predeterminado que se usa cuando se especifican varios


conjuntos de parámetros. El conjunto de parámetros predeterminado se usa
cuando Windows PowerShell no tiene suficiente información para determinar qué
conjunto de parámetros se va a usar.

Indica si el cmdlet admite llamadas al método


System.Management.Automation.Cmdlet.ShouldProcess*. Este método muestra un
mensaje de confirmación al usuario antes de que el cmdlet haga un cambio en el
sistema. Para obtener más información sobre cómo se realizan las solicitudes de
confirmación, vea Solicitar confirmación.

Indique el nivel de impacto (o gravedad) de la acción asociada al mensaje de


confirmación. En la mayoría de los casos, se debe usar el valor predeterminado de
Medio. Para obtener más información sobre cómo el nivel de impacto afecta a las
solicitudes de confirmación que se muestran al usuario, vea Solicitar confirmación.

Para obtener más información sobre cómo declarar el atributo de cmdlet, vea
Declaración de CmdletAttribute.
Invalidar un método de procesamiento de entrada (RC03)
Para que el cmdlet participe en el Windows PowerShell, debe invalidar al menos uno de
los métodos de procesamiento de entrada siguientes.

System.Management.Automation.Cmdlet.BeginProcessing Este método se llama una vez


y se usa para proporcionar funcionalidad de procesamiento previo.

System.Management.Automation.Cmdlet.ProcessRecord Este método se llama varias


veces y se usa para proporcionar funcionalidad de registro por registro.

System.Management.Automation.Cmdlet.EndProcessing Este método se llama una vez y


se usa para proporcionar la funcionalidad posterior al procesamiento.

Especificar el atributo OutputType (RC04)


El atributo OutputType (introducido en Windows PowerShell 2.0) especifica el tipo .NET
Framework que el cmdlet devuelve a la canalización. Al especificar el tipo de salida de
los cmdlets, los objetos devueltos por el cmdlet son más reconocibles por otros cmdlets.
Para obtener más información sobre cómo decorar la clase de cmdlet con este atributo,
vea Declaración de atributo OutputType.

No conservar los identificadores de los objetos de salida


(RC05)
El cmdlet no debe conservar ningún identificador para los objetos que se pasan al
método System.Management.Automation.Cmdlet.WriteObject*. Estos objetos se pasan
al siguiente cmdlet de la canalización o los usa un script. Si conserva los identificadores
de los objetos, dos entidades serán las propietarias de cada objeto, lo que produce
errores.

Controlar los errores de forma sólida (RC06)


Un entorno de administración detecta y realiza cambios importantes en el sistema que
está administrando de forma inherente. Por lo tanto, es fundamental que los cmdlets
controle correctamente los errores. Para obtener más información sobre los registros de
errores, vea Windows PowerShell Error Reporting.

Cuando un error impide que un cmdlet siga procesando más registros, es un error
de terminación. El cmdlet debe llamar al método
System.Management.Automation.Cmdlet.ThrowTerminatingError* que hace
referencia a un objeto System.Management.Automation.ErrorRecord. Si el cmdlet
no detecta una excepción, Windows PowerShell tiempo de ejecución genera un
error de terminación que contiene menos información.

Para un error de no terminación que no detiene la operación en el siguiente


registro que viene de la canalización (por ejemplo, un registro generado por un
proceso diferente), el cmdlet debe llamar al método
System.Management.Automation.Cmdlet.WriteError* que hace referencia a un
objeto System.Management.Automation.ErrorRecord. Un ejemplo de error de no
terminación es el error que se produce si un proceso determinado no se detiene.
Llamar al método System.Management.Automation.Cmdlet.WriteError* permite al
usuario realizar de forma coherente las acciones solicitadas y conservar la
información de acciones concretas que no se realizan correctamente. El cmdlet
debe controlar cada registro de la forma más independiente posible.

El objeto System.Management.Automation.ErrorRecord al que hacen referencia los


métodos System.Management.Automation.Cmdlet.ThrowTerminatingError* y
System.Management.Automation.Cmdlet.WriteError* requiere una excepción en su
núcleo. Siga las .NET Framework de diseño al determinar la excepción que se va a
usar. Si el error es semánticamente el mismo que una excepción existente, use esa
excepción o derive de esa excepción. De lo contrario, derive una nueva jerarquía
de excepciones o excepciones directamente del tipo System.Exception.

Un objeto System.Management.Automation.ErrorRecord también requiere una categoría


de error que agrupa los errores del usuario. El usuario puede ver los errores en función
de la categoría estableciendo el valor de la $ErrorView variable de shell en
CategoryView. La enumeración System.Management.Automation.ErrorCategory define
las categorías posibles.

Si un cmdlet crea un subproceso y el código que se ejecuta en ese subproceso


produce una excepción no controlada, Windows PowerShell no detectará el error y
finalizará el proceso.

Si un objeto tiene código en su destructor que produce una excepción no


controlada, Windows PowerShell detectará el error y finalizará el proceso. Esto
también ocurre si un objeto llama a métodos Dispose que provocan una excepción
no controlada.

Usar un Windows PowerShell para implementar los


cmdlets (RC07)
Cree un Windows PowerShell para empaquetar e implementar los cmdlets. La
compatibilidad con módulos se introdujo en Windows PowerShell 2.0. Puede usar los
ensamblados que contienen las clases de cmdlet directamente como archivos de
módulo binarios (esto es muy útil al probar los cmdlets) o puede crear un manifiesto de
módulo que haga referencia a los ensamblados de cmdlet. (También puede agregar
ensamblados de complemento existentes al usar módulos). Para obtener más
información sobre los módulos, vea Writing a Windows PowerShell Module.

Consulte también
Directrices de desarrollo recomendadas encarecidamente

Directrices de desarrollo de consulta

Escribir un cmdlet de Windows PowerShell


Directrices de desarrollo recomendadas
encarecidamente
Artículo • 07/10/2021

En esta sección se describen las directrices que debe seguir al escribir los cmdlets. Se
separan en instrucciones para diseñar cmdlets e instrucciones para escribir el código del
cmdlet. Es posible que encuentre que estas directrices no son aplicables a todos los
escenarios. Sin embargo, si se aplican y no se siguen estas directrices, es posible que los
usuarios tengan una experiencia deficiente al usar los cmdlets.

Directrices de diseño
Se deben seguir las siguientes directrices al diseñar cmdlets para garantizar una
experiencia de usuario coherente entre el uso de los cmdlets y otros cmdlets. Cuando
encuentre una guía de diseño que se aplique a su situación, asegúrese de buscar
instrucciones similares en las directrices de código.

Usar un nombre específico para un nombre de cmdlet


(SD01)
Los nombres usados en la nomenclatura de cmdlets deben ser muy específicos para que
el usuario pueda detectar los cmdlets. Prefijo de nombres genéricos como "servidor"
con una versión abreviada del nombre del producto. Por ejemplo, si un sustantivo hace
referencia a un servidor que ejecuta una instancia de Microsoft SQL Server, use un
nombre como "SQLServer". La combinación de nombres específicos y la breve lista de
verbos aprobados permiten al usuario detectar y prever rápidamente la funcionalidad, al
tiempo que evita la duplicación entre los nombres de cmdlet.

Para mejorar la experiencia del usuario, el nombre que elija para un nombre de cmdlet
debe ser singular. Por ejemplo, use el nombre en Get-Process lugar de Get-Processes .
Es mejor seguir esta regla para todos los nombres de cmdlet, incluso cuando es
probable que un cmdlet actúe sobre más de un elemento.

Uso de Pascal Case para nombres de cmdlet (SD02)


Use el caso Pascal para los nombres de parámetro. En otras palabras, en mayúsculas, la
primera letra del verbo y todos los términos usados en el sustantivo. Por ejemplo,
" Clear-ItemProperty ".
Directrices de diseño de parámetros (SD03)
Un cmdlet necesita parámetros que reciban los datos en los que debe operar y
parámetros que indiquen información que se usa para determinar las características de
la operación. Por ejemplo, un cmdlet podría tener un parámetro que recibe datos de la
canalización y el cmdlet podría tener un parámetro para indicar que el cmdlet se puede
forzar para Name Force realizar su operación. No hay ningún límite en el número de
parámetros que puede definir un cmdlet.

Usar nombres de parámetro estándar

El cmdlet debe usar nombres de parámetro estándar para que el usuario pueda
determinar rápidamente lo que significa un parámetro determinado. Si se requiere un
nombre más específico, use un nombre de parámetro estándar y, a continuación,
especifique un nombre más específico como alias. Por ejemplo, el cmdlet tiene un
parámetro que tiene un nombre genérico ( ) y Get-Service un alias más específico (
Name ServiceName ). Ambos términos se pueden usar para especificar el parámetro .

Para obtener más información sobre los nombres de parámetros y sus tipos de datos,
vea Cmdlet Parameter Name and Functionality Guidelines.

Usar nombres de parámetro singulares


Evite el uso de nombres plurales para los parámetros cuyo valor es un único elemento.
Esto incluye parámetros que toman matrices o listas porque el usuario podría
proporcionar una matriz o lista con un solo elemento.

Los nombres de parámetros plurales solo se deben usar en aquellos casos en los que el
valor del parámetro sea siempre un valor de varios elementos. En estos casos, el cmdlet
debe comprobar que se proporcionan varios elementos y el cmdlet debe mostrar una
advertencia al usuario si no se proporcionan varios elementos.

Uso de pascal case para nombres de parámetro

Use el caso Pascal para los nombres de parámetro. En otras palabras, incluya la primera
letra de cada palabra en el nombre del parámetro, incluida la primera letra del nombre.
Por ejemplo, el nombre del parámetro ErrorAction usa la mayúsculas y mayúsculas
correcta. Los siguientes nombres de parámetro usan mayúsculas incorrectas:

errorAction

erroraction
Parámetros que toman una lista de opciones
Hay dos maneras de crear un parámetro cuyo valor se puede seleccionar de un conjunto
de opciones.

Defina un tipo de enumeración (o use un tipo de enumeración existente) que


especifique los valores válidos. A continuación, use el tipo de enumeración para
crear un parámetro de ese tipo.

Agregue el atributo ValidateSet a la declaración de parámetro. Para obtener más


información sobre este atributo, vea ValidateSet Attribute Declaration.

Usar tipos estándar para parámetros


Para garantizar la coherencia con otros cmdlets, use tipos estándar para los parámetros
siempre que sea posible. Para obtener más información sobre los tipos que se deben
usar para distintos parámetros, vea Tipos y nombres de parámetros de cmdlet estándar.
En este tema se proporcionan vínculos a varios temas que describen los nombres y .NET
Framework para grupos de parámetros estándar, como los "parámetros de actividad".

Usar Strongly-Typed .NET Framework tipos de datos


Los parámetros deben definirse como tipos .NET Framework para proporcionar una
mejor validación de parámetros. Por ejemplo, los parámetros que están restringidos a
un valor de un conjunto de valores deben definirse como un tipo de enumeración. Para
admitir un valor de Identificador uniforme de recursos (URI), defina el parámetro como
un tipo System.Uri. Evite los parámetros de cadena básicos para todas las propiedades
de texto de forma libre, pero sin formato.

Usar tipos de parámetros coherentes

Cuando varios cmdlets usen el mismo parámetro, use siempre el mismo tipo de
parámetro. Por ejemplo, si el parámetro es un tipo System.Int16 para un cmdlet, no
haga que el parámetro de otro Process cmdlet sea de tipo Process System.Uint16.

Parámetros que toman True y False

Si el parámetro solo toma true y , defina el parámetro como tipo false


System.Management.Automation.SwitchParameter. Un parámetro switch se trata true
como cuando se especifica en un comando. Si el parámetro no se incluye en un
comando, Windows PowerShell considera que el valor del parámetro es false . No
defina parámetros booleanos.

Si el parámetro necesita diferenciar entre 3 valores: $true, $false y "unspecified", defina


un parámetro de tipo que acepta valores <bool> NULL. La necesidad de un tercer valor
"sin especificar" suele producirse cuando el cmdlet puede modificar una propiedad
booleana de un objeto . En este caso, "sin especificar" significa no cambiar el valor
actual de la propiedad.

Compatibilidad de matrices para parámetros

Con frecuencia, los usuarios deben realizar la misma operación en varios argumentos.
Para estos usuarios, un cmdlet debe aceptar una matriz como entrada de parámetros
para que un usuario pueda pasar los argumentos al parámetro como una variable
Windows PowerShell datos. Por ejemplo, el cmdlet Get-Process usa una matriz para las
cadenas que identifican los nombres de los procesos que se deben recuperar.

Compatibilidad con el parámetro PassThru


De forma predeterminada, muchos cmdlets que modifican el sistema, como el cmdlet
Stop-Process, actúan como "receptores" para los objetos y no devuelven un resultado.
Este cmdlet debe implementar el PassThru parámetro para forzar al cmdlet a devolver
un objeto . Cuando se especifica el parámetro , el cmdlet devuelve un objeto mediante
una llamada al método PassThru System.Management.Automation.Cmdlet.WriteObject.
Por ejemplo, el siguiente comando detiene el proceso calc y pasa el proceso resultante a
la canalización.

PowerShell

Stop-Process calc -passthru

En la mayoría de los casos, los cmdlets Add, Set y New deben admitir un PassThru
parámetro .

Compatibilidad con conjuntos de parámetros

Un cmdlet está pensado para lograr un único propósito. Sin embargo, con frecuencia
hay más de una manera de describir la operación o el destino de la operación. Por
ejemplo, un proceso podría identificarse por su nombre, por su identificador o por un
objeto de proceso. El cmdlet debe admitir todas las representaciones razonables de sus
destinos. Normalmente, el cmdlet satisface este requisito especificando conjuntos de
parámetros (denominados conjuntos de parámetros) que funcionan juntos. Un único
parámetro puede pertenecer a cualquier número de conjuntos de parámetros. Para
obtener más información sobre los conjuntos de parámetros, vea Cmdlet Parameter
Sets.

Al especificar conjuntos de parámetros, establezca solo un parámetro del conjunto en


ValueFromPipeline. Para obtener más información sobre cómo declarar el atributo
Parameter, vea ParameterAttribute Declaration.

Cuando se usan conjuntos de parámetros, el atributo Cmdlet define el conjunto de


parámetros predeterminado. El conjunto de parámetros predeterminado debe incluir
los parámetros que es más probable que se utilicen en una sesión Windows PowerShell
interactiva. Para obtener más información sobre cómo declarar el atributo Cmdlet, vea
Declaración de CmdletAttribute.

Proporcionar comentarios al usuario (SD04)


Use las directrices de esta sección para proporcionar comentarios al usuario. Estos
comentarios permiten al usuario ser consciente de lo que ocurre en el sistema y tomar
mejores decisiones administrativas.

El Windows PowerShell de ejecución permite a un usuario especificar cómo controlar la


salida de cada llamada al método Write estableciendo una variable de preferencia. El
usuario puede establecer varias variables de preferencia, incluida una variable que
determina si el sistema debe mostrar información y una variable que determina si el
sistema debe consultar al usuario antes de tomar medidas adicionales.

Compatibilidad con los métodos WriteWarning, WriteVerbose y


WriteDebug

Un cmdlet debe llamar al método


System.Management.Automation.Cmdlet.WriteWarning cuando el cmdlet está a punto
de realizar una operación que podría tener un resultado no deseado. Por ejemplo, un
cmdlet debe llamar a este método si el cmdlet está a punto de sobrescribir un archivo
de solo lectura.

Un cmdlet debe llamar al método


System.Management.Automation.Cmdlet.WriteVerbose cuando el usuario requiera
algún detalle sobre lo que hace el cmdlet. Por ejemplo, un cmdlet debe llamar a esta
información si el autor del cmdlet considera que hay escenarios que pueden requerir
más información sobre lo que hace el cmdlet.
El cmdlet debe llamar al método System.Management.Automation.Cmdlet.WriteDebug
cuando un desarrollador o ingeniero de soporte técnico de producto debe comprender
lo que ha dañado la operación del cmdlet. No es necesario que el cmdlet llame al
método System.Management.Automation.Cmdlet.WriteDebug en el mismo código que
llama al método System.Management.Automation.Cmdlet.WriteVerbose porque el
parámetro presenta ambos conjuntos de Debug información.

Compatibilidad con WriteProgress para operaciones que llevan


mucho tiempo
Las operaciones de cmdlet que llevan mucho tiempo en completarse y que no se
pueden ejecutar en segundo plano deben admitir informes de progreso a través de
llamadas periódicas al método System.Management.Automation.Cmdlet.WriteProgress.

Uso de las interfaces de host

En ocasiones, un cmdlet debe comunicarse directamente con el usuario en lugar de


mediante los distintos métodos Write o Should admitidos por la clase
System.Management.Automation.Cmdlet. En este caso, el cmdlet debe derivar de la
clase System.Management.Automation.PSCmdlet y usar la propiedad
System.Management.Automation.PSCmdlet.Host*. Esta propiedad admite diferentes
niveles de tipo de comunicación, incluidos los tipos PromptForChoice, Prompt y
WriteLine/ReadLine. En el nivel más específico, también proporciona maneras de leer y
escribir claves individuales y tratar con búferes.

A menos que un cmdlet esté diseñado específicamente para generar una interfaz gráfica
de usuario (GUI), no debe omitir el host mediante la propiedad
System.Management.Automation.PSCmdlet.Host*. Un ejemplo de un cmdlet diseñado
para generar una GUI es el cmdlet Out-GridView.

7 Nota

Los cmdlets no deben usar la API System.Console.

Crear un archivo de ayuda de cmdlet (SD05)


Para cada ensamblado de cmdlet, cree un Help.xml que contenga información sobre el
cmdlet. Esta información incluye una descripción del cmdlet, descripciones de los
parámetros del cmdlet, ejemplos del uso del cmdlet y mucho más.
Directrices de código
Se deben seguir las instrucciones siguientes al codificar cmdlets para garantizar una
experiencia de usuario coherente entre el uso de los cmdlets y otros cmdlets. Cuando
encuentre una guía de código que se aplique a su situación, asegúrese de buscar
directrices de diseño para instrucciones similares.

Parámetros de codificación (SC01)


Defina un parámetro declarando una propiedad pública de la clase de cmdlet que se
decora con el atributo Parameter. Los parámetros no tienen que ser miembros estáticos
de la clase .NET Framework derivada para el cmdlet . Para obtener más información
sobre cómo declarar el atributo Parameter, vea Declaración de atributo de parámetro.

Compatibilidad con Windows PowerShell de acceso

La Windows PowerShell de acceso es el mecanismo para normalizar el acceso a los


espacios de nombres. Al asignar una ruta de acceso Windows PowerShell a un
parámetro en el cmdlet , el usuario puede definir una "unidad" personalizada que actúe
como acceso directo a una ruta de acceso específica. Cuando un usuario designa dicha
unidad, los datos almacenados, como los datos del Registro, se pueden usar de forma
coherente.

Si el cmdlet permite al usuario especificar un archivo o un origen de datos, debe definir


un parámetro de tipo System.String. Si se admite más de una unidad, el tipo debe ser
una matriz. El nombre del parámetro debe ser Path , con un alias de PSPath . Además,
el parámetro Path debe admitir caracteres comodín. Si no se requiere compatibilidad
con caracteres comodín, defina un LiteralPath parámetro .

Si los datos que lee o escribe el Windows PowerShell cmdlet deben ser un archivo, el
cmdlet debe aceptar una entrada de ruta de acceso y el cmdlet debe usar la propiedad
System.Management.Automation.Sessionstate.Path para convertir las rutas de acceso de
Windows PowerShell en rutas de acceso que el sistema de archivos reconoce. Los
mecanismos específicos incluyen los métodos siguientes:

System.Management.Automation.PSCmdlet.GetResolvedProviderPathFromPSPath
System.Management.Automation.PSCmdlet.GetUnresolvedProviderPathFromPSPat
h
System.Management.Automation.PathIntrinsics.GetResolvedProviderPathFromPSPa
th
System.Management.Automation.PathIntrinsics.GetUnresolvedProviderPathFromPS
Path

Si los datos que lee o escribe el cmdlet son solo un conjunto de cadenas en lugar de un
archivo, el cmdlet debe usar la información de contenido del proveedor (miembro) para
leer Content y escribir. Esta información se obtiene de la propiedad
System.Management.Automation.Provider.CmdletProvider.InvokeProvider. Estos
mecanismos permiten a otros almacenes de datos participar en la lectura y escritura de
datos.

Admitir caracteres comodín


Si es posible, un cmdlet debe admitir caracteres comodín. La compatibilidad con
caracteres comodín se produce en muchos lugares de un cmdlet (especialmente cuando
un parámetro toma una cadena para identificar un objeto de un conjunto de objetos).
Por ejemplo, el cmdlet de ejemplo del tutorial StopProc define un parámetro para
controlar Stop-Proc las Name cadenas que representan nombres de proceso. Este
parámetro admite caracteres comodín para que el usuario pueda especificar fácilmente
los procesos que se deben detener.

Cuando hay disponible compatibilidad con caracteres comodín, una operación de


cmdlet normalmente genera una matriz. En ocasiones, no tiene sentido admitir una
matriz porque el usuario podría usar solo un elemento a la vez. Por ejemplo, el cmdlet
Set-Location no necesita admitir una matriz porque el usuario establece solo una
ubicación. En esta instancia, el cmdlet todavía admite caracteres comodín, pero fuerza la
resolución a una sola ubicación.

Para obtener más información sobre los patrones de caracteres comodín, vea Admitir
caracteres comodín en parámetros de cmdlet.

Definir objetos

Esta sección contiene instrucciones para definir objetos para cmdlets y para extender
objetos existentes.

Definición de miembros estándar

Defina miembros estándar para extender un tipo de objeto en un archivo Types.ps1xml


personalizado (use el archivo types.ps1xml de Windows PowerShell como plantilla). Los
miembros estándar se definen mediante un nodo con el nombre PSStandardMembers.
Estas definiciones permiten que otros cmdlets y Windows PowerShell runtime funcionen
con el objeto de forma coherente.

Definir ObjectMembers para que se utilicen como parámetros

Si va a diseñar un objeto para un cmdlet, asegúrese de que sus miembros se asignan


directamente a los parámetros de los cmdlets que lo usarán. Esta asignación permite
que el objeto se envíe fácilmente a la canalización y se pase de un cmdlet a otro.

A los objetos .NET Framework que devuelven los cmdlets les faltan con frecuencia
algunos miembros importantes o prácticos que el desarrollador o el usuario del script
necesitan. Estos miembros que faltan pueden ser especialmente importantes para
mostrar y crear los nombres de miembro correctos para que el objeto se pueda pasar
correctamente a la canalización. Cree un archivo Types.ps1xml personalizado para
documentar estos miembros necesarios. Al crear este archivo, se recomienda la
siguiente convención de nomenclatura: <Your_Product_Name>. Types.ps1xml.

Por ejemplo, podría agregar una propiedad de script al tipo Mode System.IO.FileInfo para
mostrar los atributos de un archivo con mayor claridad. Además, podría agregar una
propiedad de alias al tipo System.Array para permitir el uso coherente de ese nombre
de Count propiedad (en lugar de Length ).

Implementación de la interfaz IComparable

Implemente una interfaz System.IComparable en todos los objetos de salida. Esto


permite canalizar fácilmente los objetos de salida a varios cmdlets de ordenación y
análisis.

Actualizar información de visualización

Si la presentación de un objeto no proporciona los resultados esperados, cree un


<YourProductName> personalizado. Archivo Format.ps1xml para ese objeto.

Compatibilidad con la entrada de canalización bien


definida (SC02)

Implementación para el medio de una canalización


Implemente un cmdlet suponiendo que se llamará desde el centro de una canalización
(es decir, otros cmdlets producirán su entrada o consumirán su salida). Por ejemplo,
puede suponer que el cmdlet, porque genera datos, solo se usa como el Get-Process
primer cmdlet de una canalización. Sin embargo, dado que este cmdlet está diseñado
para el centro de una canalización, este cmdlet permite que los cmdlets o datos
anteriores de la canalización especifiquen los procesos que se deben recuperar.

Entrada de compatibilidad desde la canalización

En cada conjunto de parámetros de un cmdlet, incluya al menos un parámetro que


admita la entrada de la canalización. La compatibilidad con la entrada de canalización
permite al usuario recuperar datos u objetos, enviarlos al conjunto de parámetros
correcto y pasar los resultados directamente a un cmdlet.

Un parámetro acepta la entrada de la canalización si el atributo Parameter incluye la


palabra clave , el atributo keyword o ambas palabras ValueFromPipeline clave en su
ValueFromPipelineByPropertyName declaración. Si ninguno de los parámetros de un

conjunto de parámetros admite las palabras clave o , el cmdlet no se puede colocar


significativamente después de otro cmdlet porque omitirá cualquier entrada
ValueFromPipeline ValueFromPipelineByPropertyName de canalización.

Compatibilidad con el método ProcessRecord


Para aceptar todos los registros del cmdlet anterior en la canalización, el cmdlet debe
implementar el método System.Management.Automation.Cmdlet.ProcessRecord.
Windows PowerShell llama a este método varias veces, una vez por cada registro que se
envía al cmdlet.

Escribir registros únicos en la canalización (SC03)


Cuando un cmdlet devuelve objetos, el cmdlet debe escribir los objetos inmediatamente
a medida que se generan. El cmdlet no debe contenerlos para almacenarlos en búfer en
una matriz combinada. Los cmdlets que reciben los objetos como entrada podrán
procesar, mostrar o procesar y mostrar los objetos de salida sin retraso. Un cmdlet que
genera objetos de salida de uno en uno debe llamar al método
System.Management.Automation.Cmdlet.WriteObject. Un cmdlet que genera objetos de
salida en lotes (por ejemplo, porque una API subyacente devuelve una matriz de objetos
de salida) debe llamar al método System.Management.Automation.Cmdlet.WriteObject
con su segundo parámetro establecido en true .

Crear cmdlets Case-Insensitive y Case-Preserving (SC04)


De forma predeterminada, Windows PowerShell sí mismo no tiene en cuenta las
mayúsculas y minúsculas. Sin embargo, dado que se ocupa de muchos sistemas
preexistente, Windows PowerShell conserva las mayúsculas y minúsculas para facilitar el
funcionamiento y la compatibilidad. En otras palabras, si se proporciona un carácter en
mayúsculas, Windows PowerShell lo mantiene en mayúsculas. Para que los sistemas
funcionen bien, un cmdlet debe seguir esta convención. Si es posible, debe funcionar de
una manera que no tenga en cuenta las mayúsculas y minúsculas. Sin embargo, debe
conservar el caso original de los cmdlets que se producen más adelante en un comando
o en la canalización.

Consulte también
Directrices de desarrollo necesarias

Directrices de desarrollo de consulta

Escribir un cmdlet de Windows PowerShell


Directrices de desarrollo de consulta
Artículo • 07/10/2021

En esta sección se describen las directrices que debe tener en cuenta para garantizar un
buen desarrollo y experiencias de usuario. A veces se pueden aplicar y, a veces, es
posible que no.

Directrices de diseño
Se deben tener en cuenta las siguientes directrices al diseñar cmdlets. Cuando
encuentre una guía de diseño que se aplique a su situación, asegúrese de ver las
directrices de código para instrucciones similares.

Compatibilidad con un parámetro InputObject (AD01)


Dado Windows PowerShell funciona directamente con objetos de Microsoft .NET
Framework, a menudo hay disponible un objeto .NET Framework que coincide
exactamente con el tipo que el usuario necesita para realizar una operación
determinada. InputObject es el nombre estándar de un parámetro que toma un objeto
como entrada. Por ejemplo, el cmdlet de ejemplo del tutorial StopProc define un
parámetro de Stop-Proc tipo Process que admite la entrada de la InputObject
canalización. El usuario puede obtener un conjunto de objetos de proceso, manipularlos
para seleccionar los objetos exactos que se detendrá y, a continuación, pasarlos al Stop-
Proc cmdlet directamente.

Compatibilidad con el parámetro Force (AD02)


En ocasiones, un cmdlet debe proteger al usuario de realizar una operación solicitada.
Este cmdlet debe admitir un parámetro Force para permitir que el usuario invalide esa
protección si el usuario tiene permisos para realizar la operación.

Por ejemplo, el cmdlet Remove-Item normalmente no quita un archivo de solo lectura.


Sin embargo, este cmdlet admite un parámetro Force para que un usuario pueda forzar
la eliminación de un archivo de solo lectura. Si el usuario ya tiene permiso para
modificar el atributo de solo lectura y el usuario quita el archivo, el uso del parámetro
Force simplifica la operación. Sin embargo, si el usuario no tiene permiso para quitar el
archivo, el parámetro Force no tiene ningún efecto.
Controlar las credenciales mediante Windows PowerShell
(AD03)
Un cmdlet debe definir un Credential parámetro para representar las credenciales. Este
parámetro debe ser de tipo System.Management.Automation.PSCredential y debe
definirse mediante una declaración de atributo Credential. Esta compatibilidad solicita
automáticamente al usuario el nombre de usuario, la contraseña o ambos cuando no se
proporciona una credencial completa directamente. Para obtener más información
sobre el atributo Credential, vea Declaración de atributo de credencial.

Compatibilidad con parámetros de codificación (AD04)


Si el cmdlet lee o escribe texto en o desde un formulario binario, como escribir en un
archivo en un sistema de archivos o leerlo desde este, el cmdlet debe tener el parámetro
Encoding que especifique cómo se codifica el texto en formato binario.

Los cmdlets de prueba deben devolver un valor booleano


(AD05)
Los cmdlets que realizan pruebas en sus recursos deben devolver un tipo
System.Boolean a la canalización para que se puedan usar en expresiones condicionales.

Directrices de código
Se deben tener en cuenta las siguientes directrices al escribir código de cmdlet. Cuando
encuentre una directriz que se aplique a su situación, asegúrese de buscar directrices de
diseño para instrucciones similares.

Seguir las convenciones de nomenclatura de clases de


cmdlets (AC01)
Al seguir las convenciones de nomenclatura estándar, los cmdlets son más reconocibles
y ayudan al usuario a comprender exactamente lo que hacen los cmdlets. Esta práctica
es especialmente importante para otros desarrolladores que usan Windows PowerShell
porque los cmdlets son tipos públicos.

Definir un cmdlet en el espacio de nombres correcto


Normalmente se define la clase para un cmdlet en un espacio .NET Framework de
nombres que anexa ". Comandos" para el espacio de nombres que representa el
producto en el que se ejecuta el cmdlet. Por ejemplo, los cmdlets que se incluyen con
Windows PowerShell se definen en el espacio de Microsoft.PowerShell.Commands
nombres .

Asigne un nombre a la clase de cmdlet para que coincida con el


nombre del cmdlet.

Cuando asigne un nombre a la clase .NET Framework que implementa un cmdlet, asigne
un nombre a la clase " ", donde reemplace los marcadores de posición y por el verbo y
el nombre que se usa para el <Verb><Noun><Command> <Verb> nombre del
<Noun> cmdlet. Por ejemplo, el cmdlet Get-Process se implementa mediante una clase
denominada GetProcessCommand .

Si ninguna entrada de canalización invalida el método


BeginProcessing (AC02)
Si el cmdlet no acepta la entrada de la canalización, el procesamiento debe
implementarse en el método System.Management.Automation.Cmdlet.BeginProcessing.
El uso de este método permite Windows PowerShell mantener el orden entre cmdlets. El
primer cmdlet de la canalización siempre devuelve sus objetos antes de que los cmdlets
restantes de la canalización puedan iniciar su procesamiento.

Para controlar las solicitudes de detenerse, invalide el


método StopProcessing (AC03)
Invalide el método System.Management.Automation.Cmdlet.StopProcessing para que el
cmdlet pueda controlar la señal de detenerse. Algunos cmdlets necesitan mucho tiempo
para completar su operación y permiten pasar mucho tiempo entre las llamadas al
entorno de ejecución de Windows PowerShell, como cuando el cmdlet bloquea el
subproceso en llamadas RPC de ejecución larga. Esto incluye cmdlets que hacen
llamadas al método System.Management.Automation.Cmdlet.WriteObject, al método
System.Management.Automation.Cmdlet.WriteError y a otros mecanismos de
comentarios que pueden tardar mucho tiempo en completarse. En estos casos, es
posible que el usuario tenga que enviar una señal de detenerse a estos cmdlets.

Implementación de la interfaz IDisposable (AC04)


Si el cmdlet tiene objetos que el método
System.Management.Automation.Cmdlet.ProcessRecord no desecharon (escritos en la
canalización), es posible que el cmdlet requiera la eliminación de objetos adicional. Por
ejemplo, si el cmdlet abre un identificador de archivo en su método
System.Management.Automation.Cmdlet.BeginProcessing y mantiene el identificador
abierto para que lo use el método
System.Management.Automation.Cmdlet.ProcessRecord, este identificador debe
cerrarse al final del procesamiento.

El Windows PowerShell runtime no siempre llama al método


System.Management.Automation.Cmdlet.EndProcessing. Por ejemplo, es posible que no
se llame al método System.Management.Automation.Cmdlet.EndProcessing si el cmdlet
se cancela a mitad de su operación o si se produce un error de terminación en cualquier
parte del cmdlet. Por lo tanto, la clase .NET Framework para un cmdlet que requiere
limpieza de objetos debe implementar el patrón de interfaz System.IDisposable
completo, incluido el finalizador, para que el entorno de ejecución de Windows
PowerShell pueda llamar a los métodos
System.Management.Automation.Cmdlet.EndProcessing y System.IDisposable.Dispose*
al final del procesamiento.

Usar tipos de parámetros compatibles con la serialización


(AC05)
Para admitir la ejecución del cmdlet en equipos remotos, use tipos que se puedan
serializar fácilmente en el equipo cliente y, a continuación, rehidratarse en el equipo
servidor. Los tipos siguientes son descriptivos para la serialización.

Tipos primitivos:

Byte, SByte, Decimal, Single, Double, Int16, Int32, Int64, Uint16, UInt32 y UInt64.

Boolean, Guid, Byte[], TimeSpan, DateTime, Uri y Version.

Char, String, XmlDocument.

Tipos rehidrátibles integrados:

PSPrimitiveDictionary

SwitchParameter

PSListModifier

PSCredential
IPAddress, MailAddress

CultureInfo

X509Certificate2, X500DistinguishedName

DirectorySecurity, FileSecurity, RegistrySecurity

Otros tipos:

SecureString

Contenedores (listas y diccionarios del tipo anterior)

Uso de SecureString para datos confidenciales (AC06)


Al controlar datos confidenciales, use siempre el tipo de datos
System.Security.Securestring. Esto podría incluir la entrada de canalización a los
parámetros, así como la devolución de datos confidenciales a la canalización.

Consulte también
Directrices de desarrollo necesarias

Directrices de desarrollo recomendadas encarecidamente

Escribir un cmdlet de Windows PowerShell


Declaración de clase del cmdlet
Artículo • 27/09/2021

Una clase .NET Framework microsoft se declara como un cmdlet especificando el


atributo Cmdlet como metadatos para la clase . (El atributo cmdlet es el único atributo
necesario para todos los cmdlets). Al especificar el atributo Cmdlet, debe especificar el
par verbo-y-nombre que identifica el cmdlet al usuario. Además, debe describir la
funcionalidad de Windows PowerShell que admite el cmdlet . Para obtener más
información sobre la sintaxis de declaración que se usa para especificar el atributo
Cmdlet, vea Declaración de atributo de cmdlet.

7 Nota

La clase System.Management.Automation.CmdletAttribute define el atributo


Cmdlet. Las propiedades de esta clase corresponden a los parámetros de
declaración que se usan al declarar el atributo.

Sustantivos
El nombre del cmdlet especifica los recursos sobre los que actúa el cmdlet. El sustantivo
diferencia los cmdlets de otros cmdlets.

Los nombres de los nombres de cmdlet deben ser específicos y, en el caso de nombres
genéricos, como el servidor , es mejor agregar un prefijo corto que diferencie el recurso
de otros recursos similares. Por ejemplo, un nombre de cmdlet que incluye un
sustantivo con un prefijo es Get-SQLServer . La combinación de un sustantivo específico
con un verbo más general permite al usuario localizar rápidamente el cmdlet por su
acción y, a continuación, identificar el cmdlet por su recurso, al tiempo que evita la
duplicación innecesaria del nombre del cmdlet.

Para obtener una lista de caracteres especiales que no se pueden usar en nombres de
cmdlet, vea Instrucciones de desarrollo necesarias.

Verbos
Al especificar un verbo, las directrices de desarrollo requieren que se use uno de los
verbos predefinidos proporcionados por Windows PowerShell. Mediante el uso de uno
de estos verbos predefinidos, garantizará la coherencia entre los cmdlets que escribe y
los cmdlets escritos por Microsoft y otros. Por ejemplo, el verbo "Get" se usa para los
cmdlets que recuperan datos.

Para obtener más información sobre las directrices para verbos, vea Nombres de verbos
de cmdlet. Para obtener una lista de caracteres especiales que no se pueden usar en
nombres de cmdlet, vea Instrucciones de desarrollo necesarias.

Compatibilidad con Windows PowerShell


funcionalidad
El atributo Cmdlet también permite especificar que el cmdlet admite algunas de las
funcionalidades comunes que proporciona Windows PowerShell. Esto incluye
compatibilidad con funcionalidades comunes, como la confirmación de comentarios del
usuario (denominada compatibilidad con la característica ShouldProcess) y la
compatibilidad con transacciones. (La compatibilidad con transacciones se introdujo en
Windows PowerShell 2.0).

Para obtener más información sobre la sintaxis de declaración que se usa para
especificar el atributo Cmdlet, vea Declaración de atributo de cmdlet.

Definición de clase de cmdlet


El código siguiente es la definición de una clase de cmdlet GetProc. Observe que se usa
el uso de mayúsculas y minúsculas Pascal y que el nombre de la clase incluye el verbo y
el nombre del cmdlet.

C#

[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet

Mayúsculas y minúsculas Pascal


Cuando asigne un nombre a los cmdlets, use mayúsculas y minúsculas Pascal. Por
ejemplo, los cmdlets y muestran la manera correcta de usar mayúsculas y mayúsculas al
asignar Get-Item nombres a los Get-ItemProperty cmdlets.

Consulte también
System.Management.Automation.CmdletAttribute
Declaración de CmdletAttribute

Nombres de verbos de cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Verbos aprobados para los comandos
de PowerShell
Artículo • 01/02/2022

PowerShell usa un par verbo-sustantivo para los nombres de los cmdlets y las clases
derivadas de .NET. El elemento verbal del nombre identifica la acción que realiza el
cmdlet. Por su parte, el sustantivo del nombre identifica la entidad en la que se lleva a
cabo la acción. Por ejemplo, el cmdlet Get-Command recupera todos los comandos que
están registrados en PowerShell.

7 Nota

PowerShell usa el término verbo para describir una palabra que implica una acción,
aunque esa palabra no sea un verbo estándar en el idioma inglés. Por ejemplo, el
término Nuevo es un nombre de verbo de PowerShell válido porque implica una
acción, aunque no sea un verbo en el idioma inglés.

Cada verbo aprobado tiene definido un prefijo de alias correspondiente. Usamos este
prefijo de alias en los alias para los comandos que emplean ese verbo. Por ejemplo, el
prefijo de alias para Import es ip y, en consecuencia, el alias para Import-Module es
ipmo . Se trata de una recomendación, pero no de una regla; en concreto, no es
necesario respetar los alias de comandos que imitan comandos conocidos de otros
entornos.

Recomendaciones de nomenclatura de verbos


Las siguientes recomendaciones le ayudarán a elegir un verbo adecuado para su cmdlet,
a fin de garantizar la coherencia entre los cmdlets que se crean, los que proporciona
PowerShell y los diseñados por otros usuarios.

Uso de uno de los nombres de verbo predefinidos de PowerShell


Use el verbo para describir el ámbito general de la acción, y los parámetros, para
restringir aún más la acción del cmdlet.
No use un sinónimo de un verbo aprobado. Por ejemplo, use siempre Remove , pero
nunca Delete ni Eliminate .
Use solo la forma de cada verbo que se muestra en este tema. Por ejemplo, use
Get , pero no Getting ni Gets .
No utilice los siguientes verbos o alias reservados. El lenguaje de PowerShell y
algunos cmdlets poco frecuentes usan estos verbos en circunstancias
excepcionales.
ForEach (foreach)
Ping (pi)
Sort (sr)
Tee (te)
Where (wh)

Puede obtener una lista completa de verbos con el cmdlet Get-Verb .

Verbos similares para diferentes acciones


Los siguientes verbos similares representan acciones diferentes.

Nuevo frente a Agregar


Use el verbo New para crear un recurso. Use para Add agregar algo a un contenedor o
recurso existente. Por ejemplo, Add-Content agrega la salida a un archivo existente.

Comparación entre New y Set


Use el verbo New para crear un recurso. Use el verbo Set para modificar un recurso
existente y, opcionalmente, si no existe, crearlo, como el cmdlet Set-Variable .

Comparación entre Find y Search


Utilice el verbo Find para buscar un objeto. Utilice el verbo Search para crear una
referencia a un recurso en un contenedor.

Comparación entre Get y Lectura


Utilice el verbo Get para obtener información sobre un recurso (por ejemplo, un
archivo) o para obtener un objeto con el que pueda acceder al recurso en el futuro. Use
el Read verbo para abrir un recurso y extraer la información contenida en .

Comparación entre Invoke y Start


Utilice el verbo Invoke para realizar operaciones sincrónicas, como ejecutar un
comando y esperar a que finalice. Use el Start verbo para iniciar operaciones
asincrónicas, como iniciar un proceso autónomo.

Comparación entre Ping y Prueba


Utilice el verbo Test .

Verbos comunes
PowerShell usa la clase de enumeración
System.Management.Automation.VerbsCommon para definir acciones genéricas que se
pueden aplicar a casi cualquier cmdlet. En la tabla siguiente se muestran la mayoría de
los verbos definidos.

Verbo Acción Sinónimos que


(alias) hay que evitar

Add (a) Agrega un recurso a un contenedor o asocia un elemento a otro. Append, Attach,
Por ejemplo, el cmdlet Add-Content agrega contenido a un Concatenate,
archivo. Este verbo se empareja con Remove . Insert

Clear (cl) Quita todos los recursos de un contenedor, pero no elimina el Flush, Erase,
contenedor. Por ejemplo, el cmdlet Clear-Content quita el Release, Unmark,
contenido de un archivo, pero no elimina el archivo. Unset, Nullify

Close Cambia el estado de un recurso para que sea inaccesible, no


(cs) disponible o inutilizable. Este verbo se empareja con Open. .

Copy Copia un recurso en otro nombre o en otro contenedor. Por Duplicate, Clone,
(cp) ejemplo, el cmdlet Copy-Item copia un elemento (por ejemplo, un Replicate, Sync
archivo) de una ubicación del almacén de datos a otra.

Enter (et) Especifica una acción que permite al usuario moverse a un Push, Into
recurso. Por ejemplo, el cmdlet Enter-PSSession coloca al usuario
en una sesión interactiva. Este verbo se empareja con Exit .

Exit (ex) Establece el entorno o contexto actual en el contexto usado más Pop, Out
recientemente. Por ejemplo, el cmdlet Exit-PSSession coloca al
usuario en la sesión que se empleó para iniciar la sesión
interactiva. Este verbo se empareja con Enter .

Find (fd) Busca un objeto en un contenedor desconocido, implícito, Search


opcional o especificado.
Verbo Acción Sinónimos que
(alias) hay que evitar

Formato Organiza objetos en un formato o diseño especificados.


(f)

Get (g) Especifica una acción que recupera un recurso. Este verbo se Read, Open, Cat,
empareja con Set . Type, Dir, Obtain,
Dump, Acquire,
Examine, Find,
Search

Hide (h) Convierte un recurso en indetectable. Por ejemplo, un cmdlet Bloquear


cuyo nombre incluya el verbo Hide podría ocultar un servicio de
un usuario. Este verbo se empareja con Show .

Join (j) Combina varios recursos en uno. Por ejemplo, el cmdlet Join- Combine, Unite,
Path combina una ruta de acceso con una de sus rutas de acceso Connect,
secundarias para crear una única. Este verbo se empareja con Associate
Split .

Lock (lk) Protege un recurso. Este verbo se empareja con Unlock . Restrict, Secure

Move Traslada un recurso de una ubicación a otra. Por ejemplo, el Transfer, Name,
(m) cmdlet Move-Item copia un elemento de una ubicación del Migrate
almacén de datos en otra.

New (n) Crea un recurso. (También se puede usar el verbo Set al crear un Create,
recurso que incluya datos, como el cmdlet Set-Variable ). Generate, Build,
Make, Allocate

Open Cambia el estado de un recurso para que sea accesible, disponible


(op) o utilizable. Este verbo se empareja con Close .

Optimize Aumenta la eficacia de un recurso.


(om)

Pop Quita un elemento de la parte superior de una pila. Por ejemplo,


(pop) el cmdlet Pop-Location cambia la ubicación actual a la última
ubicación insertada en la pila.

Push Agrega un elemento a la parte superior de una pila. Por ejemplo,


(pu) el cmdlet Push-Location inserta la ubicación actual en la pila.

Redo (re) Restablece un recurso al estado que se deshizo.

Remove Elimina un recurso de un contenedor. Por ejemplo, el cmdlet Clear, Cut,


(r) Remove-Variable elimina una variable y su valor. Este verbo se Dispose, Discard,
empareja con Add . Erase
Verbo Acción Sinónimos que
(alias) hay que evitar

Rename Cambia el nombre de un recurso. Por ejemplo, el cmdlet Rename- Change


(rn) Item , que se usa para acceder a los datos almacenados, cambia el
nombre de un elemento en el almacén de datos.

Reset (rs) Vuelve a establecer un recurso en su estado original.

Resize(rz) Cambia el tamaño de un recurso.

Search Crea una referencia a un recurso en un contenedor. Find, Locate


(sr)

Select Busca un recurso en un contenedor. Por ejemplo, el cmdlet Find, Locate


(sc) Select-String busca texto en cadenas y archivos.

Set (s) Reemplaza datos de un recurso existente o crea un recurso que Write, Reset,
contiene algunos datos. Por ejemplo, el cmdlet Set-Date cambia Assign,
la hora del sistema en el equipo local. (El verbo New también se Configure
puede usar para crear un recurso). Este verbo se empareja con
Get .

Show Convierte un recurso en visible para el usuario. Este verbo se Display, Produce
(sh) empareja con Hide .

Skip (sk) Omite uno o varios recursos o puntos de una secuencia. Bypass, Jump

Split (sl) Separa elementos de un recurso. Por ejemplo, el cmdlet Split- Independiente
Path devuelve distintos elementos de una ruta de acceso. Este
verbo se empareja con Join .

Step (st) Se desplaza al siguiente punto o recurso de una secuencia.

Switch Especifica una acción que alterna entre dos recursos, como
(sw) cambiar entre dos ubicaciones, responsabilidades o estados.

Undo Establece un recurso en su estado anterior.


(un)

Unlock Libera un recurso que estaba bloqueado. Este verbo se empareja Release,
(uk) con Lock . Unrestrict,
Unsecure

Watch Inspecciona o supervisa continuamente los cambios de un


(wc) recurso.

Verbos de comunicaciones
PowerShell usa la clase System.Management.Automation.VerbsCommunications para
definir las acciones que se aplican a las comunicaciones. En la tabla siguiente se
muestran la mayoría de los verbos definidos.

Verbo Acción Sinónimos que hay


(alias) que evitar

Connect Crea un vínculo entre un origen y un destino. Este verbo se Join, Telnet
(cc) empareja con Disconnect .

Disconnect Rompe el vínculo entre un origen y un destino. Este verbo Break, Logoff
(dc) se empareja con Connect .

Read (rd) Adquiere información de un origen. Este verbo se empareja Acquire, Prompt, Get
con Write .

Receive Acepta información enviada desde un origen. Este verbo se Read, Accept, Peek
(rc) empareja con Send .

Send (sd) Entrega información en un destino. Este verbo se empareja Put, Broadcast, Mail,
con Receive . Fax

Write (wr) Agrega información a un destino. Este verbo se empareja Put, Print
con Read .

Verbos de datos
PowerShell usa la clase System.Management.Automation.VerbsData para definir las
acciones que se aplican a los datos. En la tabla siguiente se muestran la mayoría de los
verbos definidos.

Nombre de Acción Sinónimos


verbo que hay
(alias) que evitar

Backup (ba) Almacena los datos mediante su replicación. Save, Burn,


Replicate,
Sync

Checkpoint Crea una instantánea del estado actual de los datos o de su Diferencias
(ch) configuración.

Compare (cr) Evalúa los datos de un recurso con respecto a los datos de otro Diferencias
recurso.

Compress Compacta los datos de un recurso. Se empareja con Expand . Compacto


(cm)
Nombre de Acción Sinónimos
verbo que hay
(alias) que evitar

Convert (cv) Cambia los datos de una representación a otra cuando el cmdlet Change,
admite la conversión bidireccional o cuando el cmdlet admite la Resize,
conversión entre varios tipos de datos. Resample

ConvertFrom Realiza la conversión de un tipo principal de entrada (el sustantivo Export,


(cf) del cmdlet indica la entrada) en uno o más tipos de salida Output, Out
admitidos.

ConvertTo Realiza la conversión de uno o más tipos de entrada en un tipo de Import,


(ct) salida principal (el sustantivo del cmdlet indica el tipo de salida). Input, In

Dismount Desasocia una entidad con nombre de una ubicación. Este verbo se Unmount,
(dm) empareja con Mount . Unlink

Edit (ed) Modifica los datos existentes agregando o quitando contenido. Change,
Update,
Modify

Expand (en) Restaura los datos de un recurso que se ha comprimido a su Explode,


estado original. Este verbo se empareja con Compress . Uncompress

Export (ep) Encapsula la entrada principal en un almacén de datos persistente, Extract,


como un archivo, o en un formato de intercambio. Este verbo se Backup
empareja con Import .

Grupo (gp) Organiza o asocia uno o varios recursos.

Import (ip) Crea un recurso a partir de los datos que se almacenan en un BulkLoad,
almacén de datos persistente (por ejemplo, un archivo) o en un Load
formato de intercambio. Por ejemplo, el cmdlet Import-CSV
importa datos de un archivo de valores separados por comas (CSV)
a objetos que otros cmdlets pueden usar. Este verbo se empareja
con Export .

Initialize (in) Prepara un recurso para su uso y lo establece en un estado Erase, Init,
predeterminado. Renew,
Rebuild,
Reinitialize,
Setup

Limit (l) Aplica restricciones a un recurso. Quota

Merge (mg) Crea un recurso único a partir de varios recursos. Combine,


Join

Mount (mt) Asocia una entidad con nombre a una ubicación. Este verbo se Conectar
empareja con Dismount .
Nombre de Acción Sinónimos
verbo que hay
(alias) que evitar

Out (o) Envía datos fuera del entorno. Por ejemplo, el cmdlet Out-Printer
envía datos a una impresora.

Publish (pb) Pone un recurso a disposición de otros usuarios. Este verbo se Deploy,
empareja con Unpublish . Release,
Install

Restore (rr) Establece un recurso en un estado predefinido, como un estado Repair,


establecido por Checkpoint . Por ejemplo, el cmdlet Restore- Return,
Computer inicia una restauración del sistema en el equipo local. Undo, Fix

Save (sv) Conserva los datos para evitar pérdidas.

Sync (sy) Garantiza que dos o más recursos se encuentran en el mismo Replicate,
estado. Coerce,
Match

Unpublish Anula la puesta a disposición de un recurso para otros usuarios. Uninstall,


(ub) Este verbo se empareja con Publish . Revert, Hide

Update (ud) Pone un recurso al día para mantener su estado, precisión, Refresh,
conformidad o cumplimiento. Por ejemplo, el cmdlet Update- Renew,
FormatData actualiza y agrega archivos de formato a la consola de Recalculate,
PowerShell actual. Re-index

Verbos de diagnóstico
PowerShell usa la clase System.Management.Automation.VerbsDiagnostic para definir
las acciones que se aplican a los diagnósticos. En la tabla siguiente se muestran la
mayoría de los verbos definidos.

Verbo Acción Sinónimos que hay


(alias) que evitar

Debug Examina un recurso para diagnosticar problemas operativos. Diagnóstico


(db)

Measure Identifica los recursos que una operación especificada consume Calculate,
(ms) o recupera estadísticas de un recurso. Determine, Analyze

Ping (pi) En desuso: use el verbo Probar en su lugar.

Repair Restaura un recurso a una condición utilizable. Fix, Restore


(rp)
Verbo Acción Sinónimos que hay
(alias) que evitar

Resolve Asigna una representación abreviada de un recurso a una Expand, Determine


(rv) representación más completa.

Test (t) Comprueba la operación o la coherencia de un recurso. Diagnose, Analyze,


Salvage, Verify

Trace (tr) Realiza un seguimiento de las actividades de un recurso. Track, Follow,


Inspect, Dig

Verbos del ciclo de vida


PowerShell usa la clase System.Management.Automation.VerbsLifeCycle para definir las
acciones que se aplican al ciclo de vida de un recurso. En la tabla siguiente se muestran
la mayoría de los verbos definidos.

Verbo Acción Sinónimos


(alias) que hay que
evitar

Approve Confirma o acepta el estado de un recurso o un proceso.


(ap)

Assert (as) Confirma el estado de un recurso. Certify

Build (bd) Crea un artefacto (normalmente, un archivo binario o un


documento) fuera de algún conjunto de archivos de entrada
(normalmente, código fuente o documentos declarativos). Este
verbo se agregó en PowerShell 6.

Complete Concluye una operación.


(cp)

Confirm Confirma, verifica o valida el estado de un recurso o un proceso. Acknowledge,


(cn) Agree, Certify,
Validate,
Verify

Deny (dn) Rechaza, objeta, bloquea o se opone al estado de un recurso o un Block, Object,
proceso. Refuse, Reject

Deploy Envía una aplicación, un sitio web o una solución a uno o varios
(dp) destinos remotos de tal forma que un consumidor de esa solución
pueda acceder a ella una vez completada la implementación. Este
verbo se agregó en PowerShell 6.
Verbo Acción Sinónimos
(alias) que hay que
evitar

Disable Configura un recurso en un estado no disponible o inactivo. Por Halt, Hide


(d) ejemplo, el cmdlet Disable-PSBreakpoint convierte un punto de
interrupción en inactivo. Este verbo se empareja con Enable .

Enable (e) Configura un recurso en un estado disponible o activo. Por ejemplo, Start, Begin
el cmdlet Enable-PSBreakpoint convierte un punto de interrupción
en activo. Este verbo se empareja con Disable .

Install (is) Coloca un recurso en una ubicación y, opcionalmente, lo inicializa. Configurar


Este verbo se empareja con Uninstall .

Invoke (i) Realiza una acción, como ejecutar un comando o un método. Run, Start

Register Crea una entrada para un recurso en un repositorio, como una base
(rg) de datos. Este verbo se empareja con Unregister .

Request Solicita un recurso o solicita permisos.


(rq)

Restart (rt) Detiene una operación y, luego, la inicia de nuevo. Por ejemplo, el Reciclar
cmdlet Restart-Service detiene y reinicia un servicio.

Resume Inicia una operación que se había suspendido. Por ejemplo, el


(ru) cmdlet Resume-Service inicia un servicio que se había suspendido.
Este verbo se empareja con Suspend .

Start (sa) Inicia una operación. Por ejemplo, el cmdlet Start-Service inicia un Launch,
servicio. Este verbo se empareja con Stop . Initiate, Boot

Stop (sp) Interrumpe una actividad. Este verbo se empareja con Start . End, Kill,
Terminate,
Cancel

Submit Presenta un recurso para su aprobación. Publicar


(sb)

Suspend Pausa una actividad. Por ejemplo, el cmdlet Suspend-Service pausa Pausar
(ss) un servicio. Este verbo se empareja con Resume .

Uninstall Quita un recurso de una ubicación indicada. Este verbo se empareja


(us) con Install .

Unregister Quita la entrada de un recurso de un repositorio. Este verbo se Quitar


(ur) empareja con Register .
Verbo Acción Sinónimos
(alias) que hay que
evitar

Wait (w) Pausa una operación hasta que se produzca un evento especificado. Sleep, Pause
Por ejemplo, el cmdlet Wait-Job pausa las operaciones hasta que se
completan uno o varios de los trabajos en segundo plano.

Verbos de seguridad
PowerShell usa la clase System.Management.Automation.VerbsSecurity para definir las
acciones que se aplican a la seguridad. En la tabla siguiente se muestran la mayoría de
los verbos definidos.

Verbo Acción Sinónimos


(alias) que hay que
evitar

Block (bl) Restringe el acceso a un recurso. Este verbo se empareja con Prevent, Limit,
Unblock . Deny

Grant (gr) Permite el acceso a un recurso. Este verbo se empareja con Revoke . Allow, Enable

Protect Protege un recurso de ataques o pérdidas. Este verbo se empareja Encrypt,


(pt) con Unprotect . Safeguard,
Seal

Revoke Especifica una acción que no permite acceder a un recurso. Este Remove,
(rk) verbo se empareja con Grant . Disable

Unblock Quita las restricciones a un recurso. Este verbo se empareja con Clear, Allow
(ul) Block .

Unprotect Quita de un recurso las medidas de seguridad que se agregaron Decrypt,


(up) para evitar ataques o pérdidas. Este verbo se empareja con Unseal
Protect .

Otros verbos
PowerShell usa la clase System.Management.Automation.VerbsOther para definir
nombres de verbo canónicos que no se ajustan a una categoría de nombre de verbo
específica, como los de nombres comunes, comunicaciones, datos o ciclo de vida, o los
verbos de seguridad.

Verbo (alias) Acción Sinónimos que hay que evitar


Verbo (alias) Acción Sinónimos que hay que evitar

Use (u) Utiliza o incluye un recurso para hacer algo.

Consulte también
System.Management.Automation.VerbsCommon
System.Management.Automation.VerbsCommunications
System.Management.Automation.VerbsData
System.Management.Automation.VerbsDiagnostic
System.Management.Automation.VerbsLifeCycle
System.Management.Automation.VerbsSecurity
System.Management.Automation.VerbsOther
Declaración del cmdlet
Guía del programador de Windows PowerShell
SDK del shell de Windows PowerShell
Métodos de procesamiento de entrada
del cmdlet
Artículo • 27/09/2021

Los cmdlets deben invalidar uno o varios de los métodos de procesamiento de entrada
descritos en este tema para realizar su trabajo. Estos métodos permiten al cmdlet
realizar operaciones de procesamiento previo, procesamiento de entrada y
procesamiento posterior. Estos métodos también permiten detener el procesamiento de
cmdlets. Para obtener un ejemplo más detallado de cómo usar estos métodos, vea
SelectStr Tutorial.

Operaciones de procesamiento previo


Los cmdlets deben invalidar el método
System.Management.Automation.Cmdlet.BeginProcessing para agregar las operaciones
de preprocesamiento válidas para todos los registros que el cmdlet procesará más
adelante. Cuando PowerShell procesa una canalización de comandos, PowerShell llama
a este método una vez para cada instancia del cmdlet de la canalización. Para obtener
más información sobre cómo PowerShell invoca la canalización de comandos, vea Ciclo
de vida de procesamiento de cmdlets.

El código siguiente muestra una implementación del método BeginProcessing.

C#

protected override void BeginProcessing()


{
// Replace the WriteObject method with the logic required by your cmdlet.
WriteObject("This is a test of the BeginProcessing template.");
}

Operaciones de procesamiento de entrada


Los cmdlets pueden invalidar el método
System.Management.Automation.Cmdlet.ProcessRecord para procesar la entrada que se
envía al cmdlet. Cuando PowerShell procesa una canalización de comandos, PowerShell
llama a este método para cada registro de entrada procesado por el cmdlet. Para
obtener más información sobre cómo PowerShell invoca la canalización de comandos,
vea Ciclo de vida de procesamiento de cmdlets.
El código siguiente muestra una implementación del método ProcessRecord.

C#

protected override void ProcessRecord()


{
// Replace the WriteObject method with the logic required by your cmdlet.
WriteObject("This is a test of the ProcessRecord template.");
}

Operaciones posteriores al procesamiento


Los cmdlets deben invalidar el método
System.Management.Automation.Cmdlet.EndProcessing para agregar las operaciones
posteriores al procesamiento válidas para todos los registros procesados por el cmdlet.
Por ejemplo, es posible que el cmdlet tenga que limpiar las variables de objeto una vez
finalizado el procesamiento.

Cuando PowerShell procesa una canalización de comandos, PowerShell llama a este


método una vez para cada instancia del cmdlet de la canalización. Sin embargo, es
importante recordar que el tiempo de ejecución de PowerShell no llamará al método
EndProcessing si el cmdlet se cancela a mitad de su procesamiento de entrada o si se
produce un error de terminación en cualquier parte del cmdlet. Por este motivo, un
cmdlet que requiere limpieza de objetos debe implementar el patrón
System.IDisposable completo, incluido un finalizador, para que el tiempo de ejecución
pueda llamar a los métodos EndProcessing y System.IDisposable.Dispose al final del
procesamiento. Para obtener más información sobre cómo PowerShell invoca la
canalización de comandos, vea Ciclo de vida de procesamiento de cmdlets.

El código siguiente muestra una implementación del método EndProcessing.

C#

protected override void EndProcessing()


{
// Replace the WriteObject method with the logic required by your cmdlet.
WriteObject("This is a test of the EndProcessing template.");
}

Consulte también
System.Management.Automation.Cmdlet.BeginProcessing
System.Management.Automation.Cmdlet.ProcessRecord

System.Management.Automation.Cmdlet.EndProcessing

Tutorial de SelectStr

System.IDisposable

SDK del shell de Windows PowerShell


Parámetros del cmdlet
Artículo • 27/09/2021

Los parámetros del cmdlet proporcionan el mecanismo que permite que un cmdlet
acepte la entrada. Los parámetros pueden aceptar entradas directamente desde la línea
de comandos o desde objetos pasados al cmdlet a través de la canalización. Los
argumentos (también conocidos como valores) de estos parámetros pueden especificar
la entrada que acepta el cmdlet, cómo debe realizar sus acciones el cmdlet y los datos
que el cmdlet devuelve a la canalización.

En esta sección
Declarar propiedades como parámetros Proporciona información básica que debe
comprender antes de declarar los parámetros de un cmdlet.

Tipos de parámetros de cmdlet Describe los distintos tipos de parámetros que puede
declarar en cmdlets.

Instrucciones de funcionalidad y nombre de parámetro de cmdlet Describe los nombres,


el tipo de datos recomendado y la funcionalidad de los parámetros estándar.

Alias de parámetro Describe los alias que se pueden definir para los parámetros.

Nombres de parámetros comunes En este tema se describen los parámetros que


Windows PowerShell a los cmdlets.

Conjuntos de parámetros de cmdlet Describe cómo los conjuntos de parámetros


permiten escribir un único cmdlet que puede realizar acciones diferentes para distintos
escenarios.

Parámetros dinámicos del cmdlet Describe los parámetros que están disponibles para el
usuario en condiciones especiales.

Admitir caracteres comodín en parámetros de cmdlet Describe cómo proporcionar


compatibilidad con caracteres comodín al diseñar un cmdlet que se ejecutará en un
grupo de recursos.

Validación de la entrada de parámetros Describe cómo Windows PowerShell valida los


argumentos pasados a los parámetros del cmdlet.

Parámetros de filtro de entrada Describe los parámetros Filter Include , y que


Exclude filtran el conjunto de objetos de entrada a los que afecta el cmdlet.
Secciones relacionadas
Cómo validar la entrada de parámetros

Consulte también
Declaración de atributo de parámetro

Cmdlets de Windows PowerShell


Declaración de propiedades como
parámetros
Artículo • 27/09/2021

En este tema se proporciona información básica que debe comprender antes de


declarar los parámetros de un cmdlet.

Para declarar los parámetros de un cmdlet dentro de la clase de cmdlet, defina las
propiedades públicas que representan cada parámetro y agregue uno o varios atributos
Parameter a cada propiedad. El Windows PowerShell runtime usa los atributos
Parameter para identificar la propiedad como un parámetro de cmdlet. La sintaxis básica
para declarar el atributo Parameter es [Parameter()] .

Este es un ejemplo de una propiedad definida como un parámetro obligatorio.

C#

[Parameter(Position = 0, Mandatory = true)]


public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Estos son algunos aspectos que debe recordar sobre los parámetros.

Un parámetro debe marcarse explícitamente como público. Los parámetros que no


están marcados como públicos tienen como valor predeterminado internal y no se
encontrarán en el entorno Windows PowerShell ejecución.

Los parámetros deben definirse como tipos de .NET Framework Microsoft para
proporcionar una mejor validación de parámetros. Por ejemplo, los parámetros
que están restringidos a un valor de un conjunto de valores deben definirse como
un tipo de enumeración. Los parámetros que toman un valor de identificador
uniforme de recursos (URI) deben ser de tipo System.Uri.

Evite los parámetros de cadena básicos para todas las propiedades de texto de
forma libre, pero sin formato.

Puede agregar un parámetro a cualquier número de conjuntos de parámetros.


Para obtener más información sobre los conjuntos de parámetros, vea Cmdlet
Parameter Sets.
Windows PowerShell también proporciona un conjunto de parámetros comunes que
están disponibles automáticamente para cada cmdlet. Para obtener más información
sobre estos parámetros y sus alias, vea Cmdlet Common Parameters.

Consulte también
Parámetros comunes del cmdlet

Tipos de parámetro de cmdlet

Escribir un cmdlet de Windows PowerShell


Tipos de parámetros del cmdlet
Artículo • 24/09/2021

En este tema se describen los distintos tipos de parámetros que se pueden declarar en
los cmdlets. Los parámetros del cmdlet pueden ser parámetros posicionales, con
nombre, obligatorios, opcionales o modificadores.

Parámetros posicionales y con nombre


Todos los parámetros de cmdlet son parámetros con nombre o posicionales. Un
parámetro con nombre requiere que escriba el nombre y el argumento del parámetro al
llamar al cmdlet . Un parámetro posicional solo requiere que escriba los argumentos en
orden relativo. A continuación, el sistema asigna el primer argumento sin nombre al
primer parámetro posicional. El sistema asigna el segundo argumento sin nombre al
segundo parámetro sin nombre, y así sucesivamente. De forma predeterminada, todos
los parámetros de cmdlet se denominan parámetros.

Para definir un parámetro con nombre, omita la palabra Position clave en la


declaración de atributo Parameter, como se muestra en la siguiente declaración de
parámetro.

C#

[Parameter(ValueFromPipeline=true)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Para definir un parámetro posicional, agregue la palabra clave en la declaración de


atributo Position Parameter y, a continuación, especifique una posición. En el ejemplo
siguiente, el UserName parámetro se declara como un parámetro posicional con la
posición 0. Esto significa que el primer argumento de la llamada se enlazará
automáticamente a este parámetro.

C#

[Parameter(Position = 0)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

7 Nota

Un buen diseño de cmdlets recomienda que los parámetros más usados se


declaren como parámetros posicionales para que el usuario no tenga que escribir
el nombre del parámetro cuando se ejecute el cmdlet.

Los parámetros posicionales y con nombre aceptan argumentos únicos o varios


argumentos separados por comas. Solo se permiten varios argumentos si el parámetro
acepta una colección como una matriz de cadenas. Puede mezclar parámetros
posicionales y con nombre en el mismo cmdlet. En este caso, el sistema recupera
primero los argumentos con nombre y, a continuación, intenta asignar los argumentos
sin nombre restantes a los parámetros posicionales.

Los comandos siguientes muestran las distintas formas en que puede especificar uno y
varios argumentos para los parámetros del Get-Command cmdlet. Observe que en los dos
últimos ejemplos, no es necesario especificar -name porque el parámetro se Name
define como un parámetro posicional.

PowerShell

Get-Command -Name get-service


Get-Command -Name get-service,set-service
Get-Command get-service
Get-Command get-service,set-service

Parámetros obligatorios y opcionales


También puede definir parámetros de cmdlet como parámetros obligatorios u
opcionales. (Se debe especificar un parámetro obligatorio antes de que el Windows
PowerShell tiempo de ejecución invoque el cmdlet ). De forma predeterminada, los
parámetros se definen como opcionales.

Para definir un parámetro obligatorio, agregue la palabra clave en la declaración de


atributo Parameter y estabróla en , como se muestra Mandatory en la siguiente
declaración de true parámetro.

C#
[Parameter(Position = 0, Mandatory = true)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Para definir un parámetro opcional, omita la palabra Mandatory clave en la declaración


de atributo Parameter, como se muestra en la siguiente declaración de parámetro.

C#

[Parameter(Position = 0)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Parámetros switch
Windows PowerShell proporciona un tipo
System.Management.Automation.SwitchParameter que permite definir un parámetro
cuyo valor se establece automáticamente en si no se especifica el parámetro cuando se
llama al false cmdlet. Siempre que sea posible, use parámetros switch en lugar de
parámetros booleanos.

Tenga en cuenta el ejemplo siguiente. De forma predeterminada, Windows PowerShell


cmdlets no pasan un objeto de salida a la canalización. Sin embargo, estos cmdlets
tienen un PassThru parámetro switch que invalida el comportamiento predeterminado.
Si se especifica el parámetro cuando se llama a estos PassThru cmdlets, el cmdlet
devuelve un objeto de salida a la canalización.

Si necesita que el parámetro tenga un valor predeterminado de cuando el parámetro no


se especifica en la llamada, considere la posibilidad de invertir la true sensación del
parámetro. Por ejemplo, en lugar de establecer el atributo de parámetro en un valor
booleano de , declare la propiedad como el tipo true
System.Management.Automation.SwitchParameter y, a continuación, establezca el valor
predeterminado del parámetro en false .
Para definir un parámetro switch, declare la propiedad como el tipo
System.Management.Automation.SwitchParameter, como se muestra en el ejemplo
siguiente.

C#

[Parameter(Position = 1)]
public SwitchParameter GoodBye
{
get { return goodbye; }
set { goodbye = value; }
}
private bool goodbye;

Para que el cmdlet actúe sobre el parámetro cuando se especifica, use la siguiente
estructura dentro de uno de los métodos de procesamiento de entrada.

C#

protected override void ProcessRecord()


{
WriteObject("Switch parameter test: " + userName + ".");
if(goodbye)
{
WriteObject(" Goodbye!");
}
} // End ProcessRecord

Vea también
Escribir un cmdlet de Windows PowerShell
Tipos y nombres de parámetros del
cmdlet estándar
Artículo • 24/09/2021

Los nombres de parámetro de cmdlet deben ser coherentes en todos los cmdlets que
diseñe. En los temas siguientes se incluyen los nombres de parámetro que se
recomienda usar al declarar parámetros de cmdlet. Los temas también describen el tipo
de datos recomendado y la funcionalidad de cada parámetro.

En esta sección
Parámetros de la actividad

Parámetros de fecha y hora

Parámetros de formato

Parámetros de propiedad

Parámetros de cantidad

Parámetros del recurso

Parámetros de seguridad
Parámetros de la actividad
Artículo • 26/06/2022

En la tabla siguiente se enumeran los nombres y la funcionalidad recomendados para


los parámetros de actividad.

Parámetro Funcionalidad

Append Implemente este parámetro para que el usuario pueda agregar contenido al
Tipo de datos: final de un recurso cuando se especifique el parámetro .
SwitchParameter

CaseSensitive Implemente este parámetro para que el usuario pueda requerir distinción
Tipo de datos: entre mayúsculas y minúsculas cuando se especifique el parámetro.
SwitchParameter

Command Implemente este parámetro para que el usuario pueda especificar una
Tipo de datos: cadena de comandos que se va a ejecutar.
String

CompatibleVersion Implemente este parámetro para que el usuario pueda especificar la


Tipo de datos: semántica con la que el cmdlet debe ser compatible con versiones
System.Version anteriores.
objeto

Compress Implemente este parámetro para que se use la compresión de datos


Tipo de datos: cuando se especifica el parámetro .
SwitchParameter

Compress Implemente este parámetro para que el usuario pueda especificar el


Tipo de datos: algoritmo que se va a usar para la compresión de datos.
Keyword

Continuous Implemente este parámetro para que los datos se procesen hasta que el
Tipo de datos: usuario finalice el cmdlet cuando se especifique el parámetro . Si no se
SwitchParameter especifica el parámetro , el cmdlet procesa una cantidad predefinida de
datos y, a continuación, finaliza la operación.

Create Implemente este parámetro para indicar que se crea un recurso si aún no
Tipo de datos: existe uno cuando se especifica el parámetro .
SwitchParameter

Delete Implemente este parámetro para que los recursos se eliminen cuando el
Tipo de datos: cmdlet haya completado su operación cuando se especifique el parámetro .
SwitchParameter
Parámetro Funcionalidad

Drain Implemente este parámetro para indicar que los elementos de trabajo
Tipo de datos: pendientes se procesan antes de que el cmdlet procese nuevos datos
SwitchParameter cuando se especifique el parámetro . Si no se especifica el parámetro , los
elementos de trabajo se procesan inmediatamente.

Erase Implemente este parámetro para que el usuario pueda especificar el


Tipo de datos: número de veces que se borra un recurso antes de eliminarlo.
Int32

ErrorLevel Implemente este parámetro para que el usuario pueda especificar el nivel
Tipo de datos: de errores que se van a notificar.
Int32

Exclude Implemente este parámetro para que el usuario pueda excluir algo de una
Tipo de datos: actividad. Para obtener más información sobre cómo usar filtros de entrada,
String[] vea Parámetros de filtro de entrada.

Filter Implemente este parámetro para que el usuario pueda especificar un filtro
Tipo de datos: que seleccione los recursos en los que se va a realizar la acción del cmdlet.
Keyword Para obtener más información sobre cómo usar filtros de entrada, vea
Parámetros de filtro de entrada.

Seguir Implemente este parámetro para que se realice un seguimiento del


Tipo de datos: progreso cuando se especifica el parámetro .
SwitchParameter

Force Implemente este parámetro para indicar que el usuario puede realizar una
Tipo de datos: acción incluso si se encuentran restricciones cuando se especifica el
SwitchParameter parámetro . El parámetro no permite que la seguridad se ponga en peligro.
Por ejemplo, este parámetro permite a un usuario sobrescribir un archivo
de solo lectura.

Include Implemente este parámetro para que el usuario pueda incluir algo en una
Tipo de datos: actividad. Para obtener más información sobre cómo usar filtros de entrada,
String[] vea Parámetros de filtro de entrada.

Incremental Implemente este parámetro para indicar que el procesamiento se realiza de


Tipo de datos: forma incremental cuando se especifica el parámetro . Por ejemplo, este
SwitchParameter parámetro permite al usuario realizar copias de seguridad incrementales
que realizan copias de seguridad de archivos solo desde la última copia de
seguridad.

EntradaObject Implemente este parámetro cuando el cmdlet toma la entrada de otros


Tipo de datos: cmdlets. Al definir un parámetro InputObject , especifique siempre la
Object palabra clave ValueFromPipeline al declarar el atributo Parameter . Para
obtener más información sobre el uso de filtros de entrada, vea Parámetros
de filtro de entrada.
Parámetro Funcionalidad

Insert Implemente este parámetro para que el cmdlet inserte un elemento cuando
Tipo de datos: se especifique el parámetro .
SwitchParameter

Interactivo Implemente este parámetro para que el cmdlet funcione de forma


Tipo de datos: interactiva con el usuario cuando se especifica el parámetro .
SwitchParameter

Interval Implemente este parámetro para que el usuario pueda especificar una tabla
Tipo de datos: hash de palabras clave que contenga los valores. En el ejemplo siguiente se
HashTable muestran valores de ejemplo para el Interval parámetro : -interval
@{ResumeScan=15; Retry=3} .

Log Implemente este parámetro para auditar las acciones del cmdlet cuando se
Tipo de datos: especifica el parámetro .
SwitchParameter

NoClobber Implemente este parámetro para que el recurso no se sobrescriba cuando


Tipo de datos: se especifique el parámetro . Este parámetro se aplica generalmente a los
SwitchParameter cmdlets que crean nuevos objetos para que se les impida sobrescribir
objetos existentes con el mismo nombre.

Notify Implemente este parámetro para que se notifique al usuario que la


Tipo de datos: actividad se complete cuando se especifique el parámetro .
SwitchParameter

NotifyDirección Implemente este parámetro para que el usuario pueda especificar la


Tipo de datos: dirección de correo electrónico que se usará para enviar una notificación
dirección de correo cuando se especifique el Notify parámetro .
electrónico

Sobrescribir Implemente este parámetro para que el cmdlet sobrescriba los datos
Tipo de datos: existentes cuando se especifica el parámetro .
SwitchParameter

Prompt Implemente este parámetro para que el usuario pueda especificar un


Tipo de datos: mensaje para el cmdlet .
String

Quiet Implemente este parámetro para que el cmdlet suprima los comentarios del
Tipo de datos: usuario durante sus acciones cuando se especifique el parámetro .
SwitchParameter

Recurse Implemente este parámetro para que el cmdlet realice de forma recursiva
Tipo de datos: sus acciones en los recursos cuando se especifica el parámetro .
SwitchParameter
Parámetro Funcionalidad

Repair Implemente este parámetro para que el cmdlet intente corregir algo de un
Tipo de datos: estado roto cuando se especifique el parámetro .
SwitchParameter

RepairString Implemente este parámetro para que el usuario pueda especificar una
Tipo de datos: cadena que se usará cuando se especifique el parámetro Repair .
String

Retry Implemente este parámetro para que el usuario pueda especificar el


Tipo de datos: número de veces que el cmdlet intentará una acción.
Int32

Select Implemente este parámetro para que el usuario pueda especificar uno array
Tipo de datos: de los tipos de elementos.
Keyword array

Stream Implemente este parámetro para que el usuario pueda transmitir varios
Tipo de datos: objetos de salida a través de la canalización cuando se especifica el
SwitchParameter parámetro .

Strict Implemente este parámetro para que todos los errores se controlen como
Tipo de datos: errores de terminación cuando se especifica el parámetro .
SwitchParameter

TempLocation Implemente este parámetro para que el usuario pueda especificar la


Tipo de datos: ubicación de los datos temporales que se usan durante el funcionamiento
String del cmdlet.

Tiempo de espera Implemente este parámetro para que el usuario pueda especificar el
Tipo de datos: intervalo de tiempo de espera (en milisegundos).
Int32

Truncate Implemente este parámetro para que el cmdlet trunquen sus acciones
Tipo de datos: cuando se especifique el parámetro . Si no se especifica el parámetro , el
SwitchParameter cmdlet realiza otra acción.

Verify Implemente este parámetro para que el cmdlet pruebe para determinar si
Tipo de datos: se ha producido una acción cuando se especifica el parámetro .
SwitchParameter

Wait Implemente este parámetro para que el cmdlet espere a la entrada del
Tipo de datos: usuario antes de continuar cuando se especifique el parámetro .
SwitchParameter

WaitTime Implemente este parámetro para que el usuario pueda especificar la


Tipo de datos: duración (en segundos) que el cmdlet esperará a la entrada del usuario
Int32 cuando se especifique el parámetro Wait .
Consulte también
Parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Parámetros de fecha y hora
Artículo • 27/09/2021

En la tabla siguiente se enumeran los nombres recomendados y la funcionalidad de los


parámetros que controlan la información de fecha y hora. Los parámetros de fecha y
hora se usan normalmente para registrar cuándo se crea o se accede a algo.

Parámetro Funcionalidad

Acceder Implemente este parámetro para que, cuando se especifique, el cmdlet


Tipo de datos: funcione en los recursos a los que se ha accedido en función de la fecha y hora
SwitchParameter especificadas por los parámetros Before y After. Si se especifica este
parámetro, no se deben especificar los parámetros Creado y Modificado.

Después Implemente este parámetro para especificar la fecha y hora después de la cual
Tipo de datos: se usó el cmdlet . Para que el parámetro After funcione, el cmdlet también
DateTime debe tener un parámetro Accessed, Created o Modified. Además, ese
parámetro debe establecerse en true cuando se llama al cmdlet .

Antes Implemente este parámetro para especificar la fecha y hora antes de que se
Tipo de datos: usara el cmdlet. Para que el parámetro Before funcione, el cmdlet también
DateTime debe tener un parámetro Accessed, Created o Modified. Además, ese
parámetro debe establecerse en true cuando se llama al cmdlet .

Creado Implemente este parámetro para que, cuando se especifique, el cmdlet


Tipo de datos: funcione en los recursos creados en función de la fecha y hora especificadas
SwitchParameter por los parámetros Before y After. Si se especifica este parámetro, no se
deben especificar los parámetros Accessed y Modified.

Exact Implemente este parámetro para que, cuando se especifique, el término de


Tipo de datos: recurso debe coincidir exactamente con el nombre del recurso. Cuando no se
SwitchParameter especifica el parámetro, el término de recurso y el nombre no tienen que
coincidir exactamente.

Modificado Implemente este parámetro para que, cuando se especifique, el cmdlet


Tipo de datos: funcione en los recursos que se han cambiado en función de la fecha y hora
DateTime especificadas por los parámetros Before y After. Si se especifica este
parámetro, no se deben especificar los parámetros Accessed y Created.

Consulte también
Parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Parámetros de formato
Artículo • 24/09/2021

En la tabla siguiente se enumeran los nombres recomendados y la funcionalidad de los


parámetros que se usan para dar formato o generar datos.

Parámetro Funcionalidad

Como Implemente este parámetro para especificar el formato de salida del cmdlet.
Tipo de datos: Por ejemplo, los valores posibles podrían ser Texto o Script.
Palabra clave

Binario Implemente este parámetro para indicar que el cmdlet controla los valores
Tipo de datos: binarios.
SwitchParameter

Encoding Implemente este parámetro para especificar el tipo de codificación que se


Tipo de datos: admite. Por ejemplo, los valores posibles podrían ser ASCII, UTF8, Unicode,
Palabra clave UTF7, BigEndianUnicode, Byte y String.

Newline Implemente este parámetro para que se admiten los caracteres de nueva línea
Tipo de datos: cuando se especifica el parámetro .
SwitchParameter

nombreCorto Implemente este parámetro para que se admiten nombres cortos cuando se
Tipo de datos: especifica el parámetro .
SwitchParameter

Width Implemente este parámetro para que el usuario pueda especificar el ancho del
Tipo de datos: dispositivo de salida.
Int32

Encapsulado Implemente este parámetro para que se admite el ajuste de texto cuando se
Tipo de datos: especifica el parámetro .
SwitchParameter

Consulte también
Parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Parámetros de propiedad
Artículo • 27/09/2021

En la tabla siguiente se enumeran los nombres recomendados y la funcionalidad de los


parámetros de propiedad.

Parámetro Funcionalidad

Recuento Implemente este parámetro para que el usuario pueda especificar el número
Tipo de datos: de objetos que se procesarán.
Int32

Descripción Implemente este parámetro para que el usuario pueda especificar una
Tipo de datos: descripción para un recurso.
cadena

From Implemente este parámetro para que el usuario pueda especificar el objeto de
Tipo de datos: referencia del que obtener información.
cadena

Id Implemente este parámetro para que el usuario pueda especificar el


Tipo de datos: identificador de un recurso.
dependiente del
recurso

Entrada Implemente este parámetro para que el usuario pueda especificar la


Tipo de datos: especificación del archivo de entrada.
cadena

Ubicación Implemente este parámetro para que el usuario pueda especificar la ubicación
Tipo de datos: del recurso.
cadena

LogName Implemente este parámetro para que el usuario pueda especificar el nombre
Tipo de datos: del archivo de registro que se va a procesar o usar.
cadena

Nombre Implemente este parámetro para que el usuario pueda especificar el nombre
Tipo de datos: del recurso.
cadena

Salida Implemente este parámetro para que el usuario pueda especificar el archivo
Tipo de datos: de salida.
cadena

Propietario Implemente este parámetro para que el usuario pueda especificar el nombre
Tipo de datos: del propietario del recurso.
cadena
Parámetro Funcionalidad

Propiedad Implemente este parámetro para que el usuario pueda especificar el nombre o
Tipo de datos: los nombres de las propiedades que se usarán.
cadena

Motivo Implemente este parámetro para que el usuario pueda especificar por qué se
Tipo de datos: invoca este cmdlet.
cadena

Regex Implemente este parámetro para que se utilicen expresiones regulares cuando
Tipo de datos: se especifique el parámetro . Cuando se especifica este parámetro, no se
SwitchParameter resuelven los caracteres comodín.

Velocidad Implemente este parámetro para que el usuario pueda especificar la velocidad
Tipo de datos: en baudios. El usuario establece este parámetro a la velocidad del recurso.
Int32

State Implemente este parámetro para que el usuario pueda especificar los nombres
Tipo de datos: de los estados, como KEYDOWN.
matriz de
palabras clave

Valor Implemente este parámetro para que el usuario pueda especificar un valor que
Tipo de datos: se va a proporcionar al cmdlet.
Objeto

Versión Implemente este parámetro para que el usuario pueda especificar la versión
Tipo de datos: de la propiedad.
cadena

Consulte también
Parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Parámetros de cantidad
Artículo • 27/09/2021

En la tabla siguiente se enumeran los nombres recomendados y la funcionalidad de los


parámetros de cantidad.

Parámetro Funcionalidad

Todo Implemente este parámetro para que indique que se debe actuar sobre todos los
Tipo de recursos en lugar de un true subconjunto predeterminado de recursos.
datos: Implemente este parámetro para false que indique un subconjunto de los
booleano recursos.

Asignación Implemente este parámetro para que el usuario pueda especificar el número de
Tipo de elementos que se asignarán.
datos: Int32

BlockCount Implemente este parámetro para que el usuario pueda especificar el recuento de
Tipo de bloques.
datos: Int64

Recuento Implemente este parámetro para que el usuario pueda especificar el recuento.
Tipo de
datos: Int64

Ámbito Implemente este parámetro para que el usuario pueda especificar el ámbito en el
Tipo de que se va a operar.
datos:
Palabra
clave

Consulte también
Parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Parámetros de recursos
Artículo • 27/09/2021

En la tabla siguiente se enumeran los nombres recomendados y la funcionalidad de los


parámetros de recursos. Para estos parámetros, los recursos podrían ser el ensamblado
que contiene la clase de cmdlet o la aplicación host que ejecuta el cmdlet.

Parámetro Funcionalidad

Aplicación Implemente este parámetro para que el usuario pueda especificar una aplicación.
Tipo de
datos:
cadena

Ensamblaje Implemente este parámetro para que el usuario pueda especificar un ensamblado.
Tipo de
datos:
cadena

Atributo Implemente este parámetro para que el usuario pueda especificar un atributo.
Tipo de
datos:
cadena

Clase Implemente este parámetro para que el usuario pueda especificar una clase .NET
Tipo de Framework Microsoft.
datos:
cadena

Clúster Implemente este parámetro para que el usuario pueda especificar un clúster.
Tipo de
datos:
cadena

Referencia Implemente este parámetro para que el usuario pueda especificar la referencia
cultural cultural en la que se va a ejecutar el cmdlet.
Tipo de
datos:
cadena

Dominio Implemente este parámetro para que el usuario pueda especificar el nombre de
Tipo de dominio.
datos:
cadena
Parámetro Funcionalidad

Unidad Implemente este parámetro para que el usuario pueda especificar un nombre de
Tipo de unidad.
datos:
cadena

Evento Implemente este parámetro para que el usuario pueda especificar un nombre de
Tipo de evento.
datos:
cadena

Interfaz Implemente este parámetro para que el usuario pueda especificar un nombre de
Tipo de interfaz de red.
datos:
cadena

IpAddress Implemente este parámetro para que el usuario pueda especificar una dirección IP.
Tipo de
datos:
cadena

Trabajo Implemente este parámetro para que el usuario pueda especificar un trabajo.
Tipo de
datos:
cadena

LiteralPath Implemente este parámetro para que el usuario pueda especificar la ruta de acceso
Tipo de a un recurso cuando no se admiten caracteres comodín. (Use el parámetro Path
datos: cuando se admiten caracteres comodín).
cadena

Mac Implemente este parámetro para que el usuario pueda especificar una dirección del
Tipo de controlador de acceso multimedia (MAC).
datos:
cadena

ParentId Implemente este parámetro para que el usuario pueda especificar el identificador
Tipo de primario.
datos:
cadena

Ruta de Implemente este parámetro para que el usuario pueda indicar las rutas de acceso a
acceso un recurso cuando se admiten caracteres comodín. (Use el parámetro LiteralPath
Tipo de cuando no se admiten caracteres comodín). Se recomienda desarrollar este
datos: parámetro para que admita la sintaxis provider:path completa que usan los
String, proveedores. También se recomienda desarrollarlo para que funcione con tantos
String[] proveedores como sea posible.
Parámetro Funcionalidad

Puerto Implemente este parámetro para que el usuario pueda especificar un valor entero
Tipo de para redes o un valor de cadena como "biztalk" para otros tipos de puerto.
datos:
Integer,
String

Impresora Implemente este parámetro para que el usuario pueda especificar la impresora que
Tipo de va a usar el cmdlet.
datos:
Integer,
String

Tamaño Implemente este parámetro para que el usuario pueda especificar un tamaño.
Tipo de
datos:
Int32

TID Implemente este parámetro para que el usuario pueda especificar un identificador
Tipo de de transacción (TID) para el cmdlet.
datos:
cadena

Tipo Implemente este parámetro para que el usuario pueda especificar el tipo de recurso
Tipo de en el que se va a operar.
datos:
cadena

URL Implemente este parámetro para que el usuario pueda especificar un localizador
Tipo de uniforme de recursos (URL).
datos:
cadena

User Implemente este parámetro para que el usuario pueda especificar su nombre o el
Tipo de nombre de otro usuario.
datos:
cadena

Consulte también
Parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Parámetros de seguridad
Artículo • 26/09/2021

En la tabla siguiente se enumeran los nombres recomendados y la funcionalidad de los


parámetros que se usan para proporcionar información de seguridad para una
operación, como los parámetros que especifican la clave de certificado y la información
de privilegios.

Parámetro Funcionalidad

ACL Implemente este parámetro para especificar el


Tipo de datos: cadena nivel de control de acceso de protección para un
catálogo o para un identificador uniforme de
recursos (URI).

Certfile Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el nombre de un archivo que
contiene uno de los siguientes elementos:
- Un certificado x.509 codificado reglas de
codificación distinguida Base64 o reglas de
codificación distinguida (DER)
- Un archivo pkcs (Public Key Cryptography
Standards) #12 que contiene al menos un
certificado y una clave

CertIssuerName Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el nombre del emisor de un
certificado o para que el usuario pueda
especificar una subcadena.

CertRequestFile Implemente este parámetro para especificar el


Tipo de datos: cadena nombre de un archivo que contiene una solicitud
de certificado PKCS #10 Base64 o DER.

CertSerialNumber Implemente este parámetro para especificar el


Tipo de datos: cadena número de serie emitido por la entidad de
certificación.

CertStoreLocation Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar la ubicación del almacén de
certificados. La ubicación suele ser una ruta de
acceso de archivo.

CertSubjectName Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el emisor de un certificado o
para que el usuario pueda especificar una
subcadena.
Parámetro Funcionalidad

CertUsage Implemente este parámetro para especificar el


Tipo de datos: cadena uso de clave o el uso mejorado de clave. La clave
se puede representar como una máscara de bits,
un bit, un identificador de objeto (OID) o una
cadena.

Credential: Implemente este parámetro para que el cmdlet


Tipo de datos: solicite automáticamente al usuario un nombre
System.Management.Automation.PSCredential de usuario o una contraseña. Se muestra un
mensaje para ambos si no se proporciona
directamente una credencial completa.

CSPName Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el nombre del proveedor de
servicios de certificado (CSP).

CSPType Implemente este parámetro para que el usuario


Tipo de datos: entero pueda especificar el tipo de CSP.

Grupo Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar una colección de entidades de
seguridad para el acceso. Para obtener más
información, vea la descripción del parámetro
Principal.

KeyAlgorithm Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el algoritmo de generación de
claves que se usará para la seguridad.

KeyContainerName Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el nombre del contenedor de
claves.

KeyLength Implemente este parámetro para que el usuario


Tipo de datos: entero pueda especificar la longitud de la clave en bits.

operación Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar una acción que se pueda
realizar en un objeto protegido.

Principal Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar una entidad de identificación
única para el acceso.

Privilegio Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el derecho que necesita un
cmdlet para realizar una operación para una
entidad determinada.
Parámetro Funcionalidad

Privilegios Implemente este parámetro para que el usuario


Tipo de datos: matriz de privilegios pueda especificar los derechos que necesita un
cmdlet para realizar su operación para una
entrada determinada.

Rol Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar un conjunto de operaciones
que puede realizar una entidad.

SaveCred Implemente este parámetro para que las


Tipo de datos: SwitchParameter credenciales guardadas previamente por el
usuario se utilicen cuando se especifique el
parámetro .

Ámbito Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar el grupo de objetos
protegidos para el cmdlet .

SID Implemente este parámetro para que el usuario


Tipo de datos: cadena pueda especificar un identificador único que
represente una entidad de seguridad.

Confianza Implemente este parámetro para que se admiten


Tipo de datos: SwitchParameter los niveles de confianza cuando se especifica el
parámetro .

TrustLevel Implemente este parámetro para que el usuario


Tipo de datos: Palabra clave pueda especificar el nivel de confianza que se
admite. Por ejemplo, los valores posibles
incluyen Internet, intranet y fulltrust.

Consulte también
Parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Alias de parámetro
Artículo • 27/09/2021

Los parámetros de cmdlet también pueden tener alias. Puede usar los alias en lugar de
los nombres de parámetro al escribir o especificar el parámetro en un comando.

Ventajas de usar alias


Agregar alias a parámetros proporciona las siguientes ventajas.

Puede proporcionar un acceso directo para que el usuario no tenga que usar el
nombre completo del parámetro cuando se llama al cmdlet. Por ejemplo, podría
usar el alias "CN" en lugar del nombre del parámetro "NombreDeEquipo".

Puede definir varios alias si desea proporcionar nombres diferentes para el mismo
parámetro. Es posible que quiera definir varios alias si tiene que trabajar con varios
grupos de usuarios que hacen referencia a los mismos datos de maneras
diferentes.

Puede proporcionar compatibilidad con versiones anteriores para los scripts


existentes si cambia el nombre de un parámetro.

Mediante el uso del atributo Alias junto con el atributo ValueFromPipelineByName,


puede definir un parámetro que permita que el cmdlet se enlace a distintos tipos
de objeto. Por ejemplo, digamos que tenía dos objetos de tipos diferentes y que el
primer objeto tenía una propiedad writer y el segundo objeto tenía una propiedad
de editor. Si el cmdlet tenía un parámetro que tenía alias de escritor y editor y el
cmdlet aceptaba la entrada de canalización basada en nombres de propiedad, el
cmdlet podría enlazarse a ambos objetos mediante los dos alias de parámetro.

Para obtener más información sobre los alias que se pueden usar con parámetros
específicos, vea Common Parameter Names.

Definir alias de parámetro


Para definir un alias para un parámetro, declare el atributo Alias, como se muestra en la
siguiente declaración de parámetro. En este ejemplo, se definen varios alias para el
mismo parámetro. (Para obtener más información,vea Cómo declarar parámetros de
cmdlet).

C#
[Alias("UN","Writer","Editor")]
[Parameter()]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Consulte también
Nombres de parámetros comunes

Cómo declarar los parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell


Nombres de parámetros comunes
Artículo • 27/09/2021

Los parámetros descritos en este tema se conocen como parámetros comunes. El


tiempo de ejecución de Windows PowerShell los agrega a los cmdlets y el cmdlet no los
puede declarar.

7 Nota

Estos parámetros también se agregan a los cmdlets del proveedor y a las funciones
que se decoran con el CmdletBinding atributo .

Parámetros comunes generales


Los parámetros siguientes se agregan a todos los cmdlets y se puede acceder a ellos
cada vez que se ejecuta el cmdlet. Estos parámetros se definen mediante la clase
System.Management.Automation.Internal.Commonparameters.

Confirm (alias: cf)


Tipo de datos: SwitchParameter

Este parámetro especifica si el cmdlet muestra un mensaje que pregunta si el usuario


está seguro de que desea continuar.

Depuración (alias: db)


Tipo de datos: SwitchParameter

Este parámetro especifica si los mensajes de depuración de nivel de programador se


pueden mostrar en la línea de comandos. Estos mensajes están diseñados para
solucionar problemas del funcionamiento del cmdlet y se generan mediante llamadas al
método System.Management.Automation.Cmdlet.WriteDebug. No es necesario localizar
los mensajes de depuración.

ErrorAction (alias: ea)


Tipo de datos: Enumeración
Este parámetro especifica qué acción debe tener lugar cuando se produce un error. Los
valores posibles para este parámetro se definen mediante la enumeración
System.Management.Automation.Actionpreference.

ErrorVariable (alias: ev)


Tipo de datos: cadena

Este parámetro especifica la variable en la que se colocarán los objetos cuando se


produzca un error. Para anexar a esta variable, use +varname en lugar de borrar y
establecer la variable.

OutBuffer (alias: ob)


Tipo de datos: Int32

Este parámetro define el número de objetos que se almacenarán en el búfer de salida


antes de que se pasen objetos por la canalización. De forma predeterminada, los
objetos se pasan inmediatamente por la canalización.

OutVariable (alias: ov)


Tipo de datos: cadena

Este parámetro especifica la variable en la que se colocarán todos los objetos de salida
generados por el cmdlet . Para anexar a esta variable, use +varname en lugar de borrar y
establecer la variable.

PipelineVariable (alias: pv)


Tipo de datos: cadena

Este parámetro almacena el valor del elemento de canalización actual como una variable
para cualquier comando con nombre a medida que fluye a través de la canalización.

Detallado (alias: vb)


Tipo de datos: SwitchParameter

Este parámetro especifica si el cmdlet escribe mensajes explicativos que se pueden


mostrar en la línea de comandos. Estos mensajes están diseñados para proporcionar
ayuda adicional al usuario y se generan mediante llamadas al método
System.Management.Automation.Cmdlet.WriteVerbose.

WarningAction (alias: wa)


Tipo de datos: Enumeración

Este parámetro especifica qué acción debe tener lugar cuando el cmdlet escribe un
mensaje de advertencia. Los valores posibles para este parámetro se definen mediante
la enumeración System.Management.Automation.Actionpreference.

WarningVariable (alias: wv)


Tipo de datos: cadena

Este parámetro especifica la variable en la que se pueden guardar los mensajes de


advertencia. Para anexar a esta variable, use +varname en lugar de borrar y establecer la
variable.

Risk-Mitigation parámetros
Los parámetros siguientes se agregan a los cmdlets que solicitan confirmación antes de
realizar su acción. Para obtener más información sobre las solicitudes de confirmación,
vea Solicitar confirmación. Estos parámetros se definen mediante la clase
System.Management.Automation.Internal.Shouldprocessparameters.

WhatIf (alias: wi)


Tipo de datos: SwitchParameter

Este parámetro especifica si el cmdlet escribe un mensaje que describe los efectos de
ejecutar el cmdlet sin realizar realmente ninguna acción.

Parámetros de transacción
El parámetro siguiente se agrega a los cmdlets que admiten transacciones. Estos
parámetros se definen mediante la clase
System.Management.Automation.Internal.Transactionparameters. La compatibilidad con
transacciones se introdujo en PowerShell 3.0 y se descontinuó en PowerShell 6.0.
UseTransaction (alias: usetx)
Tipo de datos: SwitchParameter

Este parámetro especifica si el cmdlet usará la transacción actual para realizar su acción.

Consulte también
System.Management.Automation.Internal.Commonparameters

System.Management.Automation.Internal.Shouldprocessparameters

System.Management.Automation.Internal.Transactionparameters

Escribir un cmdlet de Windows PowerShell

Windows PowerShell SDK


Conjuntos de parámetros de cmdlet
Artículo • 27/09/2021

PowerShell usa conjuntos de parámetros para permitirle escribir un único cmdlet que
puede realizar acciones diferentes para distintos escenarios. Los conjuntos de
parámetros permiten exponer distintos parámetros al usuario. Y, para devolver
información diferente en función de los parámetros especificados por el usuario.

Ejemplos de conjuntos de parámetros


Por ejemplo, el cmdlet de PowerShell devuelve información diferente en función de si el
Get-EventLog usuario especifica el parámetro List o LogName. Si se especifica el

parámetro List, el cmdlet devuelve información sobre los propios archivos de registro,
pero no la información de eventos que contienen. Si se especifica el parámetro
LogName, el cmdlet devuelve información sobre los eventos de un registro de eventos
específico. Los parámetros List y LogName identifican dos conjuntos de parámetros
independientes.

Parámetro único
Cada conjunto de parámetros debe tener un parámetro único que el tiempo de
ejecución de PowerShell usa para exponer el conjunto de parámetros adecuado. Si es
posible, el parámetro único debe ser un parámetro obligatorio. Cuando un parámetro es
obligatorio, el usuario debe especificar el parámetro y el tiempo de ejecución de
PowerShell usa ese parámetro para identificar el conjunto de parámetros. El parámetro
único no puede ser obligatorio si el cmdlet está diseñado para ejecutarse sin especificar
ningún parámetro.

Varios conjuntos de parámetros


En la ilustración siguiente, la columna izquierda muestra tres conjuntos de parámetros
válidos. El parámetro A es único para el primer conjunto de parámetros, el parámetro B
es único para el segundo conjunto de parámetros y el parámetro C es único para el
tercer conjunto de parámetros. En la columna derecha, los conjuntos de parámetros no
tienen un parámetro único.
Requisitos del conjunto de parámetros
Los siguientes requisitos se aplican a todos los conjuntos de parámetros.

Cada conjunto de parámetros debe tener al menos un parámetro único. Si es


posible, haga que este parámetro sea obligatorio.

Un conjunto de parámetros que contiene varios parámetros posicionales debe


definir posiciones únicas para cada parámetro. No hay dos parámetros
posicionales que puedan especificar la misma posición.

Solo un parámetro de un conjunto puede declarar la ValueFromPipeline palabra


clave con un valor de true . Varios parámetros pueden definir la
ValueFromPipelineByPropertyName palabra clave con un valor de true .

Si no se especifica ningún conjunto de parámetros para un parámetro, el


parámetro pertenece a todos los conjuntos de parámetros.

7 Nota

Para un cmdlet o una función, hay un límite de 32 conjuntos de parámetros.

Conjuntos de parámetros predeterminados


Cuando se definen varios conjuntos de parámetros, puede usar la palabra
DefaultParameterSetName clave del atributo Cmdlet para especificar el conjunto de
parámetros predeterminado. PowerShell usa el conjunto de parámetros predeterminado
si no puede determinar el conjunto de parámetros que se va a usar en función de la
información proporcionada por el comando. Para obtener más información sobre el
atributo cmdlet, vea Declaración de atributo de cmdlet.

Declarar conjuntos de parámetros


Para crear un conjunto de parámetros, debe especificar la palabra clave al declarar el
atributo ParameterSetName Parameter para cada parámetro del conjunto de parámetros.
Para los parámetros que pertenecen a varios conjuntos de parámetros, agregue un
atributo Parameter para cada conjunto de parámetros. Este atributo permite definir el
parámetro de forma diferente para cada conjunto de parámetros. Por ejemplo, puede
definir un parámetro como obligatorio en un conjunto y opcional en otro. Sin embargo,
cada conjunto de parámetros debe contener un parámetro único. Para obtener más
información, vea Declaración de atributo de parámetro.

En el ejemplo siguiente, el parámetro UserName es el parámetro único del conjunto de


parámetros y el parámetro ComputerName es el parámetro único Test01 del conjunto
de Test02 parámetros. El parámetro SharedParam pertenece a ambos conjuntos y es
obligatorio para el conjunto de parámetros, pero opcional para el conjunto de Test01
Test02 parámetros.

C#

[Parameter(Position = 0, Mandatory = true, ParameterSetName = "Test01")]


public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

[Parameter(Position = 0, Mandatory = true, ParameterSetName = "Test02")]


public string ComputerName
{
get { return computerName; }
set { computerName = value; }
}
private string computerName;

[Parameter(Mandatory= true, ParameterSetName = "Test01")]


[Parameter(ParameterSetName = "Test02")]
public string SharedParam
{
get { return sharedParam; }
set { sharedParam = value; }
}
private string sharedParam;
Parámetros dinámicos del cmdlet
Artículo • 27/09/2021

Los cmdlets pueden definir parámetros que están disponibles para el usuario en
condiciones especiales, como cuando el argumento de otro parámetro es un valor
específico. Estos parámetros se agregan en tiempo de ejecución y se conocen como
parámetros dinámicos porque solo se agregan cuando es necesario. Por ejemplo, puede
diseñar un cmdlet que agrega varios parámetros solo cuando se especifica un
parámetro switch específico.

7 Nota

Los proveedores y las funciones de PowerShell también pueden definir parámetros


dinámicos.

Parámetros dinámicos en cmdlets de


PowerShell
PowerShell usa parámetros dinámicos en varios de sus cmdlets de proveedor. Por
ejemplo, los cmdlets y agregan un Get-Item Get-ChildItem parámetro CodeSigningCert
en tiempo de ejecución cuando el parámetro Path especifica la ruta de acceso del
proveedor de certificados. Si el parámetro Path especifica una ruta de acceso para otro
proveedor, el parámetro CodeSigningCert no está disponible.

En los ejemplos siguientes se muestra cómo se agrega el parámetro CodeSigningCert


en tiempo de ejecución cuando Get-Item se ejecuta .

En este ejemplo, el tiempo de ejecución de PowerShell ha agregado el parámetro y el


cmdlet es correcto.

PowerShell

Get-Item -Path cert:\CurrentUser -CodeSigningCert

Output

Location : CurrentUser
StoreNames : {SmartCardRoot, UserDS, AuthRoot, CA...}
En este ejemplo, se especifica una unidad FileSystem y se devuelve un error. El mensaje
de error indica que no se encuentra el parámetro CodeSigningCert.

PowerShell

Get-Item -Path C:\ -CodeSigningCert

Output

Get-Item : A parameter cannot be found that matches parameter name


'codesigningcert'.
At line:1 char:37
+ get-item -path C:\ -codesigningcert <<<<
--------
CategoryInfo : InvalidArgument: (:) [Get-Item],
ParameterBindingException
FullyQualifiedErrorId :
NamedParameterNotFound,Microsoft.PowerShell.Commands.GetItemCommand

Compatibilidad con parámetros dinámicos


Para admitir parámetros dinámicos, se deben incluir los siguientes elementos en el
código del cmdlet.

Interfaz
System.Management.Automation.IDynamicParameters. Esta interfaz proporciona el
método que recupera los parámetros dinámicos.

Por ejemplo:

public class SendGreetingCommand : Cmdlet, IDynamicParameters

Método
System.Management.Automation.IDynamicParameters.GetDynamicParameters. Este
método recupera el objeto que contiene las definiciones de parámetros dinámicos.

Por ejemplo:

C#

public object GetDynamicParameters()


{
if (employee)
{
context= new SendGreetingCommandDynamicParameters();
return context;
}
return null;
}
private SendGreetingCommandDynamicParameters context;

Clase
Clase que define los parámetros dinámicos que se van a agregar. Esta clase debe incluir
un atributo Parameter para cada parámetro y cualquier atributo Alias y Validation
opcional que necesite el cmdlet.

Por ejemplo:

C#

public class SendGreetingCommandDynamicParameters


{
[Parameter]
[ValidateSet ("Marketing", "Sales", "Development")]
public string Department
{
get { return department; }
set { department = value; }
}
private string department;
}

Para obtener un ejemplo completo de un cmdlet que admite parámetros dinámicos, vea
Cómo declarar parámetros dinámicos.

Consulte también
System.Management.Automation.IDynamicParameters

System.Management.Automation.IDynamicParameters.GetDynamicParameters

Cómo declarar los parámetros dinámicos

Escribir un cmdlet de Windows PowerShell


Compatibilidad con caracteres comodín
en los parámetros del cmdlet
Artículo • 25/09/2021

A menudo, tendrá que diseñar un cmdlet para que se ejecute en un grupo de recursos
en lugar de en un único recurso. Por ejemplo, es posible que un cmdlet tenga que
buscar todos los archivos de un almacén de datos que tengan el mismo nombre o
extensión. Debe proporcionar compatibilidad con caracteres comodín al diseñar un
cmdlet que se ejecutará en un grupo de recursos.

7 Nota

El uso de caracteres comodín se conoce a veces como globbing.

Windows PowerShell Cmdlets que usan


caracteres comodín
Muchos cmdlets Windows PowerShell admiten caracteres comodín para sus valores de
parámetro. Por ejemplo, casi todos los cmdlets que tienen un Name parámetro o Path
admiten caracteres comodín para estos parámetros. (Aunque la mayoría de los cmdlets
que tienen Path un parámetro también tienen un parámetro que no admite caracteres
LiteralPath comodín). El comando siguiente muestra cómo se usa un carácter comodín

para devolver todos los cmdlets de la sesión actual cuyo nombre contiene el verbo Get.

Get-Command get-*

Caracteres comodín admitidos


Windows PowerShell admite los siguientes caracteres comodín.

Wildcard Descripción Ejemplo Coincide No


(Carácter coincide
comodín)

* Coincide con cero o más caracteres, a* A, ag,


empezando en la posición especificada Apple

? Coincide con cualquier carácter en la ?n un, en, Corrió


posición especificada. en
Wildcard Descripción Ejemplo Coincide No
(Carácter coincide
comodín)

[] Coincide con un intervalo de caracteres [a- book, nook,


l]ook cook, took
look

[] Coincide con los caracteres especificados [bn]ook book, cook,


nook look

Al diseñar cmdlets que admiten caracteres comodín, permita combinaciones de


caracteres comodín. Por ejemplo, el comando siguiente usa el cmdlet para recuperar
todos los archivos .txt que se encuentran en la carpeta c:\Techdocs y que comienzan por
las letras Get-ChildItem "a" a "l".

Get-ChildItem c:\techdocs\[a-l]\*.txt

El comando anterior usa el carácter comodín de intervalo para especificar que el


nombre de archivo debe comenzar con los caracteres "a" a "l" y usa el carácter comodín
como marcador de posición para cualquier carácter entre la primera letra del nombre de
archivo y la [a-l] * extensión .txt.

En el ejemplo siguiente se usa un patrón de caracteres comodín de intervalo que


excluye la letra "d", pero incluye todas las demás letras de "a" a "f".

Get-ChildItem c:\techdocs\[a-cef]\*.txt

Control de caracteres literales en patrones de


caracteres comodín
Si el patrón de caracteres comodín que especifique contiene caracteres literales que no
deben interpretarse como caracteres comodín, use el carácter de carácter comodín ( ` )
como carácter de escape. Al especificar caracteres literales en la API de PowerShell, use
un solo carácter de backtick. Al especificar caracteres literales en el símbolo del sistema
de PowerShell, use dos signos de invertible.

Por ejemplo, el siguiente patrón contiene dos corchetes que se deben tomar
literalmente.

Cuando se usa en la API de PowerShell, use:

"John Smith ` [*']"


Cuando se usa desde el símbolo del sistema de PowerShell:

"John Smith ` ` [* ` ']"

Este patrón coincide con "John Smith [Marketing]" o "John Smith [Desarrollo]". Por
ejemplo:

PS> "John Smith [Marketing]" -like "John Smith ``[*``]"


True

PS> "John Smith [Development]" -like "John Smith ``[*``]"


True

Salida del cmdlet y caracteres comodín


Cuando los parámetros de cmdlet admiten caracteres comodín, la operación
normalmente genera una salida de matriz. En ocasiones, no tiene sentido admitir una
salida de matriz porque el usuario podría usar solo un elemento. Por ejemplo, el Set-
Location cmdlet no admite la salida de la matriz porque el usuario establece solo una
ubicación. En este caso, el cmdlet todavía admite caracteres comodín, pero fuerza la
resolución a una sola ubicación.

Vea también
Escribir un cmdlet de Windows PowerShell

WildcardPattern (clase)
Validación de la entrada de parámetros
Artículo • 24/09/2021

PowerShell puede validar los argumentos pasados a los parámetros del cmdlet de varias
maneras. PowerShell puede validar la longitud, el intervalo y el patrón de los caracteres
del argumento. Puede validar el número de argumentos disponibles (el recuento). Estas
reglas de validación se definen mediante atributos de validación que se declaran con el
atributo Parameter en las propiedades públicas de la clase de cmdlet.

Para validar un argumento de parámetro, el tiempo de ejecución de PowerShell usa la


información proporcionada por los atributos de validación para confirmar el valor del
parámetro antes de ejecutar el cmdlet. Si la entrada del parámetro no es válida, el
usuario recibe un mensaje de error. Cada parámetro de validación define una regla de
validación que PowerShell aplica.

PowerShell aplica las reglas de validación en función de los atributos siguientes.

ValidateCount
Especifica el número mínimo y máximo de argumentos que un parámetro puede
aceptar. Para obtener más información, vea ValidateCount Attribute Declaration.

ValidateLength
Especifica el número mínimo y máximo de caracteres del argumento de parámetro. Para
obtener más información, vea ValidateLength Attribute Declaration.

ValidatePattern
Especifica una expresión regular que valida el argumento del parámetro. Para obtener
más información, vea ValidatePattern Attribute Declaration.

ValidateRange
Especifica los valores mínimo y máximo del argumento de parámetro. Para obtener más
información, vea Declaración de atributo ValidateRange.

ValidateScript
Especifica los valores válidos para el argumento de parámetro. Para obtener más
información, vea ValidateScript Attribute Declaration.

ValidateSet
Especifica los valores válidos para el argumento de parámetro. Para obtener más
información, vea ValidateSet Attribute Declaration.

Consulte también
Cómo validar la entrada de parámetros

Escribir un cmdlet de Windows PowerShell


Parámetros de filtros de entrada
Artículo • 27/09/2021

Un cmdlet puede definir Filter los parámetros , y que Include Exclude filtran el
conjunto de objetos de entrada a los que afecta el cmdlet.

Normalmente, el conjunto de objetos de entrada se especifica mediante un InputObject


parámetro Path , o Name . Por ejemplo, un cmdlet puede tener un parámetro que acepta
varias rutas de acceso mediante caracteres comodín y cada ruta de acceso apunta a
Path un objeto de entrada. Los parámetros , y se usan juntos para calificar aún más las
rutas de acceso en las que funciona el Filter cmdlet cada vez que se Include Exclude
invoca.

Incluir y excluir parámetros


Los parámetros y identifican los objetos que se incluyen o excluyen del Include
conjunto de objetos de entrada Exclude pasados al cmdlet . Use estos parámetros
cuando el filtro se pueda expresar en el lenguaje de caracteres comodín estándar. (Para
obtener más información sobre los caracteres comodín, vea Compatibilidad con
caracteres comodín en parámetros de cmdlet). El Include parámetro incluye todos los
objetos cuyos nombres coinciden con el filtro de inclusión. El Exclude parámetro
excluye todos los objetos cuyos nombres coinciden con el filtro.

Parámetro filter
El Filter parámetro especifica un filtro que no se expresa en el lenguaje de caracteres
comodín estándar. Por ejemplo, Active Directory interfaces de servicio (ADSI) o filtros
SQL pueden pasarse al cmdlet a través de su Filter parámetro . En los cmdlets
proporcionados por Windows PowerShell, estos filtros los especifican los proveedores
de Windows PowerShell que usan el cmdlet para acceder a un almacén de datos.
Normalmente, cada proveedor define su propio filtro.

Filtrado si no se especifica ningún conjunto de


objetos de entrada
Si no se especifica ningún conjunto de objetos de entrada, esto suele significar filtrar
por todos los objetos. Para obtener más información,vea Get-Process.
Vea también
Escribir un cmdlet de Windows PowerShell
Atributos del cmdlet
Artículo • 27/09/2021

Windows PowerShell define varios atributos que puede usar para agregar funcionalidad
común a los cmdlets sin implementar esa funcionalidad dentro de su propio código.
Esto incluye el atributo Cmdlet que identifica una clase de Microsoft .NET Framework
como una clase de cmdlet, el atributo OutputType que especifica los tipos .NET
Framework devueltos por el cmdlet, el atributo Parameter que identifica las propiedades
públicas como parámetros del cmdlet y mucho más.

En esta sección
Atributos en el código de cmdlet Describe la ventaja de usar atributos en el código del
cmdlet.

Tipos de atributo Describe los distintos atributos que pueden decorar una clase de
cmdlet.

Declaración de atributo de alias Describe cómo definir alias para un nombre de


parámetro de cmdlet.

Declaración de atributo de cmdlet Describe cómo definir una clase .NET Framework
como un cmdlet.

Declaración de atributo de credencial Describe cómo agregar compatibilidad para


convertir la entrada de cadena en un objeto
System.Management.Automation.PSCredential.

Declaración del atributo OutputType Describe cómo especificar los tipos de .NET
Framework devueltos por el cmdlet .

Declaración de atributo de parámetro Describe cómo definir los parámetros de un


cmdlet.

Declaración de atributo ValidateCount Describe cómo definir cuántos argumentos se


permiten para un parámetro.

Declaración de atributo ValidateLength Describe cómo definir la longitud (en caracteres)


de un argumento de parámetro.

Declaración de atributo ValidatePattern Describe cómo definir los patrones válidos para
un argumento de parámetro.
Declaración de atributo ValidateRange Describe cómo definir el intervalo válido para un
argumento de parámetro.

Declaración de atributo ValidateScript Describe cómo definir los valores posibles para un
argumento de parámetro.

Declaración de atributo ValidateSet Describe cómo definir los valores posibles para un
argumento de parámetro.

Referencia
Escribir un cmdlet de Windows PowerShell
Atributos en el código del cmdlet
Artículo • 27/09/2021

Para usar la funcionalidad común proporcionada por Windows PowerShell, las clases y
las propiedades públicas definidas en el código del cmdlet se decoran con atributos. Por
ejemplo, la siguiente definición de clase usa el atributo Cmdlet para identificar la clase
.NET Framework microsoft en la que se implementa el cmdlet Get-Proc. (Este cmdlet se
usa como ejemplo en este documento y es similar al cmdlet proporcionado Get-Process
por Windows PowerShell).

C#

[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet

Estos atributos se consideran metadatos porque su implementación es independiente


de la implementación del código del cmdlet. Cuando el Windows PowerShell ejecución
ejecuta el cmdlet , reconoce los atributos y, a continuación, realiza la acción adecuada
para cada atributo.

Aunque es posible que quiera implementar su propia versión de la funcionalidad


proporcionada por estos atributos, un buen diseño de cmdlet usa estas funcionalidades
comunes.

Para obtener más información sobre los distintos atributos que se pueden declarar en
los cmdlets, vea Tipos de atributo.

Consulte también
Tipos de atributo

Escribir un cmdlet de Windows PowerShell


Tipos de atributo
Artículo • 24/09/2021

Los atributos de cmdlet se pueden agrupar por funcionalidad. En las secciones


siguientes se describen los atributos disponibles y se describe lo que hace el tiempo de
ejecución cuando se invoca el atributo.

Atributos del cmdlet

Cmdlet
Identifica una clase .NET Framework como un cmdlet. Este es el atributo base necesario.
Para obtener más información, vea Declaración de atributo de cmdlet.

Atributos de parámetro

Parámetro
Identifica una propiedad pública en la clase de cmdlet como un parámetro de cmdlet.
Para obtener más información, vea Declaración de atributo de parámetro.

Alias
Especifica uno o varios alias para un parámetro. Para obtener más información, vea
Declaración de atributo de alias.

Atributos de validación de argumentos

ValidateCount
Especifica el número mínimo y máximo de argumentos permitidos para un parámetro
de cmdlet. Para obtener más información, vea ValidateCount Attribute Declaration.

ValidateLength
Especifica un número mínimo y máximo de caracteres para un argumento de parámetro
de cmdlet. Para obtener más información, vea ValidateLength Attribute Declaration.
ValidatePattern
Especifica un patrón de expresión regular que debe coincidir con el argumento del
parámetro de cmdlet. Para obtener más información, vea ValidatePattern Attribute
Declaration.

ValidateRange
Especifica los valores mínimo y máximo para un argumento de parámetro de cmdlet.
Para obtener más información, vea Declaración de atributo ValidateRange.

ValidateSet
Especifica un conjunto de valores válidos para el argumento de parámetro del cmdlet.
Para obtener más información, vea ValidateSet Attribute Declaration.

Consulte también
Windows PowerShell SDK
Declaración de atributo de alias
Artículo • 27/09/2021

El atributo Alias permite al usuario especificar nombres diferentes para un cmdlet o un


parámetro de cmdlet. Los alias se pueden usar para proporcionar accesos directos para
un nombre de parámetro o pueden proporcionar nombres diferentes que son
adecuados para distintos escenarios.

Sintaxis
C#

[Alias(aliasNames)]

Parámetros
aliasNames (String[]) Obligatorio. Especifica un conjunto de nombres de alias separados

por comas para el parámetro de cmdlet.

Comentarios
La clase System.Management.Automation.Aliasattribute define el atributo Alias.

Alias de cmdlet
El atributo Alias se usa con la declaración de cmdlet. Para obtener más
información sobre cómo declarar estos atributos, vea Alias de cmdlet.
Cada nombre de alias de parámetro debe ser único. Windows PowerShell no
comprueba si hay nombres de alias duplicados.

Alias de parámetro
El atributo Alias se usa con el atributo Parameter al especificar un parámetro de
cmdlet. Para obtener más información sobre cómo declarar estos atributos, vea
How to Declare Cmdlet Parameters.
Cada nombre de alias de parámetro debe ser único dentro de un cmdlet. Windows
PowerShell no comprueba si hay nombres de alias duplicados.
El atributo Alias se usa una vez para cada parámetro de un cmdlet.
Consulte también
Alias del cmdlet

Alias de parámetro

Escribir un cmdlet de Windows PowerShell


Declaración de atributo del cmdlet
Artículo • 27/09/2021

El atributo Cmdlet identifica una clase .NET Framework microsoft como un cmdlet y
especifica el verbo y el nombre que se usan para invocar el cmdlet.

Sintaxis
C#

[Cmdlet("verbName", "nounName")]
[Cmdlet("verbName", "nounName", Named Parameters...)]

Parámetros

VerbName (System.String) Requerido. Especifica el verbo del cmdlet. Este verbo especifica
la acción realizada por el cmdlet . Para obtener más información sobre los verbos de
cmdlet aprobados, vea Cmdlet Verb Names and Required Development Guidelines.

NounName (System.String) Requerido. Especifica el nombre del cmdlet. Este nombre


especifica el recurso sobre el que actúa el cmdlet. Para obtener más información sobre
los nombres de cmdlet, vea Declaración de cmdlet e Instrucciones de desarrollo muy
recomendables.

SupportsShouldProcess (System.Boolean) Parámetro con nombre opcional. True indica

que el cmdlet admite llamadas al método


System.Management.Automation.Cmdlet.ShouldProcess, que proporciona al cmdlet una
manera de preguntar al usuario antes de realizar una acción que cambie el sistema.
False , el valor predeterminado, indica que el cmdlet no admite llamadas al método

System.Management.Automation.Cmdlet.ShouldProcess. Para obtener más información


sobre las solicitudes de confirmación, vea Solicitar confirmación.

ConfirmImpact (System.Management.Automation.Confirmimpact) Parámetro con

nombre opcional. Especifica cuándo debe confirmarse la acción del cmdlet mediante
una llamada al método System.Management.Automation.Cmdlet.ShouldProcess. Solo se
llamará a System.Management.Automation.Cmdlet.ShouldProcess cuando el valor
ConfirmImpact del cmdlet (de forma predeterminada, Medium) sea igual o mayor que el
valor de la $ConfirmPreference variable. Este parámetro solo se debe especificar cuando
SupportsShouldProcess se especifica el parámetro .
DefaultParameterSetName (System.String) Parámetro con nombre opcional. Especifica el

conjunto de parámetros predeterminado que Windows PowerShell tiempo de ejecución


intenta usar cuando no puede determinar qué conjunto de parámetros usar. Tenga en
cuenta que esta situación se puede eliminar haciendo que el parámetro único de cada
conjunto de parámetros sea un parámetro obligatorio.

Hay un caso en el que Windows PowerShell puede usar el conjunto de parámetros


predeterminado incluso si se especifica un nombre de conjunto de parámetros
predeterminado. El Windows PowerShell de ejecución no puede distinguir entre
conjuntos de parámetros basados únicamente en el tipo de objeto. Por ejemplo, si tiene
un conjunto de parámetros que toma una cadena como ruta de acceso de archivo y
otro conjunto que toma directamente un objeto FileInfo, Windows PowerShell no puede
determinar qué conjunto de parámetros usar en función de los valores pasados al
cmdlet ni usa el conjunto de parámetros predeterminado. En este caso, incluso si
especifica un nombre de conjunto de parámetros predeterminado, Windows PowerShell
un mensaje de error ambiguo del conjunto de parámetros.

SupportsTransactions (System.Boolean) Parámetro con nombre opcional. True indica

que el cmdlet se puede usar dentro de una transacción. Cuando True se especifica , el
entorno Windows PowerShell tiempo de ejecución agrega el parámetro a la lista de
parámetros del UseTransaction cmdlet. False , el valor predeterminado, indica que el
cmdlet no se puede usar dentro de una transacción.

Comentarios
Juntos, el verbo y el sustantivo se usan para identificar el cmdlet registrado e
invocar el cmdlet dentro de un script.

Cuando se invoca el cmdlet desde la Windows PowerShell, el comando se parece


al siguiente comando:

VerbName-NounName

Todos los cmdlets que cambian recursos fuera de Windows PowerShell deben
incluir la palabra clave cuando se declara el atributo Cmdlet, lo que permite al
cmdlet llamar al método SupportsShouldProcess
System.Management.Automation.Cmdlet.ShouldProcess antes de que el cmdlet
realice su acción. Si la llamada a
System.Management.Automation.Cmdlet.ShouldProcess devuelve false , no se
debe realizar la acción. Para obtener más información sobre las solicitudes de
confirmación generadas por la llamada
System.Management.Automation.Cmdlet.ShouldProcess, vea Solicitar
confirmación.

Los parámetros de cmdlet y solo están disponibles para los cmdlets que admiten
llamadas Confirm WhatIf System.Management.Automation.Cmdlet.ShouldProcess.

Ejemplo
La siguiente definición de clase usa el atributo Cmdlet para identificar la clase .NET
Framework para un cmdlet Get-Proc que recupera información sobre los procesos que
se ejecutan en el equipo local.

C#

[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet

Para obtener más información sobre el cmdlet Get-Proc, vea GetProc Tutorial.

Vea también
Escribir un cmdlet de Windows PowerShell
Declaración de atributo de credenciales
Artículo • 27/09/2021

El atributo Credential es un atributo opcional que se puede usar con parámetros de


credencial de tipo System.Management.Automation.PSCredential para que también se
pueda pasar una cadena como argumento al parámetro . Cuando este atributo se
agrega a una declaración de parámetro, Windows PowerShell convierte la entrada de
cadena en un objeto System.Management.Automation.PSCredential. Por ejemplo, el
cmdlet Get-Credential usa este atributo para Windows PowerShell generar el objeto
System.Management.Automation.PSCredential devuelto por el cmdlet.

Sintaxis
C#

[Credential]

Comentarios
Normalmente, los parámetros de tipo
System.Management.Automation.PSCredential usan este atributo para que
también se pueda pasar una cadena como argumento al parámetro . Cuando se
pasa un objeto System.Management.Automation.PSCredential al parámetro ,
Windows PowerShell no hace nada.

Al crear el objeto System.Management.Automation.PSCredential, Windows


PowerShell el host actual para mostrar las solicitudes adecuadas al usuario. Por
ejemplo, el host predeterminado muestra un mensaje para un nombre de usuario y
una contraseña cuando se usa este atributo. Sin embargo, si se usa un host
personalizado que define un símbolo del sistema diferente, se mostrará ese
mensaje.

Este atributo se usa con el atributo Parameter. Para obtener más información sobre
ese atributo, vea Declaración de atributo de parámetro.

La clase System.Management.Automation.Credentialattribute define el atributo de


credencial.

Consulte también
Alias de parámetro

Declaración de atributo de parámetro

Escribir un cmdlet de Windows PowerShell


Declaración de atributo OutputType
Artículo • 27/09/2021

El OutputType atributo identifica los tipos .NET Framework devueltos por un cmdlet, una
función o un script.

Sintaxis
C#

[OutputType(params string[] type)]


[OutputType(params Type[] type)]
[OutputType(params string[] type, Named Parameters...)]
[OutputType(params Type[] type, Named Parameters...)]

Parámetros

Escriba ( string[] o Type[] ) Requerido. Especifica los tipos devueltos por la función de
cmdlet o el script.

ParameterSetName (string[]) Opcional. Especifica los conjuntos de parámetros que


devuelven los tipos especificados en el type parámetro .

providerCmdlet Opcional. Especifica el cmdlet del proveedor que devuelve los tipos
especificados en el type parámetro .

Vea también
Escribir un cmdlet de Windows PowerShell
Declaración de atributo de parámetro
Artículo • 27/09/2021

El atributo Parameter identifica una propiedad pública de la clase de cmdlet como un


parámetro de cmdlet.

Sintaxis
C#

[Parameter()]
[Parameter(Named Parameters...)]

Parámetros

Mandatory (System.Boolean) Parámetro con nombre opcional. True indica que se


requiere el parámetro de cmdlet. Si no se proporciona un parámetro necesario cuando
se invoca el cmdlet, Windows PowerShell solicita al usuario un valor de parámetro. El
valor predeterminado es false .

ParameterSetName (System.String) Parámetro con nombre opcional. Especifica el

conjunto de parámetros al que pertenece este parámetro de cmdlet. Si no se especifica


ningún conjunto de parámetros, el parámetro pertenece a todos los conjuntos de
parámetros.

Position (System.Int32) Parámetro con nombre opcional. Especifica la posición del


parámetro dentro de un Windows PowerShell comando.

ValueFromPipeline (System.Boolean) Parámetro con nombre opcional. True indica que


el parámetro de cmdlet toma su valor de un objeto de canalización. Especifique esta
palabra clave si el cmdlet tiene acceso al objeto completo, no solo a una propiedad del
objeto. El valor predeterminado es false .

ValueFromPipelineByPropertyName (System.Boolean) Parámetro con nombre opcional.

True indica que el parámetro de cmdlet toma su valor de una propiedad de un objeto
de canalización que tiene el mismo nombre o el mismo alias que este parámetro. Por
ejemplo, si el cmdlet tiene un parámetro y el objeto de canalización también tiene una
propiedad , el valor de la propiedad se asigna al Name Name parámetro del Name Name
cmdlet. El valor predeterminado es false .
ValueFromRemainingArguments (System.Boolean) Parámetro con nombre opcional. True

indica que el parámetro del cmdlet acepta todos los argumentos restantes que se pasan
al cmdlet. El valor predeterminado es false .

HelpMessage Parámetro con nombre opcional. Especifica una breve descripción del
parámetro. Windows PowerShell muestra este mensaje cuando se ejecuta un cmdlet y
no se especifica un parámetro obligatorio.

HelpMessageBaseName Parámetro con nombre opcional. Especifica la ubicación donde


residen los identificadores de recursos. Por ejemplo, este parámetro podría especificar
un ensamblado de recursos que contenga los mensajes de Ayuda que desea encontrar.

HelpMessageResourceId Parámetro con nombre opcional. Especifica el identificador de

recurso para un mensaje de Ayuda.

Comentarios
Para obtener más información sobre cómo declarar este atributo, vea How to
Declare Cmdlet Parameters.

Un cmdlet puede tener cualquier número de parámetros. Sin embargo, para una
mejor experiencia del usuario, limite el número de parámetros.

Los parámetros deben declararse en propiedades o campos no estáticos públicos.


Los parámetros se deben declarar en las propiedades. La propiedad debe tener un
accessor de conjunto público y, si se especifica la palabra clave o , la propiedad
debe tener un ValueFromPipeline ValueFromPipelineByPropertyName accessor get
público.

Al especificar parámetros posicionales, limite el número de parámetros


posicionales de un conjunto de parámetros a menos de cinco. Además, los
parámetros posicionales no tienen que ser contiguos. Las posiciones 5, 100 y 250
funcionan igual que las posiciones 0, 1 y 2.

Cuando no se especifica la palabra clave , se debe hacer referencia al Position


parámetro del cmdlet por su nombre.

Cuando use conjuntos de parámetros, tenga en cuenta lo siguiente:

Cada conjunto de parámetros debe tener al menos un parámetro único. Un


buen diseño de cmdlet indica que este parámetro único también debe ser
obligatorio si es posible. Si el cmdlet está diseñado para ejecutarse sin
parámetros, el parámetro único no puede ser obligatorio.
Ningún conjunto de parámetros debe contener más de un parámetro posicional
con la misma posición.

Solo un parámetro de un conjunto de parámetros debe declarar


ValueFromPipeline = true .

Varios parámetros pueden definir ValueFromPipelineByPropertyName = true .

Para obtener más información sobre las directrices para los nombres de
parámetro, vea Cmdlet Parameter Names.

La clase System.Management.Automation.Parameterattribute define el atributo de


parámetro.

Consulte también
System.Management.Automation.Parameterattribute

Nombres de parámetros de cmdlet

Escribir un cmdlet de Windows PowerShell


Declaración de atributo ValidateCount
Artículo • 25/09/2021

El atributo ValidateCount especifica el número mínimo y máximo de argumentos


permitidos para un parámetro de cmdlet.

Sintaxis
C#

[ValidateCount(int minLength, int maxlength)]

Parámetros

MinLength (System.Int32) Requerido. Especifica el número mínimo de argumentos.

MaxLength (System.Int32) Requerido. Especifica el número máximo de argumentos.

Comentarios
Para obtener más información sobre cómo declarar este atributo, vea How to
Validate an Argument Count.
Cuando no se invoca este atributo, el parámetro de cmdlet correspondiente puede
tener cualquier número de argumentos.
El Windows PowerShell tiempo de ejecución genera un error en las condiciones
siguientes:
Los MinLength parámetros de atributo y no son del tipo MaxLength
System.Int32.
El valor del parámetro MaxLength de atributo es menor que el valor del
parámetro de MinLength atributo.
La clase System.Management.Automation.ValidateCountAttribute define el atributo
ValidateCount.

Consulte también
System.Management.Automation.ValidateCountAttribute

Cómo validar un recuento de argumentos


Escribir un cmdlet de Windows PowerShell
Declaración de atributo ValidateLength
Artículo • 24/09/2021

El atributo ValidateLength especifica el número mínimo y máximo de caracteres para un


argumento de parámetro de cmdlet. Este atributo también se puede usar en Windows
PowerShell funciones.

Sintaxis
C#

[ValidateLength(int minLength, int maxlength)]

Parámetros
MinLength (System.Int32) Requerido. Especifica el número mínimo de caracteres

permitido.

MaxLength (System.Int32) Requerido. Especifica el número máximo de caracteres


permitidos.

Comentarios
Para obtener más información sobre cómo declarar este atributo, vea How to
Declare Input Validation Rules.

Cuando no se usa este atributo, el argumento de parámetro correspondiente


puede ser de cualquier longitud.

El Windows PowerShell de ejecución genera un error en las condiciones siguientes:

Cuando el valor del parámetro MaxLength de atributo es menor que el valor del
parámetro de MinLength atributo.

Cuando el MaxLength parámetro de atributo se establece en 0.

Cuando el argumento no es una cadena.

El atributo ValidateLength se define mediante la clase


System.Management.Automation.Validatelengthattribute.
Consulte también
System.Management.Automation.Validatelengthattribute

Escribir un cmdlet de Windows PowerShell


Declaración de atributo ValidatePattern
Artículo • 25/09/2021

El atributo ValidatePattern especifica un patrón de expresión regular que valida el


argumento de un parámetro de cmdlet. Este atributo también se puede usar en
Windows PowerShell funciones.

Cuando se invoca ValidatePattern dentro de un cmdlet, el runtime de Windows


PowerShell convierte el argumento del parámetro de cmdlet en una cadena y, a
continuación, compara esa cadena con el patrón proporcionado por el atributo
ValidatePattern. El cmdlet solo se ejecuta si la representación de cadena convertida del
argumento y el patrón proporcionado coinciden. Si no coinciden, el tiempo de ejecución
de Windows PowerShell genera un error.

Sintaxis
C#

[ValidatePattern(string regexString)]
[ValidatePattern(string regexString, Named Parameters)]

Parámetros
RegexString (System.String) Requerido. Especifica una expresión regular que valida el

argumento del parámetro.

Options (System.Text.Regularexpressions.Regexoptions) Parámetro con nombre


opcional. Especifica una combinación bit a bit de marcas
System.Text.Regularexpressions.Regexoptions que especifican opciones de expresión
regular.

Comentarios
Este atributo solo se puede usar una vez por parámetro.

Puede usar el Option parámetro del atributo para definir aún más el patrón. Por
ejemplo, puede hacer que el patrón distingue mayúsculas de minúsculas.

Si este atributo se aplica a una colección, cada elemento de la colección debe


coincidir con el patrón .
El atributo ValidatePattern se define mediante la clase
System.Management.Automation.Validatepatternattribute.

Consulte también
System.Management.Automation.Validatepatternattribute

Escribir un cmdlet de Windows PowerShell


Declaración de atributo ValidateRange
Artículo • 25/09/2021

El atributo ValidateRange especifica los valores mínimo y máximo (el intervalo) para el
argumento de parámetro del cmdlet. Este atributo también se puede usar en Windows
PowerShell funciones.

Sintaxis
C#

[ValidateRange(object minRange, object maxRange)]

Parámetros
MinRange (System.Object) Requerido. Especifica el valor mínimo permitido.

MaxRange (System.Object) Requerido. Especifica el valor máximo permitido.

Comentarios
El Windows PowerShell tiempo de ejecución produce un error de construcción
cuando el valor del parámetro es mayor que MinRange el valor del MaxRange
parámetro.

El Windows PowerShell de ejecución genera un error de validación en las


condiciones siguientes:

Cuando el valor del argumento es menor que el MinRange límite o mayor que el
MaxRange límite.

Cuando el argumento no es del mismo tipo que los MinRange parámetros y


MaxRange .

El atributo ValidateRange se define mediante la clase


System.Management.Automation.Validaterangeattribute.

Consulte también
System.Management.Automation.Validaterangeattribute

Escribir un cmdlet de Windows PowerShell


Declaración de atributo ValidateScript
Artículo • 01/03/2022

El ValidateScript atributo especifica un script que se usa para validar un parámetro o


un valor de variable. PowerShell canaliza el valor al script y genera un error si el script
$false devuelve o si el script produce una excepción.

Cuando se usa el ValidateScript atributo , el valor que se está validando se asigna a la


$_ variable . Puede usar la $_ variable para hacer referencia al valor del script.

Sintaxis
C#

[ValidateScriptAttribute(ScriptBlock scriptBlock)]

Parámetros
scriptBlock - (System.Management.Automation.ScriptBlock) Requerido. Bloque de

script utilizado para validar la entrada.


ErrorMessage - Opcional: el elemento que se valida y el bloque de script de

validación se pasan como el primer y segundo argumentos de formato.

Comentarios
Este atributo solo se puede usar una vez por parámetro.
Si este atributo se aplica a una colección, cada elemento de la colección debe
coincidir con el patrón .
La clase System.Management.Automation.ValidateScriptAttribute define el atributo
ValidateScript.

Consulte también
System.Management.Automation.ValidateScriptAttribute

Escribir un cmdlet de Windows PowerShell


Declaración de atributo ValidateSet
Artículo • 27/09/2021

El atributo ValidateSetAttribute especifica un conjunto de valores posibles para un


argumento de parámetro de cmdlet. Este atributo también se puede usar en Windows
PowerShell funciones.

Cuando se especifica este atributo, Windows PowerShell tiempo de ejecución determina


si el argumento proporcionado para el parámetro de cmdlet coincide con un elemento
del conjunto de elementos proporcionado. El cmdlet solo se ejecuta si el argumento de
parámetro coincide con un elemento del conjunto. Si no se encuentra ninguna
coincidencia, el tiempo de ejecución de Windows PowerShell genera un error.

Sintaxis
C#

[ValidateSetAttribute(params string[] validValues)]


[ValidateSetAttribute(params string[] validValues, Named Parameters)]

Parámetros
ValidValues (System.String) Requerido. Especifica los valores de elemento de parámetro

válidos. En el ejemplo siguiente se muestra cómo especificar un elemento o varios


elementos.

C#

[ValidateSetAttribute("Steve")]
[ValidateSetAttribute("Steve","Mary")]

IgnoreCase (System.Boolean) Parámetro con nombre opcional. El valor predeterminado

de true indica que se omite case. Un valor de false hace que el cmdlet distingue
mayúsculas de minúsculas.

Comentarios
Este atributo solo se puede usar una vez por parámetro.
Si el valor del parámetro es una matriz, cada elemento de la matriz debe coincidir
con un elemento del conjunto de atributos.

La clase System.Management.Automation.Validatesetattribute define el atributo


ValidateSetAttribute.

Consulte también
System.Management.Automation.Validatesetattribute

Escribir un cmdlet de Windows PowerShell


Alias del cmdlet
Artículo • 27/09/2021

Puede usar alias de cmdlet para mejorar la experiencia del usuario del cmdlet. Puede
agregar alias a los cmdlets usados con frecuencia para reducir la escritura y facilitar la
realización de tareas rápidamente. Puede incluir alias integrados en los cmdlets o los
usuarios pueden definir sus propios alias personalizados.

Por ejemplo, el cmdlet Get-Command tiene un gcm alias integrado. También puede usar
alias para agregar nombres de comandos desde otros lenguajes para que los usuarios
no tengan que aprender nuevos comandos.

Instrucciones de alias
Siga estas instrucciones al crear alias integrados para los cmdlets:

Antes de asignar alias, inicie Windows PowerShell y, a continuación, ejecute el


cmdlet Get-Alias para ver los alias que ya se usan.

Incluya un prefijo de alias que haga referencia al verbo del nombre del cmdlet y un
sufijo de alias que haga referencia al nombre del cmdlet. Por ejemplo, el alias del
Import-Module cmdlet es ipmo . Para obtener una lista de todos los verbos y sus

alias, vea Verbos de cmdlet.

Para los cmdlets que tienen el mismo verbo, incluya el mismo prefijo de alias. Por
ejemplo, los alias de todos los cmdlets Windows PowerShell que tienen el verbo
"Get" en su nombre usan el prefijo "g".

Para los cmdlets que tienen el mismo nombre, incluya el mismo sufijo de alias. Por
ejemplo, los alias de todos los cmdlets Windows PowerShell que tienen el nombre
"Session" en su nombre usan el sufijo "sn".

Para los cmdlets que son equivalentes a comandos en otros lenguajes, use el
nombre del comando.

En general, haga que los alias sea lo más corto posible. Asegúrese de que el alias
tiene al menos un carácter distinto para el verbo y un carácter distinto para el
sustantivo. Agregue más caracteres según sea necesario para que el alias sea
único.

Para el cmdlet escrito en C# (o cualquier otro lenguaje .NET compilado), el alias se


puede definir mediante el alias attibute. Por ejemplo:
C#

[Cmdlet("Get", "SomeObject")]
[Alias("gso")]
public class GetSomeObjectCommand : Cmdlet

Consulte también
Escribir un cmdlet de Windows PowerShell
Salida del cmdlet
Artículo • 27/09/2021

En esta sección se de analizan los tipos de salida de cmdlet y los métodos a los que los
cmdlets pueden llamar para generar resultados, como mensajes de error y objetos. En
esta sección también se describe cómo definir los .NET Framework que devuelven los
cmdlets y cómo se muestran esos objetos.

En esta sección
Tipos de salida de cmdlet Describe los tipos y la salida que pueden generar los cmdlets
y los métodos a los que llaman los cmdlets para generar la salida.

Informes de errores de cmdlet Describe los informes de errores de cmdlet, un


subconjunto de la salida del cmdlet.

Extender objetos de salida Describe cómo usar los archivos de tipos (.ps1xml) para
ampliar los objetos .NET Framework que devuelven cmdlets, funciones y scripts.

Archivos de formato de PowerShell Describe los archivos de formato (.format.ps1xml)


que definen la presentación predeterminada de un conjunto específico de objetos .NET
Framework en Windows PowerShell.

Archivos de formato personalizados Describe cómo crear sus propios archivos de


formato personalizados para sobrescribir los formatos de presentación predeterminados
o para definir la presentación de objetos devueltos por sus propios comandos.

Vea también
Escribir un cmdlet de Windows PowerShell
Tipos de salida de cmdlet
Artículo • 27/09/2021

PowerShell proporciona varios métodos a los que pueden llamar los cmdlets para
generar la salida. Estos métodos usan una operación específica para escribir su salida en
un flujo de datos específico, como el flujo de datos correcto o el flujo de datos de error.
En este artículo se describen los tipos de salida y los métodos usados para generarlos.

Tipos de salida

Salida correcta
Los cmdlets pueden notificar el éxito devolviendo un objeto que el comando siguiente
puede procesar en la canalización. Una vez que el cmdlet ha realizado correctamente su
acción, llama al método System.Management.Automation.Cmdlet.WriteObject. Se
recomienda llamar a este método en lugar de los métodos System.Console.WriteLine o
System.Management.Automation.Host.PSHostUserInterface.WriteLine.

Puede proporcionar un parámetro de modificador PassThru para los cmdlets que


normalmente no devuelven objetos. Cuando se especifica el parámetro de modificador
PassThru en la línea de comandos, se pide al cmdlet que devuelva un objeto . Para
obtener un ejemplo de un cmdlet que tiene un parámetro PassThru, vea Add-History.

Salida de error
Los cmdlets pueden notificar errores. Cuando se produce un error de terminación, el
cmdlet produce una excepción. Cuando se produce un error de no terminación, el
cmdlet llama al método
System.Management.Automation.Provider.CmdletProvider.WriteError para enviar un
registro de error al flujo de datos de error. Para obtener más información sobre los
informes de errores, vea Conceptos de informes de errores.

Salida detallada
Los cmdlets pueden proporcionarle información útil mientras el cmdlet procesa
correctamente los registros mediante una llamada al método
System.Management.Automation.Cmdlet.WriteVerbose. El método genera mensajes
detallados que indican cómo se va a continuar la acción.
De forma predeterminada, no se muestran los mensajes detallados. Puede especificar el
parámetro Verbose cuando se ejecuta el cmdlet para mostrar estos mensajes. Verbose
es un parámetro común que está disponible para todos los cmdlets.

Salida de progreso
Los cmdlets pueden proporcionarle información de progreso cuando el cmdlet realiza
tareas que llevan mucho tiempo en completarse, como copiar un directorio de forma
recursiva. Para mostrar información de progreso, el cmdlet llama al método
System.Management.Automation.Cmdlet.WriteProgress.

Salida de depuración
Los cmdlets pueden proporcionar mensajes de depuración que son útiles al solucionar
problemas del código del cmdlet. Para mostrar información de depuración, el cmdlet
llama al método System.Management.Automation.Cmdlet.WriteDebug.

De forma predeterminada, no se muestran los mensajes de depuración. Puede


especificar el parámetro Debug cuando se ejecuta el cmdlet para mostrar estos
mensajes. Debug es un parámetro común que está disponible para todos los cmdlets.

Salida de advertencia
Los cmdlets pueden mostrar mensajes de advertencia llamando al método
System.Management.Automation.Cmdlet.WriteWarning.

De forma predeterminada, se muestran los mensajes de advertencia. Sin embargo,


puede configurar mensajes de advertencia mediante la variable o mediante los
parámetros Verbose y Debug cuando se $WarningPreference llama al cmdlet.

Mostrar la salida
Para todas las llamadas de método de escritura, la presentación de contenido viene
determinada por variables en tiempo de ejecución específicas. La excepción es el
método System.Management.Automation.Cmdlet.WriteObject. Con estas variables,
puede realizar la llamada de escritura adecuada en el lugar correcto del código y no
preocuparse por cuándo o si se debe mostrar la salida.
Acceso a la funcionalidad de salida de una
aplicación host
También puede diseñar un cmdlet para acceder directamente a la funcionalidad de
salida de una aplicación host a través del entorno de ejecución de PowerShell. Uso de
las API de host proporcionadas por PowerShell en lugar de System.Console o
System.Windows. Forms garantiza que el cmdlet funcionará con una variedad de hosts.
Por ejemplo: el hostpowershell.exe consola,powershell_ise.exehost gráfico, el host de
comunicación remota de PowerShell y hosts de terceros.

Consulte también
Conceptos de los informes de errores

Información general del cmdlet

Escribir un cmdlet de Windows PowerShell


Informes de errores de cmdlet
Artículo • 27/09/2021

Los cmdlets deben notificar los errores de forma diferente en función de si los errores
están terminando errores o errores no terminales. Los errores de terminación son
errores que hacen que la canalización finalice inmediatamente o errores que se
producen cuando no hay ninguna razón para continuar el procesamiento. Los errores no
terminales son aquellos que informan de una condición de error actual, pero el cmdlet
puede seguir procesando objetos de entrada. Con errores no terminales, normalmente
se notifica al usuario del problema, pero el cmdlet continúa procesando el siguiente
objeto de entrada.

Errores de terminación y no terminales


Las instrucciones siguientes se pueden usar para determinar si una condición de error es
un error de terminación o un error no terminal.

¿La condición de error impide que el cmdlet procese correctamente más objetos
de entrada? Si es así, se trata de un error de terminación.

¿La condición de error está relacionada con un objeto de entrada específico o con
un subconjunto de objetos de entrada? Si es así, se trata de un error no terminal.

¿Acepta el cmdlet varios objetos de entrada, de forma que el procesamiento se


puede ejecutar correctamente en otro objeto de entrada? Si es así, se trata de un
error no terminal.

Los cmdlets que pueden aceptar varios objetos de entrada deben decidir entre lo
que está finalizando y los errores no terminales, incluso cuando una situación
determinada se aplica solo a un único objeto de entrada.

Los cmdlets pueden recibir cualquier número de objetos de entrada y enviar


cualquier número de objetos correctos o de error antes de iniciar una excepción
de terminación. No hay ninguna relación entre el número de objetos de entrada
recibidos y el número de objetos correctos y de error enviados.

Los cmdlets que solo pueden aceptar 0-1 objetos de entrada y generar solo 0-1
objetos de salida deben tratar los errores como errores de terminación y generar
excepciones de terminación.

Notificar errores no terminales


La generación de informes de un error no terminal siempre debe realizarse dentro de la
implementación del cmdlet del método
System.Management.Automation.Cmdlet.BeginProcessing, el método
System.Management.Automation.Cmdlet.ProcessRecord o el método
System.Management.Automation.Cmdlet.EndProcessing. Estos tipos de errores se
notifican mediante una llamada al método
System.Management.Automation.Cmdlet.WriteError que, a su vez, envía un registro de
error al flujo de errores.

Informes de errores de terminación


Los errores de terminación se notifican iniciando excepciones o llamando al método
System.Management.Automation.Cmdlet.ThrowTerminatingError. Tenga en cuenta que
los cmdlets también pueden detectar y volver a detectar excepciones como
OutOfMemory; sin embargo, no son necesarios para volver a crear excepciones, ya que
el tiempo de ejecución de PowerShell también las detectará.

También puede definir sus propias excepciones para problemas específicos de su


situación o agregar información adicional a una excepción existente mediante su
registro de errores.

Registros de errores
PowerShell describe una condición de error no terminal con objetos
System.Management.Automation.ErrorRecord. Cada objeto proporciona información de
categoría de error, un objeto de destino opcional y detalles sobre la condición de error.

Identificadores de error
El identificador de error es una cadena simple que identifica la condición de error dentro
del cmdlet . PowerShell combina este identificador con un identificador de cmdlet para
crear un identificador de error completo que se puede usar más adelante al filtrar
secuencias de errores o registrar errores, al responder a errores específicos o con otras
actividades específicas del usuario.

Se deben seguir las instrucciones siguientes al especificar identificadores de error:

Asigne identificadores de error diferentes y muy específicos a distintas rutas de


acceso de código. Cada ruta de acceso de código que llama a
System.Management.Automation.Cmdlet.WriteError o
System.Management.Automation.Cmdlet.ThrowTerminatingError debe tener su
propio identificador de error.

Los identificadores de error deben ser únicos para los tipos de excepción de
Common Language Runtime (CLR) para los errores de terminación y no terminales.

No cambie la semántica de un identificador de error entre las versiones del cmdlet


o del proveedor de PowerShell. Una vez establecida la semántica de un
identificador de error, debe permanecer constante a lo largo del ciclo de vida del
cmdlet.

Para terminar los errores, use un identificador de error único para un tipo de
excepción CLR determinado. Si cambia el tipo de excepción, use un nuevo
identificador de error.

Para errores no terminales, use un identificador de error específico para un objeto


de entrada específico.

Elija texto para el identificador que se corresponde con el error que se notifica. No
use espacios en blanco ni signos de puntuación.

No genere identificadores de error que no se puedan reproducir. Por ejemplo, no


genere identificadores que incluyan un identificador de proceso. Los
identificadores de error solo son útiles cuando se corresponden con
identificadores que ven otros usuarios que experimentan el mismo problema.

Categorías de errores
Las categorías de errores se usan para agrupar los errores del usuario. PowerShell define
estas categorías y cmdlets y los proveedores de PowerShell deben elegir entre ellas al
generar el registro de errores.

Para obtener una descripción de las categorías de error disponibles, vea la enumeración
System.Management.Automation.ErrorCategory. En general, debe evitar el uso de
NoError, UndefinedError y GenericError siempre que sea posible.

Los usuarios pueden ver los errores en función de la categoría cuando establecen
$ErrorView en CategoryView.

Consulte también
Información general del cmdlet
Tipos de salida del cmdlet

Referencia de Windows PowerShell


Extensión de los objetos de salida
Artículo • 24/09/2021

Puede extender el .NET Framework objetos devueltos por cmdlets, funciones y scripts
mediante archivos de tipos (.ps1xml). Los archivos de tipos son archivos basados en
XML que permiten agregar propiedades y métodos a objetos existentes. Por ejemplo,
Windows PowerShell proporciona el archivo Types.ps1xml, que agrega elementos a
varios objetos .NET Framework existentes. El archivo Types.ps1xml se encuentra en el
Windows PowerShell de instalación ( $pshome ). Puede crear su propio archivo de tipos
para ampliar aún más esos objetos o para ampliar otros objetos. Cuando se extiende un
objeto mediante un archivo de tipos, cualquier instancia del objeto se extiende con los
nuevos elementos .

Extender el objeto System.Array


En el ejemplo siguiente se muestra Windows PowerShell extiende el objeto System.Array
en el archivo Types.ps1xml. De forma predeterminada, los objetos System.Array tienen
una Length propiedad que enumera el número de objetos de la matriz. Sin embargo,
dado que el nombre "length" no describe claramente la propiedad, Windows PowerShell
agrega la propiedad de alias, que muestra el mismo valor Count que la Length
propiedad . El siguiente XML agrega la Count propiedad al tipo System.Array.

XML

<Type>
<Name>System.Array</Name>
<Members>
<AliasProperty>
<Name>Count</Name>
<ReferencedMemberName>Length</ReferencedMemberName>
</AliasProperty>
</Members>
</Type>

Para ver esta nueva propiedad de alias, use un comando Get-Member en cualquier
matriz, como se muestra en el ejemplo siguiente.

PowerShell

Get-Member -InputObject (1,2,3,4)


El comando devuelve los resultados siguientes.

Resultados

Name MemberType Definition


---- ---------- ----------
Count AliasProperty Count = Length
Address Method System.Object& Address(Int32 )
Clone Method System.Object Clone()
CopyTo Method System.Void CopyTo(Array array, Int32 index):
Equals Method System.Boolean Equals(Object obj)
Get Method System.Object Get(Int32 )
...
Length Property System.Int32 Length {get;}

Puede usar la propiedad o la propiedad para Count determinar cuántos objetos hay en
una Length matriz. Por ejemplo:

PowerShell

PS> (1, 2, 3, 4).Count

Resultados

PowerShell

PS> (1, 2, 3, 4).Length

Resultados

Archivos de tipos personalizados


Para crear un archivo de tipos personalizado, empiece copiando un archivo de tipos
existente. El nuevo archivo puede tener cualquier nombre, pero debe tener una
extensión de nombre de archivo .ps1xml. Al copiar el archivo, puede colocar el nuevo
archivo en cualquier directorio al que pueda acceder Windows PowerShell, pero resulta
útil colocar los archivos en el directorio de instalación de Windows PowerShell ( ) o en
un subdirectorio del directorio de $pshome instalación.
Para agregar sus propios tipos extendidos al archivo, agregue un elemento types para
cada objeto que quiera extender. En los temas siguientes se proporcionan ejemplos.

Para obtener más información sobre cómo agregar propiedades y conjuntos de


propiedades, vea Propiedades extendidas.

Para obtener más información sobre cómo agregar métodos, vea Métodos
extendidos.

Para obtener más información sobre cómo agregar conjuntos de miembros, vea
Extended Member Sets.

Después de definir sus propios tipos extendidos, use uno de los métodos siguientes
para que los objetos extendidos estén disponibles:

Para que el archivo de tipos extendidos esté disponible para la sesión actual, use el
cmdlet Update-TypeData para agregar el nuevo archivo. Si desea que los tipos
tienen prioridad sobre los tipos definidos en otros archivos de tipos (incluido el
archivo Types.ps1xml), use el parámetro del PrependData cmdlet Update-TypeData.
Para que el archivo de tipos extendidos esté disponible para todas las sesiones
futuras, agregue el archivo de tipos a un módulo, exporte la sesión actual o
agregue el comando Update-TypeData al perfil de Windows PowerShell.

Archivos de tipos de firma


Los archivos de tipos deben estar firmados digitalmente para evitar la manipulación, ya
que el XML puede incluir bloques de script. Para más información sobre cómo agregar
firmas digitales, consulte about_Signing

Consulte también
Definir propiedades predeterminadas para objetos

Definición de métodos predeterminados para los objetos

Definición de conjuntos de miembros predeterminados para los objetos

Escribir un cmdlet de Windows PowerShell


Extensión de las propiedades de los
objetos
Artículo • 27/09/2021

Al extender los .NET Framework, puede agregar propiedades de alias, propiedades de


código, propiedades de nota, propiedades de script y conjuntos de propiedades a los
objetos. El XML que define estas propiedades se describe en las secciones siguientes.

7 Nota

Los ejemplos de las secciones siguientes son del archivo de Types.ps1xml tipos
predeterminados en el directorio de instalación de PowerShell ( $PSHOME ). Para
obtener más información, vea Acerca de Types.ps1xml.

Propiedades de alias
Una propiedad de alias define un nuevo nombre para una propiedad existente.

En el ejemplo siguiente, la propiedad Count se agrega al tipo System.Array. El elemento


AliasProperty define la propiedad extendida como una propiedad de alias. El elemento
Name especifica el nuevo nombre. Además, el elemento ReferencedMemberName
especifica la propiedad existente a la que hace referencia el alias. También puede
agregar el AliasProperty elemento a los miembros del elemento MemberSets.

XML

<Type>
<Name>System.Array</Name>
<Members>
<AliasProperty>
<Name>Count</Name>
<ReferencedMemberName>Length</ReferencedMemberName>
</AliasProperty>
</Members>
</Type>

Propiedades de código
Una propiedad de código hace referencia a una propiedad estática de .NET Framework
objeto .
En el ejemplo siguiente, la propiedad Mode se agrega al tipo System.IO.DirectoryInfo. El
elemento CodeProperty define la propiedad extendida como una propiedad de código.
El elemento Name especifica el nombre de la propiedad extendida. Además, el
elemento GetCodeReference define el método estático al que hace referencia la
propiedad extendida. También puede agregar el CodeProperty elemento a los miembros
del elemento MemberSets.

XML

<Type>
<Name>System.IO.DirectoryInfo</Name>
<Members>
<CodeProperty>
<Name>Mode</Name>
<GetCodeReference>

<TypeName>Microsoft.PowerShell.Commands.FileSystemProvider</TypeName>
<MethodName>Mode</MethodName>
</GetCodeReference>
</CodeProperty>
</Members>
</Type>

Anotar propiedades
Una propiedad de nota define una propiedad que tiene un valor estático.

En el ejemplo siguiente, la propiedad Status, cuyo valor es siempre Success, se agrega


al tipo System.IO.DirectoryInfo. El elemento NoteProperty define la propiedad extendida
como una propiedad de nota. El elemento Name especifica el nombre de la propiedad
extendida. El elemento Value especifica el valor estático de la propiedad extendida. El
NoteProperty elemento también se puede agregar a los miembros del elemento
MemberSets.

XML

<Type>
<Name>System.IO.DirectoryInfo</Name>
<Members>
<NoteProperty>
<Name>Status</Name>
<Value>Success</Value>
</NoteProperty>
</Members>
</Type>
Propiedades del script
Una propiedad de script define una propiedad cuyo valor es la salida de un script.

En el ejemplo siguiente, la propiedad VersionInfo se agrega al tipo System.IO.FileInfo. El


elemento ScriptProperty define la propiedad extendida como una propiedad de script.
El elemento Name especifica el nombre de la propiedad extendida. Además, el
elemento GetScriptBlock especifica el script que genera el valor de propiedad. También
puede agregar el ScriptProperty elemento a los miembros del elemento MemberSets.

XML

<Type>
<Name>System.IO.FileInfo</Name>
<Members>
<ScriptProperty>
<Name>VersionInfo</Name>
<GetScriptBlock>
[System.Diagnostics.FileVersionInfo]::GetVersionInfo($this.FullName)
</GetScriptBlock>
</ScriptProperty>
</Members>
</Type>

Conjuntos de propiedades
Un conjunto de propiedades define un grupo de propiedades extendidas a las que se
puede hacer referencia mediante el nombre del conjunto. Por ejemplo, el parámetro
Format-Table Property puede especificar un conjunto de propiedades específico que se
va a mostrar. Cuando se especifica un conjunto de propiedades, solo se muestran las
propiedades que pertenecen al conjunto.

No hay ninguna restricción en el número de conjuntos de propiedades que se pueden


definir para un objeto . Sin embargo, los conjuntos de propiedades utilizados para
definir las propiedades de presentación predeterminadas de un objeto deben
especificarse dentro del conjunto de miembros PSStandardMembers. En el
Types.ps1xml archivo de tipos, los nombres de conjunto de propiedades
predeterminados incluyen DefaultDisplayProperty, DefaultDisplayPropertySet y
DefaultKeyPropertySet. Se omiten los conjuntos de propiedades adicionales que
agregue al conjunto de miembros PSStandardMembers.

En el ejemplo siguiente, el conjunto de propiedades DefaultDisplayPropertySet se


agrega al conjunto de miembros PSStandardMembers del tipo
System.Serviceprocess.Servicecontroller. El elemento PropertySet define el grupo de
propiedades. El elemento Name especifica el nombre del conjunto de propiedades.
Además, el elemento ReferencedProperties especifica las propiedades del conjunto.
También puede agregar el PropertySet elemento a los miembros del elemento Type.

XML

<Type>
<Name>System.ServiceProcess.ServiceController</Name>
<Members>
<MemberSet>
<Name>PSStandardMembers</Name>
<Members>
<PropertySet>
<Name>DefaultDisplayPropertySet</Name>
<ReferencedProperties>
<Name>Status</Name
<Name>Name</Name>
<Name>DisplayName</Name>
</ReferencedProperties>
</PropertySet>
</Members>
</MemberSet>
</Members>
</Type>

Consulte también
Acerca de Types.ps1xml

System.Management.Automation

Escribir un cmdlet de Windows PowerShell


Definición de métodos predeterminados
para los objetos
Artículo • 27/09/2021

Al extender los .NET Framework, puede agregar métodos de código y métodos de script
a los objetos . El XML que se usa para definir estos métodos se describe en las secciones
siguientes.

7 Nota

Los ejemplos de las secciones siguientes son del archivo de tipos del Windows
PowerShell Types.ps1xml de instalación ( $PSHOME ). Para obtener más información,
vea About Types.ps1xml.

Métodos de código
Un método de código hace referencia a un método estático de .NET Framework objeto .

En el ejemplo siguiente, el método ToString se agrega al System.Xml. Tipo XmlNode. El


elemento PSCodeMethod define el método extendido como un método de código. El
elemento Name especifica el nombre del método extendido. Además, el elemento
CodeReference especifica el método estático. También puede agregar el elemento
PSCodeMethod a los miembros del elemento PSMemberSets.

XML

<Type>
<Name>System.Xml.XmlNode</Name>
<Members>
<CodeMethod>
<Name>ToString</Name>
<CodeReference>
<TypeName>Microsoft.PowerShell.ToStringCodeMethods</TypeName>
<MethodName>XmlNode</MethodName>
</CodeReference>
</CodeMethod>
</Members>
</Type>

Métodos de script
Un método de script define un método cuyo valor es la salida de un script. En el
ejemplo siguiente, el método ConvertToDateTime se agrega al tipo
System.Management.ManagementObject. El elemento PSScriptMethod define el
método extendido como un método de script. El elemento Name especifica el nombre
del método extendido. Además, el elemento Script especifica el script que genera el
valor del método. También puede agregar el elemento PSScriptMethod a los miembros
del elemento PSMemberSets.

XML

<Type>
<Name>System.Management.ManagementObject</Name>
<Members>
<ScriptMethod>
<Name>ConvertToDateTime</Name>
<Script>

[System.Management.ManagementDateTimeConverter]::ToDateTime($args[0])
</Script>
</ScriptMethod>
</Members>
</Type>

Consulte también
Escribir un cmdlet de Windows PowerShell
Definición de conjuntos de miembros
predeterminados para los objetos
Artículo • 27/09/2021

El conjunto de miembros PSStandardMembers se usa Windows PowerShell para definir


los conjuntos de propiedades predeterminados para un objeto . Los conjuntos de
propiedades predeterminados los pueden usar comandos como los cmdlets de formato
para mostrar solo las propiedades definidas por el conjunto de propiedades. Los
conjuntos de propiedades predeterminados incluyen DefaultDisplayProperty,
DefaultDisplayPropertySet y DefaultKeyPropertySet. Windows PowerShell omite todos
los demás conjuntos de miembros y cualquier otro conjunto de propiedades agregado
al conjunto de miembros PSStandardMembers.

Conjunto de miembros para


System.Diagnostics.Process
En el ejemplo siguiente, el conjunto de miembros PSStandardMembers define el
conjunto de propiedades DefaultDisplayPropertySet para los objetos
System.Diagnostics.Process. El cmdlet Format-List usa este conjunto de propiedades.

XML

<Type>
<Name>System.Diagnostics.Process</Name>
<Members>
<MemberSet>
<Name>PSStandardMembers</Name>
<Members>
<PropertySet>
<Name>DefaultDisplayPropertySet</Name>
<ReferencedProperties>
<Name>Id</Name>
<Name>Handles</Name>
<Name>CPU</Name>
<Name>Name</Name>
</ReferencedProperties>
</PropertySet>
</Members>
</MemberSet>

La salida siguiente muestra las propiedades predeterminadas devueltas por el cmdlet


Format-List. Solo se Id Handles devuelven las CPU propiedades , , y para cada objeto de
Name proceso.

PowerShell

Get-Process | format-list

Resultados

Id : 2036
Handles : 27
CPU :
Name : AEADISRV

Id : 272
Handles : 38
CPU :
Name : agrsmsvc
...

Vea también
Escribir un cmdlet de Windows PowerShell
Archivos de formato personalizado
Artículo • 27/09/2021

El formato de presentación de los objetos devueltos por cmdlets, funciones y scripts se


define mediante archivos de formato (archivos format.ps1xml). Varios de estos archivos
se proporcionan mediante Windows PowerShell para definir el formato de presentación
predeterminado para los objetos devueltos por Windows PowerShell cmdlets. Sin
embargo, también puede crear sus propios archivos de formato personalizados para
sobrescribir los formatos de presentación predeterminados o para definir la
presentación de objetos devueltos por sus propios comandos.

Windows PowerShell los datos de estos archivos de formato para determinar lo que se
muestra y cómo se formatearán los datos. Los datos mostrados pueden incluir las
propiedades de un objeto o el valor de un bloque de script. Los bloques de script se
usan si desea mostrar algún valor que no está disponible directamente desde las
propiedades de un objeto . Por ejemplo, puede agregar el valor de dos propiedades de
un objeto y mostrar la suma como un fragmento de datos independiente. Al escribir su
propio archivo de formato, deberá definir vistas para los objetos que desea mostrar.
Puede definir una vista única para cada objeto, puede definir una vista única para varios
objetos o puede definir varias vistas para el mismo objeto. No hay ningún límite en el
número de vistas que puede definir.

) Importante

Los archivos de formato no determinan los elementos de un objeto que se


devuelven a la canalización. Cuando se devuelve un objeto a la canalización, todos
los miembros de ese objeto están disponibles.

Dar formato a vistas


Las vistas de formato pueden mostrar objetos en un formato de tabla, un formato de
lista, un formato ancho y un formato personalizado. En su mayor parte, cada definición
de formato se describe mediante un conjunto de etiquetas XML que describen una vista.
Cada vista contiene el nombre de la vista, los objetos que usan la vista y los elementos
de la vista, como la información de columna y fila de una vista de tabla.

Están disponibles las siguientes vistas.

Vista tabla Muestra las propiedades de un objeto o un valor de bloque de script en una
o varias columnas. Cada columna representa una propiedad del objeto o un valor de
bloque de script. Puede definir una vista de tabla que muestre todas las propiedades de
un objeto, un subconjunto de las propiedades de un objeto o una combinación de
propiedades y valores de bloque de script. Cada fila de la tabla representa un objeto
devuelto. Para obtener más información sobre esta vista, vea Vista de tabla.

Vista de lista Muestra las propiedades de un objeto o un valor de bloque de script en


una sola columna. Cada fila de la lista muestra una etiqueta opcional o el nombre de
propiedad seguido del valor de la propiedad o el bloque de script. Para obtener más
información sobre esta vista, vea Vista de lista.

Vista ancha Muestra una sola propiedad de un objeto o un valor de bloque de script en
una o varias columnas. No hay ninguna etiqueta ni encabezado para esta vista. Para
obtener más información sobre esta vista, vea Wide View.

Vista personalizada Muestra una vista personalizable de propiedades de objeto o


valores de bloque de script que no cumplen la estructura rígida de vistas de tabla, vistas
de lista o vistas anchas. Puede definir una vista personalizada independiente o definir
una vista personalizada que otra vista utilice, como una vista de tabla o una vista de
lista. Para obtener más información sobre esta vista, vea Vista personalizada.

Ver elementos XML


En el ejemplo siguiente se muestran las etiquetas XML utilizadas para definir una vista
de tabla que contiene dos columnas. El elemento ViewDefinitions es el elemento
contenedor de todas las vistas definidas en el archivo de formato. El elemento View
define la tabla, lista, ancho o vista personalizada específicos. Dentro de cada vista, el
elemento Name especifica el nombre de la vista, el elemento ViewSelectedBy define los
objetos que usan la vista y los distintos elementos de control (como el elemento )
definen el formato de la TableControl vista.

XML

ViewDefinitions
<View>
<Name>Name of View</Name>
<ViewSelectedBy>
<TypeName>Object to display using this view</TypeName>
<TypeName>Object to display using this view</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Header for column 1</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Header for column 2</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl)
</View>
</ViewDefinitions>

Consulte también
Vista tabla

Vista de lista

Vista ancha

Vista personalizada

Escribir un cmdlet de Windows PowerShell


Solicitud de confirmación
Artículo • 27/09/2021

En esta sección se analizan los mensajes de confirmación que se pueden mostrar antes
de que un cmdlet, una función o un proveedor realicen una acción.

En esta sección
Solicitud del proceso de confirmación para comandos Describe el proceso que deben
seguir los cmdlets, las funciones y los proveedores para solicitar una confirmación antes
de realizar un cambio en el sistema.

Usuarios que solicitan confirmación Describe cómo los usuarios pueden realizar una
confirmación de solicitud de cmdlet, función o proveedor cuando se llama al método
System.Management.Automation.Cmdlet.ShouldProcess.

Mensajes de confirmación Proporciona ejemplos de los distintos mensajes de


confirmación que se pueden mostrar.

Vea también
Escribir un cmdlet de Windows PowerShell
Solicitud de confirmación de los cmdlets
Artículo • 26/09/2021

Los cmdlets deben solicitar confirmación cuando están a punto de realizar un cambio en
el sistema que está fuera del Windows PowerShell de ejecución. Por ejemplo, si un
cmdlet está a punto de agregar una cuenta de usuario o detener un proceso, el cmdlet
debe requerir confirmación del usuario antes de continuar. Por el contrario, si un cmdlet
está a punto de cambiar una variable Windows PowerShell, el cmdlet no necesita
confirmación.

Para realizar una solicitud de confirmación, el cmdlet debe indicar que admite
solicitudes de confirmación y debe llamar a los métodos
System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue (opcional) para mostrar un
mensaje de solicitud de confirmación.

Admitir solicitudes de confirmación


Para admitir solicitudes de confirmación, el cmdlet debe establecer
SupportsShouldProcess el parámetro del atributo Cmdlet en true . Esto habilita los

Confirm parámetros de cmdlet y WhatIf proporcionados por Windows PowerShell. El

Confirm parámetro permite al usuario controlar si se muestra la solicitud de


confirmación. El WhatIf parámetro permite al usuario determinar si el cmdlet debe
mostrar un mensaje o realizar su acción. No agregue manualmente los parámetros
Confirm y WhatIf a un cmdlet.

En el ejemplo siguiente se muestra una declaración de atributo cmdlet que admite


solicitudes de confirmación.

C#

[Cmdlet(VerbsDiagnostic.Test, "RequestConfirmationTemplate1",
SupportsShouldProcess = true)]

Llamar a los métodos de solicitud de


confirmación
En el código del cmdlet, llame al método
System.Management.Automation.Cmdlet.ShouldProcess antes de que se realice la
operación que cambia el sistema. Diseñe el cmdlet para que si la llamada devuelve un
valor de , la operación no se realiza y el false cmdlet procesa la siguiente operación.

Llamar al método ShouldContinue


La mayoría de los cmdlets solicitan confirmación solo mediante el método
System.Management.Automation.Cmdlet.ShouldProcess. Sin embargo, algunos casos
pueden requerir confirmación adicional. En estos casos, complemente la llamada a
System.Management.Automation.Cmdlet.ShouldProcess con una llamada al método
System.Management.Automation.Cmdlet.ShouldContinue. Esto permite que el cmdlet o
el proveedor controle de forma más fina el ámbito de la respuesta Sí a toda la respuesta
al símbolo del sistema de confirmación.

Si un cmdlet llama al método System.Management.Automation.Cmdlet.ShouldContinue,


el cmdlet también debe proporcionar un Force parámetro switch. Si el usuario
especifica cuándo el usuario invoca el cmdlet, el cmdlet todavía debe llamar a Force
System.Management.Automation.Cmdlet.ShouldProcess, pero debe omitir la llamada a
System.Management.Automation.Cmdlet.ShouldContinue.

System.Management.Automation.Cmdlet.ShouldContinue producirá una excepción


cuando se llame desde un entorno no interactivo en el que no se pueda solicitar al
usuario. Agregar un parámetro garantiza que el comando se puede seguir Force
realizando cuando se invoca en un entorno no interactivo.

En el ejemplo siguiente se muestra cómo llamar a


System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue.

C#

if (ShouldProcess (...) )
{
if (Force || ShouldContinue(...))
{
// Add code that performs the operation.
}
}

El comportamiento de una llamada a


System.Management.Automation.Cmdlet.ShouldProcess puede variar en función del
entorno en el que se invoque el cmdlet. El uso de las instrucciones anteriores le ayudará
a garantizar que el cmdlet se comporta de forma coherente con otros cmdlets,
independientemente del entorno de host.
Para obtener un ejemplo de cómo llamar al método
System.Management.Automation.Cmdlet.ShouldProcess, vea Cómo solicitar
confirmaciones.

Especificar el nivel de impacto


Al crear el cmdlet, especifique el nivel de impacto (la gravedad) del cambio. Para ello,
establezca el valor del parámetro del atributo ConfirmImpact Cmdlet en Alto, Medio o
Bajo. Solo puede especificar un valor ConfirmImpact para cuando también especifique el
parámetro para el cmdlet SupportsShouldProcess .

Para la mayoría de los cmdlets, no es necesario especificar explícitamente ConfirmImpact


. En su lugar, use la configuración predeterminada del parámetro , que es Medium. Si
establece ConfirmImpact en Alta, la operación se confirmará de forma predeterminada.
Reserve esta opción para acciones muy perjudiciales, como volver a formatear un
volumen de disco duro.

Llamar a métodos que no son de confirmación


Si el cmdlet o proveedor debe enviar un mensaje pero no solicitar confirmación, puede
llamar a los tres métodos siguientes. Evite usar el método
System.Management.Automation.Cmdlet.WriteObject para enviar mensajes de estos
tipos porque la salida de System.Management.Automation.Cmdlet.WriteObject se
entremezcha con la salida normal del cmdlet o proveedor, lo que dificulta la escritura de
scripts.

Para advertir al usuario y continuar con la operación, el cmdlet o proveedor puede


llamar al método System.Management.Automation.Cmdlet.WriteWarning.

Para proporcionar información adicional que el usuario puede recuperar mediante


el parámetro , el cmdlet o proveedor puede llamar al método Verbose
System.Management.Automation.Cmdlet.WriteVerbose.

Para proporcionar detalles de nivel de depuración para otros desarrolladores o


para soporte técnico de productos, el cmdlet o proveedor puede llamar al método
System.Management.Automation.Cmdlet.WriteDebug. El usuario puede recuperar
esta información mediante el Debug parámetro .

Los cmdlets y proveedores llaman primero a los métodos siguientes para solicitar
confirmación antes de intentar realizar una operación que cambia un sistema fuera de
Windows PowerShell:
System.Management.Automation.Cmdlet.Shouldprocess

System.Management.Automation.Provider.Cmdletprovider.Shouldprocess

Para ello, llaman al método System.Management.Automation.Cmdlet.Shouldprocess,


que solicita al usuario que confirme la operación en función de cómo el usuario invocó
el comando.

Vea también
Escribir un cmdlet de Windows PowerShell
Usuarios que solicitan confirmación
Artículo • 05/10/2021

Cuando se especifica un valor de para el parámetro de la declaración de atributo cmdlet,


el parámetro Confirm se agrega a true SupportsShouldProcess los parámetros del
cmdlet.

En el entorno predeterminado, los usuarios pueden especificar el parámetro Confirm o


para que se solicite la confirmación cuando se llame al "-Confirm:$true método
ShouldProcess() . Esto fuerza la confirmación independientemente de la configuración
del nivel de impacto.

Si no se usa el parámetro Confirm, la llamada solicita confirmación si la variable de


preferencia es igual o mayor que la configuración ShouldProcess() del cmdlet o
$ConfirmPreference ConfirmImpact proveedor. El valor predeterminado de

$ConfirmPreference es Alto. Por lo tanto, en el entorno predeterminado, solo los


cmdlets y proveedores que especifican una solicitud de acción de alto impacto solicitan
confirmación.

Si Confirm se establece explícitamente en false ( ), el cmdlet se ejecuta sin pedir


confirmación y se omite la -Confirm:$false variable de $ConfirmPreference shell.

Comentarios
Para los cmdlets y proveedores que especifican , pero no , esas acciones se
controlan como acciones de "impacto medio" y no se SupportsShouldProcess
ConfirmImpact solicitarán de forma predeterminada. Su nivel de impacto es menor

que el valor predeterminado de la $ConfirmPreference variable de preferencia.

Si el usuario especifica el parámetro , se le notificará de la operación incluso si no


se le Verbose pide confirmación.

Vea también
Escribir un cmdlet de Windows PowerShell
System.Management.Automation.Cmdlet.ShouldProcess
Mensajes de confirmación
Artículo • 27/09/2021

Estos son mensajes de confirmación diferentes que se pueden mostrar en función de las
variantes de los métodos System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue a los que se llama.

) Importante

Para obtener código de ejemplo que muestra cómo solicitar confirmaciones, vea
Cómo solicitar confirmaciones.

Especificación del recurso


Puede especificar el recurso que está a punto de cambiarse llamando a
System.Management.Automation.Cmdlet.Shouldprocess%2A?
Displayproperty=Fullname (método). En este caso, se proporciona el recurso mediante
el parámetro del método y la operación se agrega target mediante Windows
PowerShell. En el mensaje siguiente, el texto "MyResource" es el recurso sobre el que se
ha actuado y la operación es el nombre del comando que realiza la llamada.

Output

Confirm
Are you sure you want to perform this action?
Performing operation "Test-RequestConfirmationTemplate1" on Target
"MyResource".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

Si el usuario selecciona Sí o Sí a Todo en la solicitud de confirmación (como se muestra


en el ejemplo siguiente), se realiza una llamada al método
System.Management.Automation.Cmdlet.ShouldContinue, lo que hace que se muestre
un segundo mensaje de confirmación.

Output

Confirm
Are you sure you want to perform this action?
Performing operation "Test-RequestConfirmationTemplate1" on Target
"MyResource".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): y

Confirm
Continue with this operation?
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"):

Especificar la operación y el recurso


Puede especificar el recurso que está a punto de cambiarse y la operación que el
comando está a punto de realizar llamando a
System.Management.Automation.Cmdlet.Shouldprocess%2A?
Displayproperty=Fullname (método). En este caso, se proporciona el recurso mediante
el parámetro target y la operación mediante el parámetro target . En el mensaje
siguiente, el texto "MyResource" es el recurso en el que se actúa y "MyAction" es la
operación que se va a realizar.

Output

Confirm
Are you sure you want to perform this action?
Performing operation "MyAction" on Target "MyResource".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"):

Si el usuario selecciona Sí o Sí a Todo en el mensaje anterior, se realiza una llamada al


método System.Management.Automation.Cmdlet.ShouldContinue, lo que hace que se
muestre un segundo mensaje de confirmación.

Output

Confirm
Are you sure you want to perform this action?
Performing operation "MyAction" on Target "MyResource".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): y

Confirm
Continue with this operation?
[Y] Yes [N] No [S] Suspend [?] Help (default is "Y"):

Vea también
Escribir un cmdlet de Windows PowerShell
Informes de errores de Windows
PowerShell
Artículo • 24/09/2021

En los temas de esta sección se describe cómo los cmdlets informan de los errores.

En esta sección
Conceptos de informes de errores Describe los dos mecanismos que los cmdlets
pueden usar para notificar errores.

Errores de terminación Describe el método utilizado para notificar los errores de


terminación, donde se puede llamar a ese método desde dentro del cmdlet y las
excepciones que puede devolver el tiempo de ejecución de Windows PowerShell
cuando se llama al método .

Errores de no terminación Describe el método utilizado para notificar errores de no


terminación y dónde se puede llamar a ese método desde dentro del cmdlet .

Mostrar información de error por categoría Describe las formas en que los usuarios
pueden mostrar el error.

Windows PowerShell de errores Describe los componentes de un registro de errores.

Interpretación de objetos ErrorRecord Describe cómo se interpretan los objetos


ErrorRecord.

Vea también
Escribir un cmdlet de Windows PowerShell
Conceptos de los informes de errores
Artículo • 27/09/2021

Windows PowerShell proporciona dos mecanismos para notificar errores: un mecanismo


para terminar los errores y otro mecanismo para los errores de no terminación. Es
importante que el cmdlet informe correctamente de los errores para que la aplicación
host que ejecuta los cmdlets pueda reaccionar de la manera adecuada.

El cmdlet debe llamar al método


System.Management.Automation.Cmdlet.Throwterminatingerror* cuando se produce un
error que no permite o no permite que el cmdlet siga procesando sus objetos de
entrada. El cmdlet debe llamar al método
System.Management.Automation.Cmdlet.WriteError para notificar errores que no
terminen cuando el cmdlet pueda continuar procesando los objetos de entrada. Ambos
métodos proporcionan un registro de error que la aplicación host puede usar para
investigar la causa del error.

Use las siguientes directrices para determinar si un error es un error de terminación o de


no terminación.

Un error es un error de terminación si impide que el cmdlet continúe procesando


el objeto actual o procese correctamente cualquier otro objeto de entrada,
independientemente de su contenido.

Un error es un error de terminación si no desea que el cmdlet siga procesando el


objeto actual o cualquier otro objeto de entrada, independientemente de su
contenido.

Un error es un error de terminación si se produce en un cmdlet que no acepta o


devuelve un objeto o si se produce en un cmdlet que acepta o devuelve solo un
objeto.

Un error es un error de no terminación si desea que el cmdlet siga procesando el


objeto actual y cualquier otro objeto de entrada.

Un error es un error de no terminación si está relacionado con un objeto de


entrada específico o un subconjunto de objetos de entrada.

Consulte también
System.Management.Automation.Cmdlet.Throwterminatingerror*
System.Management.Automation.Cmdlet.WriteError

Registros de errores de Windows PowerShell

Escribir un cmdlet de Windows PowerShell


Errores de terminación
Artículo • 27/09/2021

En este tema se describe el método utilizado para notificar errores de terminación.


También se describe cómo llamar al método desde dentro del cmdlet y se analizan las
excepciones que el tiempo de ejecución de Windows PowerShell puede devolver
cuando se llama al método .

Cuando se produce un error de terminación, el cmdlet debe notificar el error llamando


al método System.Management.Automation.Cmdlet.Throwterminatingerror*. Este
método permite al cmdlet enviar un registro de error que describe la condición que
produjo el error de terminación. Para obtener más información sobre los registros de
errores, vea Windows PowerShell Registros de errores.

Cuando se llama al método


System.Management.Automation.Cmdlet.Throwterminatingerror*, el tiempo de
ejecución de Windows PowerShell detiene permanentemente la ejecución de la
canalización y produce una excepción
System.Management.Automation.Pipelinestoppedexception. Cualquier intento posterior
de llamar a System.Management.Automation.Cmdlet.WriteObject,
System.Management.Automation.Cmdlet.WriteErroru otras API hace que esas llamadas
inicien una excepción System.Management.Automation.Pipelinestoppedexception.

La excepción System.Management.Automation.Pipelinestoppedexception también


puede producirse si otro cmdlet de la canalización informa de un error de terminación,
si el usuario ha pedido detener la canalización o si la canalización se ha detenido antes
de la finalización por cualquier motivo. El cmdlet no necesita detectar la excepción
System.Management.Automation.Pipelinestoppedexception a menos que tenga que
limpiar los recursos abiertos o su estado interno.

Los cmdlets pueden escribir cualquier número de objetos de salida o errores de no


terminación antes de notificar un error de terminación. Sin embargo, el error de
terminación detiene permanentemente la canalización y no se puede notifica ninguna
salida adicional, errores de terminación o errores de no terminación.

Los cmdlets pueden llamar a


System.Management.Automation.Cmdlet.Throwterminatingerror* solo desde el
subproceso que llamó al método de procesamiento de entrada
System.Management.Automation.Cmdlet.BeginProcessing,
System.Management.Automation.Cmdlet.ProcessRecordo
System.Management.Automation.Cmdlet.EndProcessing. No intente llamar a
System.Management.Automation.Cmdlet.Throwterminatingerror* o
System.Management.Automation.Cmdlet.WriteError desde otro subproceso. En su lugar,
los errores se deben comunicar de nuevo al subproceso principal.

Es posible que un cmdlet inicie una excepción en su implementación del método


System.Management.Automation.Cmdlet.BeginProcessing,
System.Management.Automation.Cmdlet.ProcessRecordo
System.Management.Automation.Cmdlet.EndProcessing. Cualquier excepción producida
desde estos métodos (excepto para algunas condiciones de error graves que detienen el
host de Windows PowerShell) se interpreta como un error de terminación que detiene la
canalización, pero no Windows PowerShell como un todo. (Esto solo se aplica al
subproceso del cmdlet principal. Las excepciones no detectadas en los subprocesos
generados por el cmdlet, en general, detienen el Windows PowerShell host). Se
recomienda usar System.Management.Automation.Cmdlet.Throwterminatingerror* en
lugar de producir una excepción porque el registro de error proporciona información
adicional sobre la condición de error, lo que resulta útil para el usuario final. Los cmdlets
deben respetar las guías de código administrado para detectar y controlar todas las
excepciones ( catch (Exception e) ). Convierta solo las excepciones de tipos conocidos
y esperados en registros de errores.

Consulte también
System.Management.Automation.Cmdlet.BeginProcessing

System.Management.Automation.Cmdlet.EndProcessing

System.Management.Automation.Cmdlet.ProcessRecord

System.Management.Automation.Pipelinestoppedexception

System.Management.Automation.Cmdlet.Throwterminatingerror*

System.Management.Automation.Cmdlet.WriteError

Registros de errores de Windows PowerShell

Escribir un cmdlet de Windows PowerShell


Errores de no terminación
Artículo • 27/09/2021

En este tema se describe el método que se usa para notificar errores de no terminación.
También se describe cómo llamar al método desde dentro del cmdlet .

Cuando se produce un error de no terminación, el cmdlet debe notificar este error


llamando al método System.Management.Automation.Cmdlet.WriteError. Cuando el
cmdlet notifica un error de no terminación, el cmdlet puede seguir funcionando en este
objeto de entrada y en otros objetos de canalización entrantes. Si el cmdlet llama al
método System.Management.Automation.Cmdlet.WriteError, el cmdlet puede escribir
un registro de error que describa la condición que produjo el error de no terminación.
Para obtener más información sobre los registros de errores, vea Windows PowerShell
Registros de errores.

Los cmdlets pueden llamar a System.Management.Automation.Cmdlet.WriteError según


sea necesario desde sus métodos de procesamiento de entrada. Sin embargo, los
cmdlets solo pueden llamar a System.Management.Automation.Cmdlet.WriteError desde
el subproceso que llamó al método de procesamiento de entrada
System.Management.Automation.Cmdlet.BeginProcessing,
System.Management.Automation.Cmdlet.ProcessRecordo
System.Management.Automation.Cmdlet.EndProcessing. No llame a
System.Management.Automation.Cmdlet.WriteError desde otro subproceso. En su lugar,
comunique los errores al subproceso principal.

Consulte también
System.Management.Automation.Cmdlet.WriteError

System.Management.Automation.Cmdlet.BeginProcessing

System.Management.Automation.Cmdlet.ProcessRecord

System.Management.Automation.Cmdlet.EndProcessing

Registros de errores de Windows PowerShell

Escribir un cmdlet de Windows PowerShell


Muestra de información del error
Artículo • 27/09/2021

En este tema se de analizan las formas en que los usuarios pueden mostrar información
de error.

Cuando el cmdlet encuentra un error, la presentación de la información de error será, de


forma predeterminada, similar a la siguiente salida de error.

PowerShell

$ stop-service lanmanworkstation
You do not have sufficient permissions to stop the service Workstation.

Sin embargo, los usuarios pueden ver los errores por categoría estableciendo la
$ErrorView variable en "CategoryView" . La vista de categorías muestra información
específica del registro de errores en lugar de una descripción de texto libre del error.
Esta vista puede ser útil si tiene una larga lista de errores para examinar. En la vista de
categorías, el mensaje de error anterior se muestra como se indica a continuación.

PowerShell

$ $ErrorView = "CategoryView"
$ stop-service lanmanworkstation
CloseError: (System.ServiceProcess.ServiceController:ServiceController)
[stop-service], ServiceCommandException

Para obtener más información sobre las categorías de error, vea Windows PowerShell
Registros de errores.

Consulte también
Registros de errores de Windows PowerShell

Escribir un cmdlet de Windows PowerShell


Registros de errores de Windows
PowerShell
Artículo • 24/09/2021

Los cmdlets deben pasar un objeto System.Management.Automation.ErrorRecord que


identifique la condición de error para los errores de terminación y no terminación.

El objeto System.Management.Automation.ErrorRecord contiene la siguiente


información:

Excepción que describe el error. A menudo, se trata de una excepción que el


cmdlet ha capturado y convertido en un registro de errores. Cada registro de error
debe contener una excepción.

Si el cmdlet no ha detecta una excepción, debe crear una nueva excepción y elegir la
clase de excepción que mejor describa la condición de error. Sin embargo, no es
necesario iniciar la excepción porque se puede acceder a ella a través de la propiedad
System.Management.Automation.ErrorRecord.Exception del objeto
System.Management.Automation.ErrorRecord.

Identificador de error que proporciona un designador de destino que se puede


usar con fines de diagnóstico y Windows PowerShell para controlar condiciones de
error específicas con controladores de errores específicos. Cada registro de error
debe contener un identificador de error (vea Identificador de error).

Categoría de error que proporciona un designador general que se puede usar con
fines de diagnóstico. Cada registro de error debe especificar una categoría de error
(vea Categoría de error).

Un mensaje de error de reemplazo opcional y una acción recomendada (vea


Mensaje de error de reemplazo).

Información de invocación opcional sobre el cmdlet que produjo el error. Esta


información se especifica mediante Windows PowerShell (vea Mensaje de
invocación).

Objeto de destino que se estaba procesando cuando se produjo el error. Podría ser
el objeto de entrada o podría ser otro objeto que el cmdlet estaba procesando. Por
ejemplo, para el comando , el error podría ser una instancia de un objeto remove-
item -recurse c:\somedirectory FileInfo para "c:\somedirectory\lockedfile". La
información del objeto de destino es opcional.
Identificador de error
Cuando cree un registro de error, especifique un identificador que designe la condición
de error dentro del cmdlet. Windows PowerShell combina el identificador de destino
con el nombre del cmdlet para crear un identificador de error completo. Se puede
acceder al identificador de error completo a través de la propiedad
System.Management.Automation.ErrorRecord.FullyQualifiedErrorId del objeto
System.Management.Automation.ErrorRecord. El identificador de error no está
disponible por sí mismo. Solo está disponible como parte del identificador de error
completo.

Use las siguientes directrices para generar identificadores de error al crear registros de
error:

Hacer que los identificadores de error son específicos de una condición de error.
Dirigirse a los identificadores de error con fines de diagnóstico y para scripts que
controlan condiciones de error específicas con controladores de errores
específicos. Un usuario debe poder usar el identificador de error para identificar el
error y su origen. Los identificadores de error también habilitan la generación de
informes para condiciones de error específicas de las excepciones existentes para
que no se requieran nuevas subclases de excepción.

En general, asigne identificadores de error diferentes a distintas rutas de acceso de


código. El usuario final se beneficia de identificadores específicos. A menudo, cada
ruta de acceso de código que llama a
System.Management.Automation.Cmdlet.WriteError o
System.Management.Automation.Cmdlet.Throwterminatingerror* tiene su propio
identificador. Como regla general, defina un nuevo identificador al definir una
nueva cadena de plantilla para el mensaje de error y viceversa. No use el mensaje
de error como identificador.

Al publicar código mediante un identificador de error determinado, se establece la


semántica de errores con ese identificador para el ciclo de vida completo del
soporte técnico del producto. No lo reutilice en un contexto que sea
semánticamente diferente del contexto original. Si cambia la semántica de este
error, cree y use un nuevo identificador.

Por lo general, debe usar un identificador de error determinado solo para las
excepciones de un tipo CLR determinado. Si cambia el tipo de la excepción o el
tipo del objeto de destino, cree y use un nuevo identificador.

Elija texto para el identificador de error que se corresponda de forma concisa con
el error que está informando. Use convenciones .NET Framework nomenclatura y
uso de mayúsculas y respuestas estándar. No use espacios en blanco ni signos de
puntuación. No localice identificadores de error.

No genere dinámicamente identificadores de error de una manera no


reproducible. Por ejemplo, no incorpore información de error, como un
identificador de proceso. Los identificadores de error solo son útiles si se
corresponden con los identificadores de error que ven otros usuarios que
experimentan la misma condición de error.

Categoría del error


Cuando cree un registro de error, especifique la categoría del error mediante una de las
constantes definidas por la enumeración
System.Management.Automation.ErrorCategory. Windows PowerShell utiliza la categoría
de error para mostrar información de error cuando los usuarios establecen la
$ErrorView variable en "CategoryView" .

Evite usar la constante System.Management.Automation.ErrorCategory NotSpecified. Si


tiene información sobre el error o sobre la operación que produjo el error, elija la
categoría que mejor describa el error o la operación, incluso si la categoría no es una
coincidencia perfecta.

La información mostrada por Windows PowerShell se conoce como cadena de vista de


categoría y se genera a partir de las propiedades de la clase
System.Management.Automation.Errorcategoryinfo. (Se tiene acceso a esta clase a
través de la propiedad System.Management.Automation.ErrorRecord.CategoryInfo de
error).

{Category}: ({TargetName}:{TargetType}):[{Activity}], {Reason}

En la lista siguiente se describe la información que se muestra:

Categoría: constante System.Management.Automation.ErrorCategory Windows


PowerShell definida por el usuario.

TargetName: de forma predeterminada, el nombre del objeto que el cmdlet estaba


procesando cuando se produjo el error. O bien, otra cadena definida por el cmdlet.

TargetType: de forma predeterminada, el tipo del objeto de destino. O bien, otra


cadena definida por el cmdlet.
Actividad: de forma predeterminada, el nombre del cmdlet que creó el registro de
errores. O bien, alguna otra cadena definida por el cmdlet.

Motivo: de forma predeterminada, el tipo de excepción. O bien, otra cadena


definida por el cmdlet.

Mensaje de error de reemplazo


Al desarrollar un registro de error para un cmdlet, el mensaje de error predeterminado
del error procede del texto del mensaje predeterminado en la propiedad
System.Exception.Message. Se trata de una propiedad de solo lectura cuyo texto del
mensaje está pensado solo para fines de depuración (según las .NET Framework
instrucciones). Se recomienda crear un mensaje de error que reemplace o aumente el
texto predeterminado del mensaje. Haga que el mensaje sea más fácil de usar y más
específico para el cmdlet.

Un objeto System.Management.Automation.ErrorDetails proporciona el mensaje de


reemplazo. Use uno de los constructores siguientes de este objeto porque proporcionan
información de localización adicional que puede usar Windows PowerShell.

ErrorDetails(Cmdlet, String, String, Object[]):use este constructor si la cadena de


plantilla es una cadena de recursos en el mismo ensamblado en el que se
implementa el cmdlet o si desea cargar la cadena de plantilla mediante una
invalidación del método
System.Management.Automation.Cmdlet.GetResourceString.

ErrorDetails(Assembly, String, String, Object[]):use este constructor si la cadena de


plantilla está en otro ensamblado y no la carga a través de una invalidación de
System.Management.Automation.Cmdlet.GetResourceString.

El mensaje de reemplazo debe cumplir las .NET Framework de diseño para escribir
mensajes de excepción con una pequeña diferencia. En las instrucciones se dice que los
mensajes de excepción deben escribirse para los desarrolladores. Estos mensajes de
reemplazo deben escribirse para el usuario del cmdlet.

El mensaje de error de reemplazo debe agregarse antes de llamar a los métodos


System.Management.Automation.Cmdlet.WriteError o
System.Management.Automation.Cmdlet.Throwterminatingerror*. Para agregar un
mensaje de reemplazo, establezca la propiedad
System.Management.Automation.ErrorRecord.ErrorDetails del registro de errores.
Cuando se establece esta propiedad, Windows PowerShell muestra la propiedad
System.Management.Automation.ErrorDetails.Message* en lugar del texto del mensaje
predeterminado.

Información de acción recomendada


El objeto System.Management.Automation.ErrorDetails también puede proporcionar
información sobre las acciones que se recomiendan cuando se produce el error.

Información de invocación
Cuando un cmdlet usa System.Management.Automation.Cmdlet.WriteError o
System.Management.Automation.Cmdlet.Throwterminatingerror* para notificar un
registro de error, Windows PowerShell agrega automáticamente información que
describe el comando que se invocó cuando se produjo el error. Esta información la
proporciona un objeto System.Management.Automation.Invocationinfo que contiene el
nombre del cmdlet invocado por el comando, el propio comando e información sobre la
canalización o el script. Esta propiedad es de solo lectura.

Consulte también
System.Management.Automation.Cmdlet.WriteError

System.Management.Automation.Cmdlet.Throwterminatingerror*

System.Management.Automation.ErrorCategory

System.Management.Automation.Errorcategoryinfo

System.Management.Automation.ErrorRecord

System.Management.Automation.ErrorDetails

System.Management.Automation.Invocationinfo

Informes de errores de Windows PowerShell

Escribir un cmdlet de Windows PowerShell


Interpretación de los objetos
ErrorRecord
Artículo • 27/09/2021

En la mayoría de los casos, un objeto System.Management.Automation.ErrorRecord


representa un error de no terminación generado por un comando o script. Los errores
de terminación también pueden especificar la información adicional de un ErrorRecord a
través de la interfaz System.Management.Automation.Icontainserrorrecord.

Si desea escribir un controlador de errores en el script o un host para controlar errores


específicos que se producen durante la ejecución de comandos o scripts, debe
interpretar el objeto System.Management.Automation.ErrorRecord para determinar si
representa la clase de error que desea controlar.

Cuando un cmdlet encuentra un error de terminación o no terminación, debe crear un


registro de error que describa la condición de error. La aplicación host debe investigar
estos registros de errores y realizar cualquier acción que mitigue el error. La aplicación
host también debe investigar los registros de errores no terminales que no pudieron
procesar un registro pero pudieron continuar, y debe investigar los registros de errores
para terminar los errores que provocaron la detenerse la canalización.

7 Nota

Para terminar los errores, el cmdlet llama al método


System.Management.Automation.Cmdlet.Throwterminatingerror*. Para los
errores de no terminación, el cmdlet llama al método
System.Management.Automation.Cmdlet.WriteError.

Diseño de registros de errores


Los registros de errores están diseñados para proporcionar información de error
adicional que no está disponible en las excepciones, al tiempo que se garantiza que la
información combinada de cada registro de error es única. Esta unidad permite a la
aplicación host inspeccionar las distintas partes del registro de errores para que pueda
identificar la condición de error y la acción que debe realizar el host.

Interpretación de registros de errores


Puede revisar varias partes del registro de errores para identificar el error. Estas partes
incluyen lo siguiente:

Categoría de error

Excepción de error

Identificador de error completo (FQID)

Otra información

Categoría de error
La categoría de error del registro de errores es una de las constantes predefinidas
proporcionadas por la enumeración System.Management.Automation.Errorcategory.
Esta información está disponible a través de la propiedad
System.Management.Automation.ErrorRecord.CategoryInfo del objeto
System.Management.Automation.ErrorRecord.

El cmdlet puede especificar las categorías CloseError, OpenError, InvalidType, ReadError


y WriteError, y otras categorías de error. La aplicación host puede usar la categoría de
errores para capturar grupos de errores.

Excepción
El cmdlet proporciona la excepción incluida en el registro de errores y se puede acceder
a la excepción a través de la propiedad
System.Management.Automation.ErrorRecord.Exception* del objeto
System.Management.Automation.ErrorRecord.

Las aplicaciones host pueden usar la palabra clave para identificar que la excepción es
is de una clase específica o de una clase derivada. Es mejor bifurcar en el tipo de

excepción, como se muestra en el ejemplo siguiente.

if (MyNonTerminatingError.Exception is AccessDeniedException)

De este modo, se detectan las clases derivadas. Sin embargo, hay problemas si se
deserializa la excepción.

The FQID
FQID es la información más específica que puede usar para identificar el error. Es una
cadena que incluye un identificador definido por el cmdlet, el nombre de la clase de
cmdlet y el origen que informó del error. En general, un registro de errores es análogo a
un registro de eventos de un Windows de eventos. El FQID es análogo a la siguiente
tupla, que identifica la clase del registro de eventos:( nombre de registro , origen ,
identificador de evento).

El FQID está diseñado para inspeccionarse como una sola cadena. Sin embargo, existen
casos en los que el identificador de error está diseñado para que lo analice la aplicación
host. El ejemplo siguiente es un identificador de error completo con el formato correcto.

CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand.

En el ejemplo anterior, el primer token es el identificador de error, que va seguido del


nombre de la clase de cmdlet. El identificador de error puede ser un token único o
puede ser un identificador separado por puntos que permite bifurcar al inspeccionar el
identificador. No use espacios en blanco ni signos de puntuación en el identificador de
error. Es especialmente importante no usar una coma; usa una coma para separar
Windows PowerShell identificador y el nombre de la clase de cmdlet.

Otra información
El objeto System.Management.Automation.ErrorRecord también podría proporcionar
información que describa el entorno en el que se produjo el error. Esta información
incluye elementos como detalles del error, información de invocación y el objeto de
destino que se estaba procesando cuando se produjo el error. Aunque esta información
puede ser útil para la aplicación host, normalmente no se usa para identificar el error.
Esta información está disponible a través de las siguientes propiedades:

System.Management.Automation.ErrorRecord.ErrorDetails

System.Management.Automation.ErrorRecord.InvocationInfo

System.Management.Automation.ErrorRecord.TargetObject

Consulte también
System.Management.Automation.ErrorRecord

System.Management.Automation.Errorcategory

System.Management.Automation.Errorcategoryinfo

System.Management.Automation.Cmdlet.WriteError

System.Management.Automation.Cmdlet.Throwterminatingerror*
Adición de informes de errores de no terminación al cmdlet

Informes de errores de Windows PowerShell

Escribir un cmdlet de Windows PowerShell


Trabajos en segundo plano
Artículo • 24/09/2021

Los cmdlets pueden realizar su acción internamente o como un Windows PowerShell en


segundo plano. Cuando un cmdlet se ejecuta como un trabajo en segundo plano, el
trabajo se realiza de forma asincrónica en su propio subproceso independiente del
subproceso de canalización que usa el cmdlet. Desde la perspectiva del usuario, cuando
un cmdlet se ejecuta como un trabajo en segundo plano, el símbolo del sistema se
devuelve inmediatamente incluso si el trabajo tarda mucho tiempo en completarse y el
usuario puede continuar sin interrupción mientras se ejecuta el trabajo.

Trabajos en segundo plano, trabajos


secundarios y el repositorio de trabajos
El objeto de trabajo devuelto por los cmdlets que admiten trabajos en segundo plano
define el trabajo. (El cmdlet Start-Job también devuelve un objeto de trabajo). El nombre
del trabajo, un identificador que se usa para especificar el trabajo, la información de
estado y los trabajos secundarios se incluyen en esta definición. El trabajo no realiza
ninguna de las tareas. Cada trabajo en segundo plano tiene al menos un trabajo
secundario porque el trabajo secundario realiza el trabajo real. Al ejecutar un cmdlet
para que el trabajo se realice como un trabajo en segundo plano, el cmdlet debe
agregar el trabajo y los trabajos secundarios a un repositorio común, denominado
repositorio de trabajos.

Para obtener más información sobre cómo se controlan los trabajos en segundo plano
en la línea de comandos, vea lo siguiente:

about_Jobs

about_Job_Details

about_Remote_Jobs

Escritura de un cmdlet que se ejecuta como un


trabajo en segundo plano
Para escribir un cmdlet que se pueda ejecutar como un trabajo en segundo plano, debe
completar las siguientes tareas:
Defina un asJob parámetro switch para que el usuario pueda decidir si desea
ejecutar el cmdlet como un trabajo en segundo plano.

Cree un objeto que se derive de la clase System.Management.Automation.Job. Este


objeto puede ser un objeto de trabajo personalizado o un objeto de trabajo
proporcionado por Windows PowerShell, como un objeto
System.Management.Automation.Pseventjob.

En un método de procesamiento de registros, agregue una if instrucción que


detecte si el cmdlet debe ejecutarse como un trabajo en segundo plano.

Para los objetos de trabajo personalizados, implemente la clase de trabajo .

Devuelve los objetos adecuados, dependiendo de si el cmdlet se ejecuta como un


trabajo en segundo plano.

Para obtener un ejemplo de código, vea Cómo admitir trabajos.

API de Job-Related en segundo plano


Las siguientes API se proporcionan mediante Windows PowerShell para administrar
trabajos en segundo plano.

System.Management.Automation.Job Deriva objetos de trabajo personalizados. Esta es


una clase abstracta.

System.Management.Automation.Jobrepository administra y proporciona información


sobre los trabajos en segundo plano activos actuales.

System.Management.Automation.Jobstate Define el estado del trabajo en segundo


plano. Entre los estados se incluyen Iniciado, En ejecución y Detenido.

System.Management.Automation.Jobstateinfo Proporciona información sobre el estado


de un trabajo en segundo plano y, si el último cambio de estado se produjo por un
error, el motivo por el que el trabajo entró en su estado actual.

System.Management.Automation.Jobstateeventargs Proporciona los argumentos para


un evento que se genera cuando un trabajo en segundo plano cambia de estado.

Windows PowerShell Cmdlets de trabajo


Los siguientes cmdlets los proporciona Windows PowerShell para administrar trabajos
en segundo plano.
Get-Job

Obtiene los trabajos en segundo plano de Windows PowerShell que se están ejecutando
en la sesión actual.

Receive-Job

Obtiene los resultados de los trabajos en segundo plano de Windows PowerShell en la


sesión actual.

Remove-Job

Elimina un trabajo en segundo plano de Windows PowerShell.

Start-Job

Inicia un trabajo en segundo plano de Windows PowerShell.

Stop-Job

Detiene un trabajo en segundo plano de Windows PowerShell.

Wait-Job

Suprime el símbolo del sistema hasta que finalicen uno o todos los trabajos en segundo
plano de Windows PowerShell que se ejecutan en la sesión.

Vea también
Escribir un cmdlet de Windows PowerShell
Invocación de los cmdlets y los scripts
dentro de un cmdlet
Artículo • 27/09/2021

Un cmdlet puede invocar otros cmdlets y scripts desde el método de procesamiento de


entrada del cmdlet. Esto le permite agregar la funcionalidad de los cmdlets y scripts
existentes al cmdlet sin tener que volver a escribir el código.

Método Invoke
Todos los cmdlets pueden invocar un cmdlet existente llamando al método
System.Management.Automation.Cmdlet.Invoke desde un método de procesamiento de
entrada, como System.Management.Automation.Cmdlet.BeginProcessing, que el cmdlet
invalida. Sin embargo, solo puede invocar los cmdlets que derivan directamente de la
clase System.Management.Automation.Cmdlet. No se puede invocar un cmdlet que
derive de la clase System.Management.Automation.PSCmdlet.

El método System.Management.Automation.Cmdlet.Invoke* tiene las siguientes


variantes.

System.Management.Automation.Cmdlet.Invoke Esta variante invoca el objeto de


cmdlet y devuelve una colección de objetos de tipo "T".

System.Management.Automation.Cmdlet.Invoke Esta variante invoca el objeto de


cmdlet y devuelve un emumerator fuertemente con tipo. Esta variante permite al
usuario usar los objetos de la colección para realizar operaciones personalizadas.

Ejemplos
Ejemplo Descripción

Invocación de cmdlets En este ejemplo se muestra cómo invocar un cmdlet desde otro
dentro de un cmdlet cmdlet.

Invocación de scripts dentro En este ejemplo se muestra cómo invocar un script que se
de un cmdlet proporciona al cmdlet desde otro cmdlet.

Vea también
Escribir un cmdlet de Windows PowerShell
Conjuntos de cmdlets
Artículo • 27/09/2021

Al diseñar los cmdlets, es posible que encuentre casos en los que necesite realizar varias
acciones en el mismo fragmento de datos. Por ejemplo, es posible que tenga que
obtener y establecer datos o iniciar y detener un proceso. Aunque tendrá que crear
cmdlets independientes para realizar cada acción, el diseño del cmdlet debe incluir una
clase base de la que se derivan las clases de los cmdlets individuales.

Tenga en cuenta lo siguiente al implementar una clase base.

Declare los parámetros comunes utilizados por todos los cmdlets derivados de la
clase base.

Agregue parámetros específicos del cmdlet a la clase de cmdlet adecuada.

Invalide el método de procesamiento de entrada adecuado en la clase base.

Declare el atributo System.Management.Automation.CmdletAttribute en todas las


clases de cmdlet, pero no lo declare en la clase base.

Implemente una clase System.Management.Automation.PSSnapIn o


System.Management.Automation.Custompssnapin cuyo nombre y descripción
reflejen el conjunto de cmdlets.

Ejemplo
En el ejemplo siguiente se muestra la implementación de una clase base que Get-Proc y
un cmdlet Stop-Proc que derivan de la misma clase base.

C#

using System;
using System.Diagnostics;
using System.Management.Automation; //Windows PowerShell
namespace.

namespace Microsoft.Samples.PowerShell.Commands
{

#region ProcessCommands

/// <summary>
/// This class implements a Stop-Proc cmdlet. The parameters
/// for this cmdlet are defined by the BaseProcCommand class.
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc", SupportsShouldProcess = true)]
public class StopProcCommand : BaseProcCommand
{
public override void ProcessObject(Process process)
{
if (ShouldProcess(process.ProcessName, "Stop-Proc"))
{
process.Kill();
}
}
}

/// <summary>
/// This class implements a Get-Proc cmdlet. The parameters
/// for this cmdlet are defined by the BaseProcCommand class.
/// </summary>

[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : BaseProcCommand
{
public override void ProcessObject(Process process)
{
WriteObject(process);
}
}

/// <summary>
/// This class is the base class that defines the common
/// functionality used by the Get-Proc and Stop-Proc
/// cmdlets.
/// </summary>
public class BaseProcCommand : Cmdlet
{
#region Parameters

// Defines the Name parameter that is used to


// specify a process by its name.
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

// Defines the Exclude parameter that is used to


// specify which processes should be excluded when
// the cmdlet performs its action.
[Parameter()]
public string[] Exclude
{
get { return excludeNames; }
set { excludeNames = value; }
}
private string[] excludeNames = new string[0];
#endregion Parameters

public virtual void ProcessObject(Process process)


{
throw new NotImplementedException("This method should be
overridden.");
}

#region Cmdlet Overrides


// <summary>
// For each of the requested process names, retrieve and write
// the associated processes.
// </summary>
protected override void ProcessRecord()
{
// Set up the wildcard characters used in resolving
// the process names.
WildcardOptions options = WildcardOptions.IgnoreCase |
WildcardOptions.Compiled;

WildcardPattern[] include = new WildcardPattern[Name.Length];


for (int i = 0; i < Name.Length; i++)
{
include[i] = new WildcardPattern(Name[i], options);
}

WildcardPattern[] exclude = new WildcardPattern[Exclude.Length];


for (int i = 0; i < Exclude.Length; i++)
{
exclude[i] = new WildcardPattern(Exclude[i], options);
}

foreach (Process p in Process.GetProcesses())


{
foreach (WildcardPattern wIn in include)
{
if (wIn.IsMatch(p.ProcessName))
{
bool processThisOne = true;
foreach (WildcardPattern wOut in exclude)
{
if (wOut.IsMatch(p.ProcessName))
{
processThisOne = false;
break;
}
}
if (processThisOne)
{
ProcessObject(p);
}
break;
}
}
}
}
#endregion Cmdlet Overrides
}
#endregion ProcessCommands
}

Vea también
Escribir un cmdlet de Windows PowerShell
Estado de sesión de Windows
PowerShell
Artículo • 24/09/2021

El estado de sesión hace referencia a la configuración actual de una Windows


PowerShell o módulo. Una Windows PowerShell sesión es el entorno operativo que usa
interactivamente el usuario de la línea de comandos o mediante programación por una
aplicación host. El estado de sesión de una sesión se conoce como estado de sesión
global.

Desde la perspectiva del desarrollador, Windows PowerShell sesión hace referencia al


tiempo entre el momento en que una aplicación host abre un espacio de ejecución de
Windows PowerShell y el momento en que cierra el espacio de ejecución. De otro modo,
la sesión es la duración de una instancia del motor de Windows PowerShell que se
invoca mientras existe el espacio de ejecución.

Estado de sesión del módulo


Los estados de sesión del módulo se crean cada vez que se importa el módulo o uno de
sus módulos anidados en la sesión. Cuando un módulo exporta un elemento como un
cmdlet, una función o un script, se agrega una referencia a ese elemento al estado de
sesión global de la sesión. Sin embargo, cuando se ejecuta el elemento, se ejecuta
dentro del estado de sesión del módulo.

Session-State Data
Los datos de estado de sesión pueden ser públicos o privados. Los datos públicos están
disponibles para las llamadas desde fuera del estado de sesión, mientras que los datos
privados solo están disponibles para las llamadas desde dentro del estado de sesión.
Por ejemplo, un módulo puede tener una función privada a la que solo puede llamar el
módulo o solo internamente un elemento público que se haya exportado. Esto es similar
a los miembros privados y públicos de un .NET Framework de trabajo.

La instancia actual del motor de ejecución almacena los datos de estado de sesión en el
contexto de la sesión Windows PowerShell actual. Los datos de estado de sesión
constan de los siguientes elementos:

Información de ruta de acceso

Información de unidad
Windows PowerShell del proveedor

Información sobre los módulos importados y referencias a los elementos del


módulo (como cmdlets, funciones y scripts) que exporta el módulo. Esta
información y estas referencias son solo para el estado de sesión global.

Información de variables de estado de sesión

Acceso a Session-State datos en cmdlets


Los cmdlets pueden acceder a los datos de estado de sesión indirectamente a través de
la propiedad System.Management.Automation.PSCmdlet.Sessionstate* de la clase de
cmdlet o directamente a través de la clase
System.Management.Automation.Sessionstate. La clase
System.Management.Automation.Sessionstate proporciona propiedades que se pueden
usar para investigar diferentes tipos de datos de estado de sesión.

Consulte también
System.Management.Automation.PSCmdlet.Sessionstate

¿System.Management.Automation.Sessionstate? Displayproperty=Fullname

Cmdlets de Windows PowerShell

Escribir un cmdlet de Windows PowerShell

SDK del shell de Windows PowerShell


Ejemplos de código del cmdlet
Artículo • 27/09/2021

Esta sección contiene ejemplos de código de cmdlet que puede usar para empezar a
escribir sus propios cmdlets.

) Importante

Si desea obtener instrucciones paso a paso para escribir cmdlets, consulte


Tutoriales para escribir cmdlets.

En esta sección
Cómo escribir un cmdlet simple En este ejemplo se muestra la estructura básica del
código del cmdlet.

Cómo declarar parámetros de cmdlet En este ejemplo se muestra cómo declarar los
distintos tipos de parámetros.

Cómo declarar conjuntos de parámetros En este ejemplo se muestra cómo declarar


conjuntos de parámetros que pueden cambiar la acción que realiza un cmdlet.

Cómo validar la entrada de parámetros En estos ejemplos se muestra cómo validar la


entrada de parámetros.

Cómo declarar parámetros dinámicos En este ejemplo se muestra cómo declarar un


parámetro que se agrega en tiempo de ejecución.

Cómo invocar scripts dentro de un cmdlet En este ejemplo se muestra cómo invocar un
script que se proporciona a un cmdlet.

Cómo invalidar métodos de procesamiento de entrada En estos ejemplos se muestra la


estructura básica utilizada para invalidar los métodos BeginProcessing, ProcessRecord y
EndProcessing.

Cómo admitir llamadas ShouldProcess En este ejemplo se muestra cómo se debe llamar
a los métodos System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue desde un cmdlet.

Cómo admitir transacciones En este ejemplo se muestra cómo indicar que el cmdlet
admite transacciones y cómo implementar la acción que se toma cuando se usa el
cmdlet dentro de una transacción.
Cómo admitir trabajos En este ejemplo se muestra cómo admitir trabajos al escribir
cmdlets.

Cómo invocar un cmdlet desde dentro de un cmdlet En este ejemplo se muestra cómo
invocar un cmdlet desde otro cmdlet, lo que le permite agregar la funcionalidad del
cmdlet invocado al cmdlet que está desarrollando.

Vea también
Escribir un cmdlet de Windows PowerShell
Escritura de un cmdlet
Artículo • 27/09/2021

En este artículo se muestra cómo escribir un cmdlet. El cmdlet toma un nombre de


usuario único como entrada y, Send-Greeting a continuación, escribe un saludo a ese
usuario. Aunque el cmdlet no hace mucho trabajo, en este ejemplo se muestran las
secciones principales de un cmdlet.

Pasos para escribir un cmdlet


1. Para declarar la clase como un cmdlet, use el atributo Cmdlet. El atributo Cmdlet
especifica el verbo y el nombre del nombre del cmdlet.

Para obtener más información sobre el atributo Cmdlet, vea CmdletAttribute


Declaration.

2. Especifique el nombre de la clase.

3. Especifique que el cmdlet se deriva de cualquiera de las clases siguientes:

System.Management.Automation.Cmdlet
System.Management.Automation.PSCmdlet

4. Para definir los parámetros del cmdlet, use el atributo Parameter. En este caso,
solo se especifica un parámetro necesario.

Para obtener más información sobre el atributo Parameter, vea ParameterAttribute


Declaration.

5. Invalide el método de procesamiento de entrada que procesa la entrada. En este


caso, se invalida el método
System.Management.Automation.Cmdlet.ProcessRecord.

6. Para escribir el saludo, use el método


System.Management.Automation.Cmdlet.WriteObject. El saludo se muestra en el
formato siguiente:

Output

Hello <UserName>!
Ejemplo
C#

using System.Management.Automation; // Windows PowerShell assembly.

namespace SendGreeting
{
// Declare the class as a cmdlet and specify the
// appropriate verb and noun for the cmdlet name.
[Cmdlet(VerbsCommunications.Send, "Greeting")]
public class SendGreetingCommand : Cmdlet
{
// Declare the parameters for the cmdlet.
[Parameter(Mandatory=true)]
public string Name
{
get { return name; }
set { name = value; }
}
private string name;

// Override the ProcessRecord method to process


// the supplied user name and write out a
// greeting to the user by calling the WriteObject
// method.
protected override void ProcessRecord()
{
WriteObject("Hello " + name + "!");
}
}
}

Consulte también
System.Management.Automation.Cmdlet

System.Management.Automation.PSCmdlet

System.Management.Automation.Cmdlet.ProcessRecord

System.Management.Automation.Cmdlet.WriteObject

Declaración de CmdletAttribute

Declaración de ParameterAttribute

Escribir un cmdlet de Windows PowerShell


Cómo declarar los parámetros del
cmdlet
Artículo • 24/09/2021

En estos ejemplos se muestra cómo declarar parámetros con nombre, posicionales,


obligatorios, opcionales y modificadores. En estos ejemplos también se muestra cómo
definir un alias de parámetro.

Cómo declarar un parámetro con nombre


Defina una propiedad pública como se muestra en el código siguiente. Al agregar
el atributo Parameter, omita la Position palabra clave del atributo .

C#

[Parameter()]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Para obtener más información sobre el atributo Parameter, vea Declaración de atributo
de parámetro.

Cómo declarar un parámetro posicional


Defina una propiedad pública como se muestra en el código siguiente. Al agregar
el atributo Parameter, establezca la palabra Position clave en la posición del
argumento. Un valor de 0 indica la primera posición.

C#

[Parameter(Position = 0)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;
Para obtener más información sobre el atributo Parameter, vea Declaración de atributo
de parámetro.

Cómo declarar un parámetro obligatorio


Defina una propiedad pública como se muestra en el código siguiente. Al agregar
el atributo Parameter, establezca la Mandatory palabra clave en true .

C#

[Parameter(Position = 0, Mandatory = true)]


public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Para obtener más información sobre el atributo Parameter, vea Declaración de atributo
de parámetro.

Cómo declarar un parámetro opcional


Defina una propiedad pública como se muestra en el código siguiente. Al agregar
el atributo Parameter, omita la palabra Mandatory clave .

C#

[Parameter(Position = 0)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Cómo declarar un parámetro Switch


Defina una propiedad pública como de tipo
System.Management.Automation.SwitchParametery, a continuación, declare el
atributo Parameter.

C#
[Parameter(Position = 1)]
public SwitchParameter GoodBye
{
get { return goodbye; }
set { goodbye = value; }
}
private bool goodbye;

Para obtener más información sobre el atributo Parameter, vea Declaración de atributo
de parámetro.

Cómo declarar un parámetro con alias


Defina una propiedad pública como se muestra en el código siguiente. Agregue un
atributo Alias que enumera los alias del parámetro. En este ejemplo, se definen
tres alias para el mismo parámetro. El primer alias proporciona un acceso directo.
El segundo y el tercer alias proporcionan nombres que puede usar para distintos
escenarios.

C#

[Alias("UN","Writer","Editor")]
[Parameter()]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Para obtener más información sobre el atributo Alias, vea Declaración de atributo de
alias.

Consulte también
System.Management.Automation.SwitchParameter

Declaración de atributo de parámetro

Declaración de atributo de alias

Escribir un cmdlet de Windows PowerShell


Cómo declarar los conjuntos de
parámetros
Artículo • 24/09/2021

En este ejemplo se muestra cómo definir dos conjuntos de parámetros al declarar los
parámetros de un cmdlet. Cada conjunto de parámetros tiene un parámetro único y un
parámetro compartido que usan ambos conjuntos de parámetros. Para obtener más
información sobre los conjuntos de parámetros, incluido cómo especificar el conjunto
de parámetros predeterminado, vea Cmdlet Parameter Sets.

) Importante

Siempre que sea posible, defina el parámetro único de un conjunto de parámetros


como un parámetro necesario. Sin embargo, si desea que el cmdlet se ejecute sin
especificar ningún parámetro, el parámetro único puede ser un parámetro
opcional. Por ejemplo, el parámetro único del Get-Command cmdlet es opcional.

Definición de dos conjuntos de parámetros


1. Agregue la ParameterSet palabra clave al atributo Parameter para el parámetro
único del primer conjunto de parámetros.

C#

[Parameter(Position = 0, Mandatory = true,


ParameterSetName = "Test01")]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

2. Agregue la ParameterSet palabra clave al atributo Parameter para el parámetro


único del segundo conjunto de parámetros.

C#

[Parameter(Position = 0, Mandatory = true,


ParameterSetName = "Test02")]
public string ComputerName
{
get { return computerName; }
set { computerName = value; }
}
private string computerName;

3. Para el parámetro que pertenece a ambos conjuntos de parámetros, agregue un


atributo Parameter para cada conjunto de parámetros y, a continuación, agregue la
ParameterSet palabra clave a cada conjunto. En cada atributo Parameter, puede

especificar cómo se define ese parámetro. Un parámetro puede ser opcional en un


conjunto y obligatorio en otro.

C#

[Parameter(Mandatory= true, ParameterSetName = "Test01")]


[Parameter(ParameterSetName = "Test02")]
public string SharedParam
{
get { return sharedParam; }
set { sharedParam = value; }
}
private string sharedParam;

Consulte también
Conjuntos de parámetros del cmdlet

Escribir un cmdlet de Windows PowerShell


Cómo validar la entrada de parámetros
Artículo • 27/09/2021

Esta sección contiene ejemplos que muestran cómo validar la entrada de parámetros
mediante el uso de varios atributos para implementar reglas de validación.

En esta sección
Cómo validar un argumento con un script Describe cómo validar un conjunto de
argumentos mediante el atributo ArgumentSet.

Cómo validar un conjunto de argumentos Describe cómo validar un conjunto de


argumentos mediante el atributo ArgumentSet.

Cómo validar un intervalo de argumentos Describe cómo validar un intervalo de


argumentos mediante el atributo ArgumentRange.

Cómo validar un patrón de argumento Describe cómo validar un patrón de argumento


mediante el atributo ArgumentPattern.

Cómo validar la longitud del argumento Describe cómo validar la longitud de un


argumento mediante el atributo ArgumentLength.

Cómo validar un recuento de argumentos Describe cómo validar un recuento de


argumentos mediante el atributo ArgumentCount.

La forma en que se declara un parámetro puede afectar a la validación. Para obtener


más información, vea How to Declare Cmdlet Parameters.

Referencia

Vea también
Escribir un cmdlet de Windows PowerShell
Validación de un argumento mediante
un script
Artículo • 01/03/2022

En este ejemplo se muestra cómo especificar una regla de validación que usa un script
para comprobar el argumento de parámetro antes de ejecutar el cmdlet. El valor del
parámetro se canalizará al script. El script debe devolver por $true cada valor canaldo a
él.

7 Nota

Para obtener más información sobre la clase que define este atributo, vea
System.Management.Automation.ValidateScriptAttribute.

Para validar un argumento mediante un script


Agregue el atributo ValidateScript como se muestra en el código siguiente. En este
ejemplo se especifica un conjunto de tres valores posibles para el UserName
parámetro .

C#

[ValidateScript("$_ % 2", ErrorMessage = "The item '{0}' did not pass


validation of script '{1}'")]
[Parameter(Position = 0, Mandatory = true)]
public int32 OddNumber
{
get { return oddNumber; }
set { oddNumber = value; }
}

private int32 oddNumber;

Para obtener más información sobre cómo declarar este atributo, vea ValidateScript
Attribute Declaration.

Consulte también
System.Management.Automation.ValidateScriptAttribute
Declaración de atributo ValidateScript

Escribir un cmdlet de Windows PowerShell


Cómo validar un conjunto de
argumentos
Artículo • 27/09/2021

En este ejemplo se muestra cómo especificar una regla de validación que Windows
PowerShell runtime puede usar para comprobar el argumento de parámetro antes de
ejecutar el cmdlet. Esta regla de validación proporciona un conjunto de los valores
válidos para el argumento de parámetro.

7 Nota

Para obtener más información sobre la clase que define este atributo, vea
System.Management.Automation.Validatesetattribute.

Para validar un conjunto de argumentos


Agregue el atributo ValidateSet como se muestra en el código siguiente. En este
ejemplo se especifica un conjunto de tres valores posibles para el UserName
parámetro .

C#

[ValidateSet("Steve", "Mary", "Carl", IgnoreCase = true)]


[Parameter(Position = 0, Mandatory = true)]
public string UserName
{
get { return userName; }
set { userName = value; }
}

private string userName;

Para obtener más información sobre cómo declarar este atributo, vea Declaración de
atributo ValidateSet.

Consulte también
System.Management.Automation.Validatesetattribute

Declaración de atributo ValidateSet


Escribir un cmdlet de Windows PowerShell
Cómo validar un rango de argumentos
Artículo • 27/09/2021

En este ejemplo se muestra cómo especificar una regla de validación que el tiempo de
ejecución de Windows PowerShell puede usar para comprobar los valores mínimo y
máximo del argumento de parámetro antes de ejecutar el cmdlet. Esta regla de
validación se establece declarando el atributo ValidateRange.

7 Nota

Para obtener más información sobre la clase que define este atributo, vea
System.Management.Automation.Validaterangeattribute.

Para validar un intervalo de argumentos


Agregue el atributo ValidateRange como se muestra en el código siguiente. En
este ejemplo se especifica un intervalo de 0 a 5 para el InputData parámetro .

C#

[ValidateRange(0, 5)]
[Parameter(Position = 0, Mandatory = true)]
public int InputData
{
get { return inputData; }
set { inputData = value; }
}
private int inputData;

Para obtener más información sobre cómo declarar este atributo, vea ValidateRange
Attribute Declaration.

Consulte también
Declaración de atributo ValidateRange

Escribir un cmdlet de Windows PowerShell


Cómo validar un patrón de argumentos
Artículo • 27/09/2021

En este ejemplo se muestra cómo especificar una regla de validación que el tiempo de
ejecución de Windows PowerShell puede usar para comprobar el patrón de caracteres
del argumento de parámetro antes de ejecutar el cmdlet. Esta regla de validación se
establece declarando el atributo ValidatePattern.

7 Nota

Para obtener más información sobre la clase que define este atributo, vea
System.Management.Automation.Validatepatternattribute.

Para validar un patrón de argumento


Agregue el atributo Validate como se muestra en el código siguiente. En este
ejemplo se especifica un patrón de cuatro dígitos, donde cada dígito tiene un valor
de 0 a 9.

C#

[ValidatePattern("[0-9][0-9][0-9][0-9]")]
[Parameter(Position = 0, Mandatory = true)]
public int InputData
{
get { return inputData; }
set { inputData = value; }
}

private int inputData;

Para obtener más información sobre cómo declarar este atributo, vea ValidatePattern
Attribute Declaration.

Consulte también
Declaración de atributo ValidatePattern

Escribir un cmdlet de Windows PowerShell


Cómo validar la longitud del argumento
Artículo • 27/09/2021

En este ejemplo se muestra cómo especificar una regla de validación que el tiempo de
ejecución de Windows PowerShell puede usar para comprobar el número de caracteres
(la longitud) del argumento de parámetro antes de ejecutar el cmdlet. Esta regla de
validación se establece declarando el atributo ValidateLength.

7 Nota

Para obtener más información sobre la clase que define este atributo, vea
System.Management.Automation.Validatelengthattribute.

Para validar la longitud del argumento


Agregue el atributo Validate como se muestra en el código siguiente. En este
ejemplo se especifica que la longitud del argumento debe tener una longitud de 0
a 10 caracteres.

C#

[ValidateLength(0, 10)]
[Parameter(Position = 0, Mandatory = true)]
public string UserName
{
get { return userName; }
set { userName = value; }
}
private string userName;

Para obtener más información sobre cómo declarar este atributo, vea ValidateLength
Attribute Declaration.

Consulte también
Declaración de atributo ValidateLength

Escribir un cmdlet de Windows PowerShell


Cómo validar un recuento de
argumentos
Artículo • 27/09/2021

En este ejemplo se muestra cómo especificar una regla de validación que el tiempo de
ejecución de Windows PowerShell puede usar para comprobar el número de
argumentos (el recuento) que acepta un parámetro antes de ejecutar el cmdlet. Esta
regla de validación se establece declarando el atributo ValidateCount.

7 Nota

Para obtener más información sobre la clase que define este atributo, vea
System.Management.Automation.Validatecountattribute.

Para validar un recuento de argumentos


Agregue el atributo Validate como se muestra en el código siguiente. En este
ejemplo se especifica que el parámetro aceptará un argumento o hasta tres
argumentos.

C#

[ValidateCount(1, 3)]
[Parameter(Position = 0, Mandatory = true)]
public string[] UserNames
{
get { return userNames; }
set { userNames = value; }
}

private string[] userNames;

Para obtener más información sobre cómo declarar este atributo, vea Declaración de
atributo ValidateCount.

Consulte también
Declaración de atributo ValidateCount

Escribir un cmdlet de Windows PowerShell


Cómo declarar los parámetros
dinámicos
Artículo • 27/09/2021

En este ejemplo se muestra cómo definir parámetros dinámicos que se agregan al


cmdlet en tiempo de ejecución. En este ejemplo, el Department parámetro se agrega al
cmdlet cada vez que el usuario especifica el parámetro Employee switch. Para obtener
más información sobre los parámetros dinámicos, vea Parámetros dinámicos del cmdlet.

Para definir parámetros dinámicos


1. En la declaración de clase de cmdlet, agregue la interfaz
System.Management.Automation.Idynamicparameters como se muestra.

C#

public class SendGreetingCommand : Cmdlet, IDynamicParameters

2. Llame al método
System.Management.Automation.Idynamicparameters.Getdynamicparameters*,
que devuelve el objeto en el que se definen los parámetros dinámicos. En este
ejemplo, se llama al método cuando Employee se especifica el parámetro .

C#

public object GetDynamicParameters()


{
if (employee)
{
context= new SendGreetingCommandDynamicParameters();
return context;
}
return null;
}
private SendGreetingCommandDynamicParameters context;

3. Declare una clase que defina los parámetros dinámicos que se van a agregar.
Puede usar los atributos que usó para declarar los parámetros del cmdlet estático
para declarar los parámetros dinámicos.

C#
public class SendGreetingCommandDynamicParameters
{
[Parameter]
[ValidateSet ("Marketing", "Sales", "Development")]
public string Department
{
get { return department; }
set { department = value; }
}
private string department;
}

Ejemplo
En este ejemplo, el Department parámetro se agrega cada vez que el usuario especifica
el Employee parámetro. El Department parámetro es opcional y el atributo ValidateSet se
usa para especificar los argumentos permitidos.

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation; // PowerShell assembly.

namespace SendGreeting
{
// Declare the cmdlet class that supports the
// IDynamicParameters interface.
[Cmdlet(VerbsCommunications.Send, "Greeting")]
public class SendGreetingCommand : Cmdlet, IDynamicParameters
{
// Declare the parameters for the cmdlet.
[Parameter(Mandatory = true)]
public string Name
{
get { return name; }
set { name = value; }
}
private string name;

[Parameter]
[Alias ("FTE")]
public SwitchParameter Employee
{
get { return employee; }
set { employee = value; }
}
private Boolean employee;
// Implement GetDynamicParameters to
// retrieve the dynamic parameter.
public object GetDynamicParameters()
{
if (employee)
{
context= new SendGreetingCommandDynamicParameters();
return context;
}
return null;
}
private SendGreetingCommandDynamicParameters context;

// Overide the ProcessRecord method to process the


// supplied user name and write out a greeting to
// the user by calling the WriteObject method.
protected override void ProcessRecord()
{
WriteObject("Hello " + name + "! ");
if (employee)
{
WriteObject("Department: " + context.Department);
}
}
}

// Define the dynamic parameters to be added


public class SendGreetingCommandDynamicParameters
{
[Parameter]
[ValidateSet ("Marketing", "Sales", "Development")]
public string Department
{
get { return department; }
set { department = value; }
}
private string department;
}
}

Consulte también
System.Management.Automation.Runtimedefinedparameterdictionary

System.Management.Automation.Idynamicparameters.Getdynamicparameters*

Parámetros dinámicos del cmdlet

Windows PowerShell SDK


Cómo invocar scripts dentro de un
cmdlet
Artículo • 24/09/2021

En este ejemplo se muestra cómo invocar un script que se proporciona a un cmdlet. El


cmdlet ejecuta el script y sus resultados se devuelven al cmdlet como una colección de
objetos System.Management.Automation.PSObject.

Para invocar un bloque de script


1. El comando comprueba que se ha proporcionado un bloque de script al cmdlet . Si
se proporcionó un bloque de script, el comando invoca el bloque de script con sus
parámetros necesarios.

C#

if (script != null)
{
WriteDebug("Executing script block.");

// Invoke the script block with the required arguments.


Collection<PSObject> PSObjects =
script.Invoke(
line,
simpleMatch,
caseSensitive
);

2. A continuación, el script recorre en iteración la colección devuelta de objetos


System.Management.Automation.PSObject y realiza las operaciones necesarias.

C#

foreach (PSObject psObject in psObjects)


{
if (LanguagePrimitives.IsTrue(psObject))
{
result = new MatchInfo();
result.Line = line;
result.IgnoreCase = !caseSensitive;

break;
}
}
Vea también
Escribir un cmdlet de Windows PowerShell
Cómo invalidar los métodos de
procesamiento de entrada
Artículo • 27/09/2021

En estos ejemplos se muestra cómo sobrescribir los métodos de procesamiento de


entrada dentro de un cmdlet. Estos métodos se usan para realizar las siguientes
operaciones:

El método System.Management.Automation.Cmdlet.BeginProcessing se usa para


realizar operaciones de inicio únicas que son válidas para todos los objetos
procesados por el cmdlet. El Windows PowerShell tiempo de ejecución llama a este
método solo una vez.

El método System.Management.Automation.Cmdlet.ProcessRecord se usa para


procesar los objetos pasados al cmdlet . El Windows PowerShell en tiempo de
ejecución llama a este método para cada objeto pasado al cmdlet .

El método System.Management.Automation.Cmdlet.EndProcessing se usa para


realizar operaciones posteriores al procesamiento una sola vez. El Windows
PowerShell tiempo de ejecución llama a este método solo una vez.

Para invalidar el método BeginProcessing


Declare una invalidación protegida del método
System.Management.Automation.Cmdlet.BeginProcessing.

La clase siguiente imprime un mensaje de ejemplo. Para usar esta clase, cambie el verbo
y el sustantivo en el atributo Cmdlet, cambie el nombre de la clase para reflejar el nuevo
verbo y el nombre y, a continuación, agregue la funcionalidad que necesita a la
invalidación del método System.Management.Automation.Cmdlet.BeginProcessing.

C#

[Cmdlet(VerbsDiagnostic.Test, "BeginProcessingClass")]
public class TestBeginProcessingClassTemplate : Cmdlet
{
// Override the BeginProcessing method to add preprocessing
//operations to the cmdlet.
protected override void BeginProcessing()
{
// Replace the WriteObject method with the logic required
// by your cmdlet. It is used here to generate the following
// output:
// "This is a test of the BeginProcessing template."
WriteObject("This is a test of the BeginProcessing template.");
}
}

Para invalidar el método ProcessRecord


Declare una invalidación protegida del método
System.Management.Automation.Cmdlet.ProcessRecord.

La clase siguiente imprime un mensaje de ejemplo. Para usar esta clase, cambie el verbo
y el sustantivo en el atributo Cmdlet, cambie el nombre de la clase para reflejar el nuevo
verbo y el sustantivo y, a continuación, agregue la funcionalidad que necesita a la
invalidación del método System.Management.Automation.Cmdlet.ProcessRecord.

C#

[Cmdlet(VerbsDiagnostic.Test, "ProcessRecordClass")]
public class TestProcessRecordClassTemplate : Cmdlet
{
// Override the ProcessRecord method to add processing
//operations to the cmdlet.
protected override void ProcessRecord()
{
// Replace the WriteObject method with the logic required
// by your cmdlet. It is used here to generate the following
// output:
// "This is a test of the ProcessRecord template."
WriteObject("This is a test of the ProcessRecord template.");
}
}

Para invalidar el método EndProcessing


Declare una invalidación protegida del método
System.Management.Automation.Cmdlet.EndProcessing.

La clase siguiente imprime un ejemplo. Para usar esta clase, cambie el verbo y el
sustantivo en el atributo Cmdlet, cambie el nombre de la clase para reflejar el nuevo
verbo y el nombre y, a continuación, agregue la funcionalidad que necesita a la
invalidación del método System.Management.Automation.Cmdlet.EndProcessing.

C#
[Cmdlet(VerbsDiagnostic.Test, "EndProcessingClass")]
public class TestEndProcessingClassTemplate : Cmdlet
{
// Override the EndProcessing method to add postprocessing
//operations to the cmdlet.
protected override void EndProcessing()
{
// Replace the WriteObject method with the logic required
// by your cmdlet. It is used here to generate the following
// output:
// "This is a test of the BeginProcessing template."
WriteObject("This is a test of the EndProcessing template.");
}
}

Consulte también
System.Management.Automation.Cmdlet.BeginProcessing

System.Management.Automation.Cmdlet.EndProcessing

System.Management.Automation.Cmdlet.ProcessRecord

Escribir un cmdlet de Windows PowerShell


Cómo solicitar confirmaciones
Artículo • 24/09/2021

En este ejemplo se muestra cómo llamar a los métodos


System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue para solicitar confirmaciones
al usuario antes de realizar una acción.

) Importante

Para obtener más información sobre cómo Windows PowerShell estas solicitudes,
vea Solicitar confirmación.

Para solicitar confirmación


1. Asegúrese de que SupportsShouldProcess el parámetro del atributo Cmdlet está
establecido en true . (Para las funciones, se trata de un parámetro del atributo
CmdletBinding).

C#

[Cmdlet(VerbsDiagnostic.Test, "RequestConfirmationTemplate1",
SupportsShouldProcess = true, ConfirmImpact =
ConfirmImpact.High)]

7 Nota

El SupportsShouldProcess uso de por sí solo no garantiza que se pida


confirmación al usuario. La solicitud viene determinada por el valor de
$ConfirmPreference y el impacto de la acción. Use ConfirmImpact para
establecer la gravedad del impacto de la operación.

2. Agregue un Force parámetro al cmdlet para que el usuario pueda invalidar una
solicitud de confirmación.

C#

[Parameter()]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

3. Agregue una instrucción que use el valor devuelto del método if


System.Management.Automation.Cmdlet.ShouldProcess para determinar si se
llama al método System.Management.Automation.Cmdlet.ShouldContinue.

4. Agregue una segunda instrucción que use el valor devuelto del método if
System.Management.Automation.Cmdlet.ShouldContinue y el valor del parámetro
para determinar si se debe realizar Force la operación.

Ejemplo
En el ejemplo de código siguiente, se llama a los métodos
System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue desde la invalidación del
método System.Management.Automation.Cmdlet.ProcessRecord. Sin embargo, también
puede llamar a estos métodos desde los otros métodos de procesamiento de entrada.

C#

protected override void ProcessRecord()


{
if (ShouldProcess("ShouldProcess target"))
{
if (Force || ShouldContinue("", ""))
{
// Add code that performs the operation.
}
}
}

Vea también
Escribir un cmdlet de Windows PowerShell
Cómo admitir transacciones
Artículo • 27/09/2021

En este ejemplo se muestran los elementos de código básicos que agregan


compatibilidad para las transacciones a un cmdlet.

) Importante

Para obtener más información sobre cómo Windows PowerShell las transacciones,
vea Acerca de las transacciones.

Para admitir transacciones


1. Cuando declare el atributo Cmdlet, especifique que el cmdlet admite
transacciones. Cuando el cmdlet admite transacciones, Windows PowerShell el
UseTransaction parámetro al cmdlet cuando se ejecuta.

C#

[Cmdlet(VerbsCommunications.Send, "GreetingTx",
SupportsTransactions=true )]

2. Dentro de uno de los métodos de procesamiento de entrada, agregue if un


bloque para determinar si hay una transacción disponible. Si la instrucción se
resuelve como , las acciones dentro de esta instrucción se pueden realizar if en el
contexto de la true transacción actual.

C#

if (TransactionAvailable())
{
using (CurrentPSTransaction)
{
WriteObject("Hello " + name + " from within a transaction.");
}
}

Vea también
Escribir un cmdlet de Windows PowerShell
Cómo admitir trabajos
Artículo • 27/09/2021

En este ejemplo se muestra cómo admitir trabajos al escribir cmdlets. Si desea que los
usuarios ejecuten el cmdlet como un trabajo en segundo plano, debe incluir el código
descrito en el procedimiento siguiente. Para obtener más información sobre los trabajos
en segundo plano, vea Trabajos en segundo plano.

Para admitir trabajos


1. Defina un AsJob parámetro switch para que el usuario pueda decidir si desea
ejecutar el cmdlet como un trabajo.

En el ejemplo siguiente se muestra una declaración de parámetro AsJob.

C#

[Parameter()]
public SwitchParameter AsJob
{
get { return asjob; }
set { asjob = value; }
}
private bool asjob;

2. Cree un objeto que se derive de la clase System.Management.Automation.Job. Este


objeto puede ser un objeto de trabajo personalizado o uno de los objetos de
trabajo proporcionados por Windows PowerShell, como un objeto
System.Management.Automation.Pseventjob.

En el ejemplo siguiente se muestra un objeto de trabajo personalizado.

C#

private SampleJob job = new SampleJob("Get-ProcAsJob");

3. En un método de procesamiento de registros, agregue una if instrucción para


detectar si el cmdlet debe ejecutarse como un trabajo. El código siguiente usa el
método System.Management.Automation.Cmdlet.ProcessRecord.

C#
protected override void ProcessRecord()
{
if (asjob)
{
// Add the job definition to the job repository,
// return the job object, and then create the thread
// used to run the job.
JobRepository.Add(job);
WriteObject(job);
ThreadPool.QueueUserWorkItem(WorkItem);
}
else
{
job.ProcessJob();
foreach (PSObject p in job.Output)
{
WriteObject(p);
}
}
}

4. Para los objetos de trabajo personalizados, implemente la clase de trabajo .

C#

private class SampleJob : Job


{
internal SampleJob(string command)
: base(command)
{
SetJobState(JobState.NotStarted);
}
public override string StatusMessage
{
get { throw new NotImplementedException(); }
}

public override bool HasMoreData


{
get
{
return hasMoreData;
}
}
private bool hasMoreData = true;

public override string Location


{
get { throw new NotImplementedException(); }
}

public override void StopJob()


{
throw new NotImplementedException();
}

internal void ProcessJob()


{
SetJobState(JobState.Running);
DoProcessLogic();
SetJobState(JobState.Completed);
}

// Retrieve the processes of the local computer.


void DoProcessLogic()
{
Process[] p = Process.GetProcesses();

foreach (Process pl in p)
{
Output.Add(PSObject.AsPSObject(pl));
}
Output.Complete();
} // End DoProcessLogic.
} // End SampleJob class.

5. Si el cmdlet realiza el trabajo, llame al método


System.Management.Automation.Cmdlet.WriteObject para devolver un objeto de
proceso a la canalización. Si el trabajo se realiza como un trabajo, agregue un
trabajo secundario al trabajo.

C#

void DoProcessLogic(bool asJob)


{
Process[] p = Process.GetProcesses();

foreach (Process pl in p)
{
if (!asjob)
{
WriteObject(pl);
}
else
{
job.ChildJobs[0].Output.Add(PSObject.AsPSObject(pl));
}
}
} // End DoProcessLogic.

Ejemplo
El código de ejemplo siguiente muestra el código de un cmdlet que puede recuperar
procesos Get-Proc internamente o mediante un trabajo en segundo plano.

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation; // Windows PowerShell namespace.
using System.Threading; // Thread pool namespace for posting
work.
using System.Diagnostics; // Diagnostics namespace for retrieving
// process objects.

// This sample shows a cmdlet whose work can be done by the cmdlet or by
using
// a background job. Background jobs are executed in their own thread,
// independent of the pipeline thread in which the cmdlet is executed.
//
// To load this cmdlet, create a module folder and copy the
GetProcessSample06.dll
// assembly into the module folder. Make sure that the path to the module
folder
// is added to the $PSModulePath environment variable.
// Module folder path:
// user/documents/WindowsPowerShell/modules/GetProcessSample06
//
// To import the module, run the following command: Import-Module
GetProcessSample06.
// To test the cmdlet, run the following command: Get-Proc -name <process
name>
//

//
namespace Microsoft.Samples.PowerShell.Commands
{
/// <summary>
/// This cmdlet retrieves process internally or returns
/// a job that retrieves the processes.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public sealed class GetProcCommand : PSCmdlet
{

#region Parameters
/// <summary>
/// Specify the Name parameter. This parameter accepts
/// process names from the command line.
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// Specify the AsJob parameter. This parameter indicates
/// whether the cmdlet should retrieve the processes internally
/// or return a Job object that retrieves the processes.
/// </summary>
[Parameter()]
public SwitchParameter AsJob
{
get { return asjob; }
set { asjob = value; }
}
private bool asjob;

#endregion Parameters

#region Cmdlet Overrides

// Create a custom job object.


private SampleJob job = new SampleJob("Get-ProcAsJob");

/// <summary>
/// Determines if the processes should be retrieved
/// internally or if a Job object should be returned.
/// </summary>
protected override void ProcessRecord()
{
if (asjob)
{
// Add the job definition to the job repository,
// return the job object, and then create the thread
// used to run the job.
JobRepository.Add(job);
WriteObject(job);
ThreadPool.QueueUserWorkItem(WorkItem);
}
else
{
job.ProcessJob();
foreach (PSObject p in job.Output)
{
WriteObject(p);
}
}
}
#endregion Overrides

// Implement a custom job that derives


// from the System.Management.Automation.Job class.
private class SampleJob : Job
{
internal SampleJob(string command)
: base(command)
{
SetJobState(JobState.NotStarted);
}
public override string StatusMessage
{
get { throw new NotImplementedException(); }
}

public override bool HasMoreData


{
get
{
return hasMoreData;
}
}
private bool hasMoreData = true;

public override string Location


{
get { throw new NotImplementedException(); }
}

public override void StopJob()


{
throw new NotImplementedException();
}

internal void ProcessJob()


{
SetJobState(JobState.Running);
DoProcessLogic();
SetJobState(JobState.Completed);
}

// Retrieve the processes of the local computer.


void DoProcessLogic()
{
Process[] p = Process.GetProcesses();

foreach (Process pl in p)
{
Output.Add(PSObject.AsPSObject(pl));
}
Output.Complete();
} // End DoProcessLogic.
} // End SampleJob class.

void WorkItem(object dummy)


{
job.ProcessJob();
}

// Display the results of the work. If not a job,


// process objects are returned. If a job, the
// output is added to the job as a child job.
void DoProcessLogic(bool asJob)
{
Process[] p = Process.GetProcesses();

foreach (Process pl in p)
{
if (!asjob)
{
WriteObject(pl);
}
else
{
job.ChildJobs[0].Output.Add(PSObject.AsPSObject(pl));
}
}
} // End DoProcessLogic.
} //End GetProcCommand
}
Cómo invocar un cmdlet desde dentro
de un cmdlet
Artículo • 27/09/2021

En este ejemplo se muestra cómo invocar un cmdlet desde otro cmdlet, lo que le
permite agregar la funcionalidad del cmdlet invocado al cmdlet que está desarrollando.
En este ejemplo, se Get-Process invoca el cmdlet para obtener los procesos que se
ejecutan en el equipo local. La llamada al Get-Process cmdlet es equivalente al
comando siguiente. Este comando recupera todos los procesos cuyos nombres
comienzan por los caracteres "a" a "t".

PowerShell

Get-Process -name [a-t]

) Importante

Solo se pueden invocar los cmdlets que se derivan directamente de la clase


System.Management.Automation.Cmdlet. No se puede invocar un cmdlet que se
derive de la clase System.Management.Automation.PSCmdlet.

Para invocar un cmdlet desde dentro de un


cmdlet
1. Asegúrese de que se hace referencia al ensamblado que define el cmdlet que se va
a invocar y de que se agrega la using instrucción adecuada. En este ejemplo, se
agregan los siguientes espacios de nombres.

C#

using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell assembly.
using Microsoft.PowerShell.Commands; // Windows PowerShell assembly.

2. En el método de procesamiento de entrada del cmdlet, cree una nueva instancia


del cmdlet que se va a invocar. En este ejemplo, se crea un objeto de tipo
Microsoft.PowerShell.Commands.Getprocesscommand junto con la cadena que
contiene los argumentos que se usan cuando se invoca el cmdlet.
C#

GetProcessCommand gp = new GetProcessCommand();


gp.Name = new string[] { "[a-t]*" };

3. Llame al método System.Management.Automation.Cmdlet.Invoke* para invocar el


Get-Process cmdlet.

C#

foreach (Process p in gp.Invoke<Process>())


{
Console.WriteLine(p.ToString());
}
}

Ejemplo
En este ejemplo, el cmdlet se invoca desde el método Get-Process
System.Management.Automation.Cmdlet.BeginProcessing de un cmdlet.

C#

using System;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell assembly.
using Microsoft.PowerShell.Commands; // Windows PowerShell assembly.

namespace SendGreeting
{
// Declare the class as a cmdlet and specify an
// appropriate verb and noun for the cmdlet name.
[Cmdlet(VerbsCommunications.Send, "GreetingInvoke")]
public class SendGreetingInvokeCommand : Cmdlet
{
// Declare the parameters for the cmdlet.
[Parameter(Mandatory = true)]
public string Name
{
get { return name; }
set { name = value; }
}
private string name;

// Override the BeginProcessing method to invoke


// the Get-Process cmdlet.
protected override void BeginProcessing()
{
GetProcessCommand gp = new GetProcessCommand();
gp.Name = new string[] { "[a-t]*" };
foreach (Process p in gp.Invoke<Process>())
{
Console.WriteLine(p.ToString());
}
}

// Override the ProcessRecord method to process


// the supplied user name and write out a
// greeting to the user by calling the WriteObject
// method.
protected override void ProcessRecord()
{
WriteObject("Hello " + name + "!");
}
}
}

Vea también
Escribir un cmdlet de Windows PowerShell
How to invoke a PSCmdlet from within a
PSCmdlet
Article • 10/20/2022

This example shows how to invoke a script based cmdlet or binary cmdlet inheriting
from [System.Management.Automation.PSCmdlet] from within a binary cmdlet. In this
example, the new cmdlet Get-ClipboardReverse calls Get-Clipboard to get the contents
of the clipboard. The Get-ClipboardReverse reverses the order of the characters and
returns the reversed string.

7 Note

The [PSCmdlet] class differs from the [Cmdlet] class. [PSCmdlet] implementations
use runspace context information so you must invoke another cmdlet using the
PowerShell pipeline API. In [Cmdlet] implementations you can call the cmdlet's
.NET API directly. For an example, see How to invoke a Cmdlet from within a
Cmdlet.

To invoke a cmdlet from within a PSCmdlet


1. Ensure that the namespace for the [System.Management.Automation.PowerShell]
API is referenced. In this example, the following namespaces are added.

C#

using System.Management.Automation; // PowerShell assembly.


using System.Text;

2. To invoke a command from within another binary cmdlet you must use the
[PowerShell] API to construct a new pipeline and add the cmdlet to be invoked.
Call the System.Management.Automation.PowerShell.Invoke<T>() method to
invoke the pipeline.

C#

using var ps = PowerShell.Create(RunspaceMode.CurrentRunspace);


ps.AddCommand("Get-Clipboard").AddParameter("Raw");
var output = ps.Invoke<string>();
Example
To invoke a script based cmdlet or binary cmdlet inheriting from [PSCmdlet] you must
build a PowerShell pipeline with the command and parameters you want to execute,
then invoke the pipeline.

C#

using System;
using System.Management.Automation; // PowerShell assembly.
using System.Text;

namespace ClipboardReverse
{
[Cmdlet(VerbsCommon.Get,"ClipboardReverse")]
[OutputType(typeof(string))]
public class ClipboardReverse : PSCmdlet
{
protected override void EndProcessing()
{
using var ps = PowerShell.Create(RunspaceMode.CurrentRunspace);
ps.AddCommand("Get-Clipboard").AddParameter("Raw");
var output = ps.Invoke<string>();
if (ps.HadErrors)
{
WriteError(new ErrorRecord(ps.Streams.Error[0].Exception,
"Get-Clipboard Error",
ErrorCategory.NotSpecified, null));
}
else
{
var sb = new StringBuilder();
foreach (var text in output)
{
sb.Append(text);
}

var reversed = sb.ToString().ToCharArray();


Array.Reverse(reversed);
WriteObject(new string(reversed));
}
}
}
}

See Also
Writing a Windows PowerShell Cmdlet
Tutoriales para escribir cmdlets
Artículo • 24/09/2021

Esta sección contiene tutoriales para escribir cmdlets. Estos tutoriales incluyen el código
necesario para escribir los cmdlets, además de una explicación de por qué se necesita el
código. Estos temas serán muy útiles para aquellos que están empezando a escribir
cmdlets.

) Importante

Para aquellos que desean ejemplos de código con menos descripción, vea
Ejemplos de cmdlets.

En esta sección
Tutorial de GetProc: en este tutorial se describe cómo definir una clase de cmdlet y
agregar funcionalidad básica, como agregar parámetros y notificar errores. El cmdlet
descrito en este tutorial es muy similar al cmdlet Get-Process proporcionado por
Windows PowerShell.

Tutorial de StopProc: en este tutorial se describe cómo definir un cmdlet y agregar


funcionalidad como avisos de usuario, compatibilidad con caracteres comodín y el uso
de conjuntos de parámetros. El cmdlet descrito aquí realiza la misma tarea que el cmdlet
Stop-Process proporcionado por Windows PowerShell.

Tutorial de SelectStr: en este tutorial se describe cómo definir un cmdlet que accede a
un almacén de datos. El cmdlet descrito aquí realiza la misma tarea que el cmdlet
Select-String proporcionado por Windows PowerShell.

Consulte también
Tutorial de GetProc

Tutorial de StopProc

Tutorial de SelectStr

Windows PowerShell SDK


Tutorial de GetProc
Artículo • 27/09/2021

En esta sección se proporciona un tutorial para crear un cmdlet Get-Proc que es muy
similar al cmdlet Get-Process proporcionado por Windows PowerShell. En este tutorial
se proporcionan fragmentos de código que ilustran cómo se implementan los cmdlets y
una explicación del código.

Temas de este tutorial


Los temas de este tutorial están diseñados para leerse secuencialmente, con cada tema
en función de lo que se ha analizado en el tema anterior.

Creación de un cmdlet sin parámetros En esta sección se describe cómo crear un cmdlet
que recupera información del equipo local sin el uso de parámetros y, a continuación,
escribe la información en la canalización.

Adición de parámetros que procesan Command-Line entrada En esta sección se


describe cómo agregar un parámetro al cmdlet Get-Proc para que el cmdlet pueda
procesar la entrada en función de los objetos explícitos pasados al cmdlet. La
implementación descrita aquí recupera los procesos en función de su nombre y, a
continuación, escribe la información en la canalización.

Agregar parámetros que procesan la entrada de canalización En esta sección se describe


cómo agregar un parámetro al cmdlet Get-Proc para que el cmdlet pueda procesar los
objetos pasados a él a través de la canalización. El cmdlet de implementación descrito
aquí recupera procesos basados en objetos pasados al cmdlet y, a continuación, escribe
la información en la canalización.

Agregar informes de errores no terminales al cmdlet En esta sección se describe cómo


agregar informes de errores no terminales a un cmdlet. La implementación descrita aquí
detecta los errores no terminales que se producen al procesar la entrada y escribe un
registro de errores en la secuencia de errores.

Consulte también
Creación de un cmdlet sin parámetros

Adición de parámetros que procesan Command-Line entrada

Adición de parámetros que procesan la entrada de la canalización


Agregar informes de errores no terminales al cmdlet

Windows PowerShell SDK


Creación de un cmdlet sin parámetros
Artículo • 27/09/2021

En esta sección se describe cómo crear un cmdlet que recupera información del equipo
local sin el uso de parámetros y, a continuación, escribe la información en la
canalización. El cmdlet descrito aquí es un cmdlet Get-Proc que recupera información
sobre los procesos del equipo local y, a continuación, muestra esa información en la
línea de comandos.

7 Nota

Tenga en cuenta que al escribir cmdlets, los ensamblados de referencia de


Windows PowerShell® se descargan en el disco (de forma predeterminada en
C:\Archivos de programa\Ensamblados de
referencia\Microsoft\WindowsPowerShell\v1.0). No están instalados en la caché
global de ensamblados (GAC).

Asignación de un nombre al cmdlet


Un nombre de cmdlet consta de un verbo que indica la acción que realiza el cmdlet y un
sustantivo que indica los elementos sobre los que actúa el cmdlet. Dado que este
cmdlet Get-Proc de ejemplo recupera objetos de proceso, usa el verbo "Get", definido
por la enumeración System.Management.Automation.Verbscommon, y el nombre "Proc"
para indicar que el cmdlet funciona en elementos de proceso.

Al asignar nombres a los cmdlets, no use ninguno de los caracteres siguientes: # , () {} []


& - /\ $ ; : " '<> | ? @ ` .

Elegir un sustantivo
Debe elegir un sustantivo que sea específico. Es mejor usar un nombre singular con el
prefijo de una versión abreviada del nombre del producto. Un nombre de cmdlet de
ejemplo de este tipo es " Get-SQLServer ".

Elegir un verbo
Debe usar un verbo del conjunto de nombres de verbos de cmdlet aprobados. Para
obtener más información sobre los verbos de cmdlet aprobados, vea Nombres de
verbos de cmdlet.
Definición de la clase cmdlet
Una vez que haya elegido un nombre de cmdlet, defina una clase de .NET para
implementar el cmdlet. Esta es la definición de clase para este cmdlet Get-Proc ejemplo:

C#

[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet

VB

<Cmdlet(VerbsCommon.Get, "Proc")> _
Public Class GetProcCommand
Inherits Cmdlet

Observe que antes de la definición de clase, el atributo


System.Management.Automation.CmdletAttribute, con la sintaxis , se usa para identificar
esta clase [Cmdlet(verb, noun, ...)] como un cmdlet. Este es el único atributo
necesario para todos los cmdlets y permite que el entorno Windows PowerShell tiempo
de ejecución los llame correctamente. Puede establecer palabras clave de atributo para
declarar aún más la clase si es necesario. Tenga en cuenta que la declaración de atributo
para nuestra clase GetProcCommand de ejemplo solo declara los nombres y verbos para
el cmdlet Get-Proc.

7 Nota

Para todas Windows PowerShell clases de atributo, las palabras clave que puede
establecer corresponden a las propiedades de la clase de atributo.

Al asignar un nombre a la clase del cmdlet, es una buena práctica reflejar el nombre del
cmdlet en el nombre de clase. Para ello, use el formato "VerbNounCommand" y
reemplace "Verb" y "Noun" por el verbo y el nombre usados en el nombre del cmdlet.
Como se muestra en la definición de clase anterior, el cmdlet Get-Proc de ejemplo
define una clase denominada GetProcCommand, que se deriva de la clase base
System.Management.Automation.Cmdlet.

) Importante

Si desea definir un cmdlet que acceda directamente al entorno de ejecución de


Windows PowerShell, la clase .NET debe derivar de la clase base
System.Management.Automation.PSCmdlet. Para obtener más información sobre
esta clase, vea Crear un cmdlet que define conjuntos de parámetros.

7 Nota

La clase de un cmdlet debe marcarse explícitamente como pública. Las clases que
no están marcadas como públicas tendrán como valor predeterminado internal y
no se encontrarán en el entorno Windows PowerShell ejecución.

Windows PowerShell usa el espacio de nombres Microsoft.PowerShell.Commands para


sus clases de cmdlet. Se recomienda colocar las clases de cmdlet en un espacio de
nombres Commands del espacio de nombres de api, por ejemplo, xxx.PS.Commands.

Invalidar un método de procesamiento de


entrada
La clase System.Management.Automation.Cmdlet proporciona tres métodos de
procesamiento de entrada principales, al menos uno de los cuales debe invalidar el
cmdlet. Para obtener más información sobre cómo Windows PowerShell los registros,
vea How Windows PowerShell Works .

Para todos los tipos de entrada, el Windows PowerShell tiempo de ejecución llama a
System.Management.Automation.Cmdlet.BeginProcessing para habilitar el
procesamiento. Si el cmdlet debe realizar algún preprocesamiento o configuración,
puede hacerlo invalidando este método.

7 Nota

Windows PowerShell usa el término "record" para describir el conjunto de valores


de parámetro proporcionados cuando se llama a un cmdlet.

Si el cmdlet acepta la entrada de canalización, debe invalidar el método


System.Management.Automation.Cmdlet.ProcessRecord y, opcionalmente, el método
System.Management.Automation.Cmdlet.EndProcessing. Por ejemplo, un cmdlet podría
invalidar ambos métodos si recopila todas las entradas mediante
System.Management.Automation.Cmdlet.ProcessRecord y, a continuación, funciona en
la entrada como un todo en lugar de un elemento a la vez, como hace el Sort-Object
cmdlet.
Si el cmdlet no toma la entrada de canalización, debe invalidar el método
System.Management.Automation.Cmdlet.EndProcessing. Tenga en cuenta que este
método se usa con frecuencia en lugar de
System.Management.Automation.Cmdlet.BeginProcessing cuando el cmdlet no puede
funcionar en un elemento a la vez, como es el caso de un cmdlet de ordenación.

Dado que este cmdlet Get-Proc de ejemplo debe recibir la entrada de canalización,
invalida el método System.Management.Automation.Cmdlet.ProcessRecord y usa las
implementaciones predeterminadas para
System.Management.Automation.Cmdlet.BeginProcessing y
System.Management.Automation.Cmdlet.EndProcessing. La invalidación
System.Management.Automation.Cmdlet.ProcessRecord recupera los procesos y los
escribe en la línea de comandos mediante el método
System.Management.Automation.Cmdlet.WriteObject.

C#

protected override void ProcessRecord()


{
// Get the current processes
Process[] processes = Process.GetProcesses();

// Write the processes to the pipeline making them available


// to the next cmdlet. The second parameter of this call tells
// PowerShell to enumerate the array, and send one process at a
// time to the pipeline.
WriteObject(processes, true);
}

VB

Protected Overrides Sub ProcessRecord()

'/ Get the current processes.


Dim processes As Process()
processes = Process.GetProcesses()

'/ Write the processes to the pipeline making them available


'/ to the next cmdlet. The second parameter of this call tells
'/ PowerShell to enumerate the array, and send one process at a
'/ time to the pipeline.
WriteObject(processes, True)

End Sub 'ProcessRecord

Aspectos que debe recordar sobre el procesamiento de entrada


El origen predeterminado de la entrada es un objeto explícito (por ejemplo, una
cadena) proporcionado por el usuario en la línea de comandos. Para obtener más
información, vea Crear un cmdlet para procesar la entrada de la línea de
comandos.

Un método de procesamiento de entrada también puede recibir la entrada del


objeto de salida de un cmdlet ascendente en la canalización. Para obtener más
información, vea Crear un cmdlet para procesar la entrada de canalización. Tenga
en cuenta que el cmdlet puede recibir entradas de una combinación de orígenes
de línea de comandos y de canalización.

Es posible que el cmdlet de nivel inferior no vuelva durante mucho tiempo o que
no lo haga. Por ese motivo, el método de procesamiento de entrada del cmdlet no
debe contener bloqueos durante las llamadas a
System.Management.Automation.Cmdlet.WriteObject,especialmente los bloqueos
para los que el ámbito se extiende más allá de la instancia del cmdlet.

) Importante

Los cmdlets nunca deben llamar a System.Console.Writeline* ni a su equivalente.

El cmdlet podría tener variables de objeto para limpiar cuando termine de


procesarse (por ejemplo, si abre un identificador de archivo en el método
System.Management.Automation.Cmdlet.BeginProcessing y mantiene el
identificador abierto para que lo use
System.Management.Automation.Cmdlet.ProcessRecord). Es importante recordar
que el runtime Windows PowerShell no siempre llama al método
System.Management.Automation.Cmdlet.EndProcessing, que debe realizar la
limpieza de objetos.

Por ejemplo, es posible que no se llame a


System.Management.Automation.Cmdlet.EndProcessing si el cmdlet se cancela a mitad
o si se produce un error de terminación en cualquier parte del cmdlet. Por lo tanto, un
cmdlet que requiere limpieza de objetos debe implementar el patrón
System.IDisposable completo, incluido el finalizador, para que el tiempo de ejecución
pueda llamar a System.Management.Automation.Cmdlet.EndProcessing y
System.IDisposable.Dispose* al final del procesamiento.

Ejemplo de código
Para obtener el código de ejemplo de C# completo, vea GetProcessSample01 Sample.
Definir tipos de objeto y formato
Windows PowerShell pasa información entre cmdlets mediante objetos .NET. Por lo
tanto, es posible que un cmdlet tenga que definir su propio tipo o que el cmdlet tenga
que extender un tipo existente proporcionado por otro cmdlet. Para obtener más
información sobre cómo definir nuevos tipos o extender los tipos existentes, vea
Extender tipos de objeto y Aplicar formato a .

Compilar el cmdlet
Después de implementar un cmdlet, debe registrarlo con Windows PowerShell a través
de un Windows PowerShell complemento. Para obtener más información sobre el
registro de cmdlets, vea How to Register Cmdlets, Providers, and Host Applications .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con Windows PowerShell, puede probarlo
ejecutándose en la línea de comandos. El código de nuestro cmdlet Get-Proc de
ejemplo es pequeño, pero todavía usa el runtime de Windows PowerShell y un objeto
.NET existente, lo que es suficiente para que sea útil. Vamos a probarlo para comprender
mejor qué Get-Proc puede hacer y cómo se puede usar su salida. Para obtener más
información sobre el uso de cmdlets desde la línea de comandos, vea el Tareas iniciales
con Windows PowerShell.

1. Inicie Windows PowerShell y obtenga los procesos actuales que se ejecutan en el


equipo.

PowerShell

get-proc

Aparece el siguiente resultado.

Resultados

Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- ----------
254 7 7664 12048 66 173.75 1200 QCTRAY
32 2 1372 2628 31 0.04 1860 DLG
271 6 1216 3688 33 0.03 3816 lg
27 2 560 1920 24 0.01 1768 TpScrex
...
2. Asigne una variable a los resultados del cmdlet para facilitar la manipulación.

PowerShell

$p=get-proc

3. Obtiene el número de procesos.

PowerShell

$p.length

Aparece el siguiente resultado.

Resultados

63

4. Recuperar un proceso específico.

PowerShell

$p[6]

Aparece el siguiente resultado.

Resultados

Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
1033 3 2400 3336 35 0.53 1588 rundll32

5. Obtiene la hora de inicio de este proceso.

PowerShell

$p[6].starttime

Aparece el siguiente resultado.

Resultados

Tuesday, July 26, 2005 9:34:15 AM


PowerShell

$p[6].starttime.dayofyear

Resultados

207

6. Obtenga los procesos para los que el recuento de identificadores sea mayor que
500 y ordene el resultado.

PowerShell

$p | Where-Object {$_.HandleCount -gt 500 } | Sort-Object HandleCount

Aparece el siguiente resultado.

Resultados

Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- ----------
568 14 2164 4972 39 5.55 824 svchost
716 7 2080 5332 28 25.38 468 csrss
761 21 33060 56608 440 393.56 3300 WINWORD
791 71 7412 4540 59 3.31 492 winlogon
...

7. Use el Get-Member cmdlet para enumerar las propiedades disponibles para cada
proceso.

PowerShell

$p | Get-Member -MemberType property

Resultados

TypeName: System.Diagnostics.Process

Aparece el siguiente resultado.

Resultados

Name MemberType Definition


---- ---------- ----------
BasePriority Property System.Int32 BasePriority {get;}
Container Property System.ComponentModel.IContainer
Conta...
EnableRaisingEvents Property System.Boolean EnableRaisingEvents
{ge...
...

Consulte también
Creación de un cmdlet para procesar la entrada de la línea de comandos

Creación de un cmdlet para procesar la entrada de canalización

Cómo crear un cmdlet Windows PowerShell aplicación

Extensión de tipos de objeto y formato

Funcionamiento de Windows PowerShell

Cómo registrar cmdlets, proveedores y aplicaciones host

Referencia de Windows PowerShell

Ejemplos de cmdlet
Adición de parámetros que procesan la
entrada de la línea de comandos
Artículo • 24/09/2021

Un origen de entrada para un cmdlet es la línea de comandos. En este tema se describe


cómo agregar un parámetro al cmdlet (que se describe en Creación del primer cmdlet)
para que el cmdlet pueda procesar la entrada del equipo local en función de los objetos
explícitos pasados al Get-Proc cmdlet. El cmdlet descrito aquí recupera los procesos en
función de sus nombres y, a continuación, muestra Get-Proc información sobre los
procesos en un símbolo del sistema.

Definición de la clase cmdlet


El primer paso en la creación de cmdlets es la nomenclatura de cmdlets y la declaración
de la clase .NET Framework que implementa el cmdlet. Este cmdlet recupera la
información del proceso, por lo que el nombre del verbo elegido aquí es "Get". (Casi
cualquier tipo de cmdlet que sea capaz de recuperar información puede procesar la
entrada de la línea de comandos). Para obtener más información sobre los verbos de
cmdlet aprobados, vea Nombres de verbos de cmdlet.

Esta es la declaración de clase para el Get-Proc cmdlet . Los detalles sobre esta
definición se proporcionan en Creación del primer cmdlet.

C#

[Cmdlet(VerbsCommon.Get, "proc")]
public class GetProcCommand: Cmdlet

VB

<Cmdlet(VerbsCommon.Get, "Proc")> _
Public Class GetProcCommand
Inherits Cmdlet

Declarar parámetros
Un parámetro de cmdlet permite al usuario proporcionar entradas al cmdlet. En el
ejemplo siguiente, Get-Proc y son los nombres de los cmdlets canalizados, Get-Member y
es un parámetro para el cmdlet MemberType Get-Member . El parámetro tiene el
argumento "property".

PS> get-proc ; get-member -membertype, propiedad

Para declarar parámetros para un cmdlet, primero debe definir las propiedades que
representan los parámetros. En el cmdlet , el único parámetro es , que en este caso
representa el nombre del objeto .NET Framework proceso que se Get-Proc Name va a
recuperar. Por lo tanto, la clase de cmdlet define una propiedad de tipo cadena para
aceptar una matriz de nombres.

Esta es la declaración de parámetro para el Name parámetro del Get-Proc cmdlet .

C#

/// <summary>
/// Specify the cmdlet Name parameter.
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

#endregion Parameters

VB

<Parameter(Position:=0), ValidateNotNullOrEmpty()> _
Public Property Name() As String()
Get
Return processNames
End Get

Set(ByVal value As String())


processNames = value
End Set

End Property

Para informar al Windows PowerShell tiempo de ejecución de que esta propiedad es el


parámetro , se agrega un atributo Name
System.Management.Automation.Parameterattribute a la definición de propiedad. La
sintaxis básica para declarar este atributo es [Parameter()] .
7 Nota

Un parámetro debe marcarse explícitamente como público. Los parámetros que no


están marcados como valores predeterminados públicos son internos y no se
encuentran en el entorno Windows PowerShell ejecución.

Este cmdlet usa una matriz de cadenas para el Name parámetro . Si es posible, el cmdlet
también debe definir un parámetro como una matriz, ya que esto permite que el cmdlet
acepte más de un elemento.

Cosas que debe recordar acerca de las definiciones de parámetros


Los nombres Windows PowerShell parámetros predefinidos y los tipos de datos
deben reutilizarse tanto como sea posible para asegurarse de que el cmdlet es
compatible con Windows PowerShell cmdlets. Por ejemplo, si todos los cmdlets
usan el nombre de parámetro predefinido para identificar un recurso, el usuario
comprenderá fácilmente el significado del parámetro, independientemente del
cmdlet que Id use. Básicamente, los nombres de parámetro siguen las mismas
reglas que las que se usan para los nombres de variable en Common Language
Runtime (CLR). Para obtener más información sobre la nomenclatura de
parámetros, vea Nombres de parámetro de cmdlet.

Windows PowerShell reserva algunos nombres de parámetro para proporcionar


una experiencia de usuario coherente. No use estos nombres de parámetro:
WhatIf , , , , , , , Confirm y Verbose Debug Warn ErrorAction ErrorVariable

OutVariable OutBuffer . Además, se reservan los siguientes alias para estos

nombres de parámetro: vb , , , , y db ea ev ov ob .

Name es un nombre de parámetro simple y común, recomendado para su uso en

los cmdlets. Es mejor elegir un nombre de parámetro como este que un nombre
complejo que sea único para un cmdlet específico y difícil de recordar.

Los parámetros no tienen en cuenta mayúsculas Windows PowerShell, aunque de


forma predeterminada el shell conserva mayúsculas y minúsculas. La
confidencialidad de mayúsculas y minúsculas de los argumentos depende del
funcionamiento del cmdlet. Los argumentos se pasan a un parámetro como se
especifica en la línea de comandos.

Para obtener ejemplos de otras declaraciones de parámetros, vea Parámetros del


cmdlet.
Declarar parámetros como posicionales o con
nombre
Un cmdlet debe establecer cada parámetro como un parámetro posicional o con
nombre. Ambos tipos de parámetros aceptan argumentos únicos, varios argumentos
separados por comas y valores booleanos. Un parámetro booleano, también
denominado modificador, controla solo la configuración booleana. El modificador se usa
para determinar la presencia del parámetro . El valor predeterminado recomendado es
false .

El Get-Proc cmdlet de ejemplo define Name el parámetro como un parámetro posicional


con position 0. Esto significa que el primer argumento que el usuario escribe en la línea
de comandos se inserta automáticamente para este parámetro. Si desea definir un
parámetro con nombre, para el que el usuario debe especificar el nombre del parámetro
desde la línea de comandos, deje la palabra clave fuera de la Position declaración de
atributo.

7 Nota

A menos que se deba denominar a los parámetros, se recomienda que los


parámetros más usados sean posicionales para que los usuarios no tengan que
escribir el nombre del parámetro.

Declarar parámetros como obligatorios u


opcionales
Un cmdlet debe establecer cada parámetro como un parámetro opcional o obligatorio.
En el Get-Proc cmdlet de ejemplo, el parámetro se define Name como opcional porque
la palabra clave no está establecida en la declaración de Mandatory atributo.

Compatibilidad con la validación de


parámetros
El cmdlet de ejemplo agrega un atributo de validación de Get-Proc entrada,
System.Management.Automation.Validatenotnulloremptyattribute, al parámetro para
habilitar la validación de que la entrada no está ni Name null vacía. Este atributo es uno
de los varios atributos de validación proporcionados por Windows PowerShell. Para
obtener ejemplos de otros atributos de validación, vea Validating Parameter Input.
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
public string[] Name

Invalidar un método de procesamiento de


entrada
Si el cmdlet va a controlar la entrada de la línea de comandos, debe invalidar los
métodos de procesamiento de entrada adecuados. Los métodos básicos de
procesamiento de entrada se presentan en Creación del primer cmdlet.

El Get-Proc cmdlet invalida el método


System.Management.Automation.Cmdlet.ProcessRecord para controlar la entrada de
parámetros proporcionada por el usuario Name o un script. Este método obtiene los
procesos para cada nombre de proceso solicitado o todos para los procesos si no se
proporciona ningún nombre. Observe que en
System.Management.Automation.Cmdlet.ProcessRecord, la llamada a
System.Management.Automation.Cmdlet.WriteObject%28System.Object%2CSystem.Boo
lean%29 es el mecanismo de salida para enviar objetos de salida a la canalización. El
segundo parámetro de esta llamada, , se establece en para informar al runtime de
Windows PowerShell de que enumere la matriz de salida de objetos de proceso y
escriba un proceso cada vez en la línea de enumerateCollection true comandos.

C#

protected override void ProcessRecord()


{
// If no process names are passed to the cmdlet, get all processes.
if (processNames == null)
{
// Write the processes to the pipeline making them available
// to the next cmdlet. The second argument of this call tells
// PowerShell to enumerate the array, and send one process at a
// time to the pipeline.
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to the cmdlet, get and write
// the associated processes.
foreach (string name in processNames)
{
WriteObject(Process.GetProcessesByName(name), true);
}
}
}

VB

Protected Overrides Sub ProcessRecord()

'/ If no process names are passed to the cmdlet, get all processes.
If processNames Is Nothing Then
Dim processes As Process()
processes = Process.GetProcesses()
End If

'/ If process names are specified, write the processes to the


'/ pipeline to display them or make them available to the next cmdlet.

For Each name As String In processNames


'/ The second parameter of this call tells PowerShell to enumerate
the
'/ array, and send one process at a time to the pipeline.
WriteObject(Process.GetProcessesByName(name), True)
Next

End Sub 'ProcessRecord

Ejemplo de código
Para obtener el código de ejemplo completo de C#, vea GetProcessSample02 Sample.

Definir tipos de objeto y formato


Windows PowerShell pasa información entre cmdlets mediante .NET Framework objetos
. Por lo tanto, es posible que un cmdlet tenga que definir su propio tipo o que un
cmdlet tenga que ampliar un tipo existente proporcionado por otro cmdlet. Para
obtener más información sobre cómo definir nuevos tipos o ampliar los tipos existentes,
vea Extender tipos de objetos y Aplicar formatoa .

Compilar el cmdlet
Después de implementar un cmdlet, debe registrarlo con Windows PowerShell mediante
un Windows PowerShell complemento. Para obtener más información sobre cómo
registrar cmdlets, vea How to Register Cmdlets, Providers, and Host Applications.
Prueba del cmdlet
Cuando el cmdlet se registra con Windows PowerShell, puede probarlo ejecutándose en
la línea de comandos. Estas son dos maneras de probar el código para el cmdlet de
ejemplo. Para obtener más información sobre el uso de cmdlets desde la línea de
comandos, vea Tareas iniciales con Windows PowerShell.

En el Windows PowerShell, use el siguiente comando para enumerar el proceso


Internet Explorer, que se denomina "IEXPLORE".

PowerShell

get-proc -name iexplore

Aparece el siguiente resultado.

Output

Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
354 11 10036 18992 85 0.67 3284 iexplore

Para enumerar los procesos Internet Explorer, Outlook y Bloc de notas


denominados "IEXPLORE", "OUTLOOK" y "NOTEPAD", use el siguiente comando. Si
hay varios procesos, se muestran todos ellos.

PowerShell

get-proc -name iexplore, outlook, notepad

Aparece el siguiente resultado.

Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
732 21 24696 5000 138 2.25 2288 iexplore
715 19 20556 14116 136 1.78 3860 iexplore
3917 62 74096 58112 468 191.56 1848 OUTLOOK
39 2 1024 3280 30 0.09 1444 notepad
39 2 1024 356 30 0.08 3396 notepad

Consulte también
Adición de parámetros que procesan la entrada de la canalización

Creación del primer cmdlet

Extensión de tipos de objeto y formato

Cómo registrar cmdlets, proveedores y aplicaciones host

Referencia de Windows PowerShell

Ejemplos de cmdlet
Adición de parámetros que procesan la
entrada de la canalización
Artículo • 27/09/2021

Un origen de entrada para un cmdlet es un objeto de la canalización que se origina a


partir de un cmdlet ascendente. En esta sección se describe cómo agregar un parámetro
al cmdlet Get-Proc (descrito en Creación del primer cmdlet )para que el cmdlet pueda
procesar objetos de canalización.

Este cmdlet Get-Proc usa un parámetro que acepta la entrada de un objeto de


canalización, recupera la información del proceso del equipo local en función de los
nombres proporcionados y, a continuación, muestra información sobre los procesos en
la línea de Name comandos.

Definición de la clase cmdlet


El primer paso en la creación de cmdlets es asignar siempre un nombre al cmdlet y
declarar la clase .NET que implementa el cmdlet. Este cmdlet recupera la información del
proceso, por lo que el nombre del verbo elegido aquí es "Get". (Casi cualquier tipo de
cmdlet que sea capaz de recuperar información puede procesar la entrada de la línea de
comandos). Para obtener más información sobre los verbos de cmdlet aprobados, vea
Nombres de verbos de cmdlet.

A continuación se muestra la definición de este cmdlet Get-Proc. Los detalles de esta


definición se detallan en Creación del primer cmdlet.

C#

[Cmdlet(VerbsCommon.Get, "proc")]
public class GetProcCommand : Cmdlet

VB

<Cmdlet(VerbsCommon.Get, "Proc")> _
Public Class GetProcCommand
Inherits Cmdlet

Definición de la entrada de la canalización


En esta sección se describe cómo definir la entrada de la canalización para un cmdlet.
Este Get-Proc cmdlet define una propiedad que representa el parámetro como se
describe en Agregar parámetros que Name procesan la entrada de la línea de comandos.
(Vea ese tema para obtener información general sobre la declaración de parámetros).

Sin embargo, cuando un cmdlet necesita procesar la entrada de canalización, debe tener
sus parámetros enlazados a los valores de entrada por el Windows PowerShell
ejecución. Para ello, debe agregar la palabra clave o agregar la palabra clave a la
declaración de atributo ValueFromPipeline ValueFromPipelineByProperty
System.Management.Automation.Parameterattribute. Especifique la ValueFromPipeline
palabra clave si el cmdlet tiene acceso al objeto de entrada completo. Especifique si
ValueFromPipelineByProperty el cmdlet tiene acceso solo a una propiedad del objeto .

Esta es la declaración de parámetros para Name el parámetro de este cmdlet Get-Proc


que acepta la entrada de canalización.

C#

[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

VB

<Parameter(Position:=0, ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True), ValidateNotNullOrEmpty()> _
Public Property Name() As String()
Get
Return processNames
End Get

Set(ByVal value As String())


processNames = value
End Set

End Property

La declaración anterior establece la palabra clave en para que el tiempo de ejecución de


Windows PowerShell enlace el parámetro al objeto entrante si el objeto es del mismo
tipo que el parámetro o si se puede convertir al mismo ValueFromPipeline true tipo. La
palabra clave también se establece en para que Windows PowerShell tiempo de
ValueFromPipelineByPropertyName ejecución compruebe el objeto entrante para una

true Name propiedad. Si el objeto entrante tiene esta propiedad, el tiempo de ejecución
enlazará el parámetro a Name la propiedad del objeto Name entrante.

7 Nota

La configuración de la palabra ValueFromPipeline clave de atributo para un


parámetro tiene prioridad sobre la configuración de la palabra clave
ValueFromPipelineByPropertyName .

Invalidar un método de procesamiento de


entrada
Si el cmdlet va a controlar la entrada de canalización, debe invalidar los métodos de
procesamiento de entrada adecuados. Los métodos básicos de procesamiento de
entrada se presentan en Creación del primer cmdlet.

Este Get-Proc invalida el método


System.Management.Automation.Cmdlet.ProcessRecord para controlar la entrada de
parámetros proporcionada por el usuario Name o un script. Este método obtiene los
procesos para cada nombre de proceso solicitado o todos los procesos si no se
proporciona ningún nombre. Observe que en
System.Management.Automation.Cmdlet.ProcessRecord, la llamada a
WriteObject(System.Object,System.Boolean) es el mecanismo de salida para enviar
objetos de salida a la canalización. El segundo parámetro de esta llamada, , se establece
en para decir al tiempo de ejecución de Windows PowerShell que enumere la matriz de
objetos de proceso y escriba un proceso cada vez en la línea de enumerateCollection
true comandos.

C#

protected override void ProcessRecord()


{
// If no process names are passed to the cmdlet, get all processes.
if (processNames == null)
{
// Write the processes to the pipeline making them available
// to the next cmdlet. The second argument of this call tells
// PowerShell to enumerate the array, and send one process at a
// time to the pipeline.
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to the cmdlet, get and write
// the associated processes.
foreach (string name in processNames)
{
WriteObject(Process.GetProcessesByName(name), true);
} // End foreach (string name...).
}
}

VB

Protected Overrides Sub ProcessRecord()


Dim processes As Process()

'/ If no process names are passed to the cmdlet, get all processes.
If processNames Is Nothing Then
processes = Process.GetProcesses()
Else

'/ If process names are specified, write the processes to the


'/ pipeline to display them or make them available to the next
cmdlet.
For Each name As String In processNames
'/ The second parameter of this call tells PowerShell to
enumerate the
'/ array, and send one process at a time to the pipeline.
WriteObject(Process.GetProcessesByName(name), True)
Next
End If

End Sub 'ProcessRecord

Ejemplo de código
Para obtener el código de ejemplo completo de C#, vea GetProcessSample03 Sample.

Definir tipos de objeto y formato


Windows PowerShell pasa información entre cmdlets mediante objetos .Net. Por lo
tanto, es posible que un cmdlet tenga que definir su propio tipo o que el cmdlet tenga
que ampliar un tipo existente proporcionado por otro cmdlet. Para obtener más
información sobre cómo definir nuevos tipos o ampliar los tipos existentes, vea Extender
tipos de objetos y Aplicar formato a.
Compilar el cmdlet
Después de implementar un cmdlet, debe registrarse con Windows PowerShell
mediante un Windows PowerShell complemento. Para obtener más información sobre
cómo registrar cmdlets, vea How to Register Cmdlets, Providers, and Host
Applications .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con Windows PowerShell, ejec cándalo en la línea
de comandos. Por ejemplo, pruebe el código del cmdlet de ejemplo. Para obtener más
información sobre el uso de cmdlets desde la línea de comandos, vea el Tareas iniciales
con Windows PowerShell.

En el Windows PowerShell, escriba los siguientes comandos para recuperar los


nombres de proceso a través de la canalización.

PowerShell

PS> type ProcessNames | get-proc

Aparece el siguiente resultado.

Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName


------- ------ ----- ----- ----- ------ -- -----------
809 21 40856 4448 147 9.50 2288 iexplore
737 21 26036 16348 144 22.03 3860 iexplore
39 2 1024 388 30 0.08 3396 notepad
3927 62 71836 26984 467 195.19 1848 OUTLOOK

Escriba las líneas siguientes para obtener los objetos de proceso que tienen una
Name propiedad de los procesos denominados "IEXPLORE". En este ejemplo se usa

el cmdlet (proporcionado por Windows PowerShell) como comando ascendente


para recuperar los procesos Get-Process "IEXPLORE".

PowerShell

PS> get-process iexplore | get-proc

Aparece el siguiente resultado.


Handles NPM(K) PM(K) WS(K) VS(M) CPU(s) Id ProcessName
------- ------ ----- ----- ----- ------ -- -----------
801 21 40720 6544 142 9.52 2288 iexplore
726 21 25872 16652 138 22.09 3860 iexplore
801 21 40720 6544 142 9.52 2288 iexplore
726 21 25872 16652 138 22.09 3860 iexplore

Consulte también
Agregar parámetros que procesan la entrada de la línea de comandos

Creación del primer cmdlet

Extensión de tipos de objetos y formato

Cómo registrar cmdlets, proveedores y aplicaciones host

Referencia de Windows PowerShell

Ejemplos de cmdlet
Adición de informes de errores de no
terminación al cmdlet
Artículo • 24/09/2021

Los cmdlets pueden notificar errores no terminales llamando al método


System.Management.Automation.Cmdlet.WriteError y seguir funcionando en el objeto
de entrada actual o en otros objetos de canalización entrantes. En esta sección se
explica cómo crear un cmdlet que notifica errores no terminales de sus métodos de
procesamiento de entrada.

Para errores no terminales (así como errores de terminación), el cmdlet debe pasar un
objeto System.Management.Automation.ErrorRecord que identifique el error. Cada
registro de error se identifica mediante una cadena única denominada "identificador de
error". Además del identificador, la categoría de cada error se especifica mediante
constantes definidas por una enumeración
System.Management.Automation.ErrorCategory. El usuario puede ver los errores en
función de su categoría estableciendo la $ErrorView variable en "CategoryView".

Para obtener más información sobre los registros de errores, vea Windows PowerShell
Registros de errores.

Definición del cmdlet


El primer paso en la creación de cmdlets es asignar siempre un nombre al cmdlet y
declarar la clase .NET que implementa el cmdlet. Este cmdlet recupera la información del
proceso, por lo que el nombre del verbo elegido aquí es "Get". (Casi cualquier tipo de
cmdlet que sea capaz de recuperar información puede procesar la entrada de la línea de
comandos). Para obtener más información sobre los verbos de cmdlet aprobados, vea
Nombres de verbos de cmdlet.

A continuación se muestra la definición de este Get-Proc cmdlet. Los detalles de esta


definición se detallan en Creación del primer cmdlet.

C#

[Cmdlet(VerbsCommon.Get, "proc")]
public class GetProcCommand: Cmdlet

VB
<Cmdlet(VerbsCommon.Get, "Proc")> _
Public Class GetProcCommand
Inherits Cmdlet

Definición de parámetros
Si es necesario, el cmdlet debe definir parámetros para procesar la entrada. Este Get-
Proc cmdlet define un parámetro Name como se describe en Adding Parameters that
Process Command-Line Input (Agregar parámetros que procesan Command-Line
entrada).

Esta es la declaración de parámetro para el parámetro Name de este cmdlet Get-Proc.

C#

[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

VB

<Parameter(Position:=0, ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True), ValidateNotNullOrEmpty()> _
Public Property Name() As String()
Get
Return processNames
End Get

Set(ByVal value As String())


processNames = value
End Set

End Property
Invalidar métodos de procesamiento de
entrada
Todos los cmdlets deben invalidar al menos uno de los métodos de procesamiento de
entrada proporcionados por la clase System.Management.Automation.Cmdlet. Estos
métodos se de abordan en Creación del primer cmdlet.

7 Nota

El cmdlet debe controlar cada registro de la forma más independiente posible.

Este cmdlet Get-Proc invalida el método


System.Management.Automation.Cmdlet.ProcessRecord para controlar el parámetro
Name para la entrada proporcionada por el usuario o un script. Este método obtiene los
procesos de cada nombre de proceso solicitado o de todos los procesos si no se
proporciona ningún nombre. Los detalles de esta invalidación se detallan en Creación
del primer cmdlet.

Cosas que debe recordar al notificar errores


El objeto System.Management.Automation.ErrorRecord que el cmdlet pasa al escribir un
error requiere una excepción en su núcleo. Siga las instrucciones de .NET al determinar
la excepción que se usará. Básicamente, si el error es semánticamente el mismo que una
excepción existente, el cmdlet debe usar o derivar de esa excepción. De lo contrario,
debe derivar una nueva jerarquía de excepciones o excepciones directamente de la clase
System.Exception.

Al crear identificadores de error (a los que se accede a través de la propiedad


FullyQualifiedErrorId de la clase ErrorRecord), tenga en cuenta lo siguiente.

Use cadenas destinadas a fines de diagnóstico para que al inspeccionar el


identificador completo pueda determinar cuál es el error y de dónde salió el error.

Un identificador de error completo bien formado podría ser el siguiente.

CommandNotFoundException,Microsoft.PowerShell.Commands.GetCommandCommand

Observe que en el ejemplo anterior, el identificador de error (el primer token) designa
cuál es el error y la parte restante indica de dónde salió el error.

En escenarios más complejos, el identificador de error puede ser un token


separado por puntos que se puede analizar durante la inspección. Esto le permite
también bifurcar en las partes del identificador de error, así como el identificador
de error y la categoría de error.

El cmdlet debe asignar identificadores de error específicos a distintas rutas de acceso de


código. Tenga en cuenta la siguiente información para la asignación de identificadores
de error:

Un identificador de error debe permanecer constante a lo largo del ciclo de vida


del cmdlet. No cambie la semántica de un identificador de error entre las versiones
del cmdlet.
Use texto para un identificador de error que se corresponda con el error que se
notifica. No use espacios en blanco ni signos de puntuación.
Hacer que el cmdlet genere solo identificadores de error que se puedan
reproducir. Por ejemplo, no debe generar un identificador que incluya un
identificador de proceso. Los identificadores de error son útiles para un usuario
solo cuando corresponden a identificadores que otros usuarios ven que
experimentan el mismo problema.

PowerShell no detecta excepciones no controladas en las condiciones siguientes:

Si un cmdlet crea un nuevo subproceso y el código que se ejecuta en ese


subproceso produce una excepción no controlada, PowerShell no detectará el
error y finalizará el proceso.
Si un objeto tiene código en su destructor o métodos Dispose que produce una
excepción no controlada, PowerShell no detectará el error y finalizará el proceso.

Notificar errores no terminales


Cualquiera de los métodos de procesamiento de entrada puede notificar un error no
terminal al flujo de salida mediante el método
System.Management.Automation.Cmdlet.WriteError.

Este es un ejemplo de código de este cmdlet Get-Proc que muestra la llamada a


System.Management.Automation.Cmdlet.WriteError desde la invalidación del método
System.Management.Automation.Cmdlet.ProcessRecord. En este caso, la llamada se
realiza si el cmdlet no encuentra un proceso para un identificador de proceso
especificado.

C#

protected override void ProcessRecord()


{
// If no name parameter passed to cmdlet, get all processes.
if (processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If a name parameter is passed to cmdlet, get and write
// the associated processes.
// Write a nonterminating error for failure to retrieve
// a process.
foreach (string name in processNames)
{
Process[] processes;

try
{
processes = Process.GetProcessesByName(name);
}
catch (InvalidOperationException ex)
{
WriteError(new ErrorRecord(
ex,
"NameNotFound",
ErrorCategory.InvalidOperation,
name));
continue;
}

WriteObject(processes, true);
} // foreach (...
} // else
}

Cosas que debe recordar sobre la escritura de errores no


terminales
Para un error no terminal, el cmdlet debe generar un identificador de error específico
para cada objeto de entrada específico.

Con frecuencia, un cmdlet debe modificar la acción de PowerShell producida por un


error no terminal. Para ello, puede definir los ErrorAction parámetros ErrorVariable y .
Si define el parámetro , el cmdlet presenta las opciones de usuario ErrorAction
System.Management.Automation.ActionPreference, también puede influir directamente
en la acción estableciendo la $ErrorActionPreference variable .

El cmdlet puede guardar errores no terminales en una variable mediante el parámetro ,


que ErrorVariable no se ve afectado por la configuración de ErrorAction . Los errores
se pueden anexar a una variable de error existente agregando un signo más (+) al frente
del nombre de la variable.
Ejemplo de código
Para obtener el código de ejemplo completo de C#, vea GetProcessSample04 Sample.

Definir tipos de objeto y formato


PowerShell pasa información entre cmdlets mediante objetos .NET. Por lo tanto, es
posible que un cmdlet tenga que definir su propio tipo o que el cmdlet tenga que
ampliar un tipo existente proporcionado por otro cmdlet. Para obtener más información
sobre cómo definir nuevos tipos o ampliar los tipos existentes, vea Extender tipos de
objetos y Aplicar formatoa .

Compilar el cmdlet
Después de implementar un cmdlet, debe registrarlo con Windows PowerShell un
Windows PowerShell complemento. Para obtener más información sobre cómo registrar
cmdlets, vea How to Register Cmdlets, Providers, and Host Applications .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con PowerShell, puede probarlo ejecutándose en la
línea de comandos. Vamos a probar el ejemplo Get-Proc cmdlet para ver si informa de
un error:

Inicie PowerShell y use el cmdlet Get-Proc para recuperar los procesos


denominados "TEST".

PowerShell

get-proc -name test

Aparece el siguiente resultado.

get-proc : Operation is not valid due to the current state of the


object.
At line:1 char:9
+ get-proc <<<< -name test
Consulte también
Adición de parámetros que procesan la entrada de la canalización

Adición de parámetros que procesan Command-Line entrada

Creación del primer cmdlet

Extensión de tipos de objeto y formato

Cómo registrar cmdlets, proveedores y aplicaciones host

Referencia de Windows PowerShell

Ejemplos de cmdlet
Tutorial de StopProc
Artículo • 26/09/2021

En esta sección se proporciona un tutorial para crear el cmdlet Stop-Proc, que es muy
similar al cmdlet Stop-Process proporcionado por Windows PowerShell. En este tutorial
se proporcionan fragmentos de código que ilustran cómo se implementan los cmdlets y
una explicación del código.

Temas de este tutorial


Los temas de este tutorial están diseñados para leerse secuencialmente, con cada tema
en función de lo que se ha analizado en el tema anterior.

Creación de un cmdlet que modifica el sistema En esta sección se describe cómo crear
un cmdlet que admita modificaciones del sistema, como detener un proceso que se
ejecuta en el equipo.

Agregar mensajes de usuario al cmdlet En esta sección se describe cómo agregar la


capacidad de escribir mensajes de usuario, depurar mensajes, mensajes de advertencia e
información de progreso en el cmdlet.

Agregar alias, expansión de caracteres comodín y ayuda a parámetros de cmdlet En esta


sección se describe cómo crear un cmdlet que admita alias de parámetro, Ayuda y
expansión de caracteres comodín.

Agregar conjuntos de parámetros a cmdlets En esta sección se describe cómo agregar


conjuntos de parámetros a un cmdlet. Los conjuntos de parámetros permiten que el
cmdlet funcione de forma diferente en función de los parámetros especificados por el
usuario.

Consulte también
Creación de un cmdlet que modifica el sistema

Adición de mensajes de usuario al cmdlet

Adición de alias, expansión de caracteres comodín y Ayuda a los parámetros del cmdlet

Agregar conjuntos de parámetros a cmdlets

Windows PowerShell SDK


Creación de un cmdlet que modifica el
sistema
Artículo • 27/09/2021

A veces, un cmdlet debe modificar el estado de ejecución del sistema, no solo el estado
del entorno de ejecución Windows PowerShell ejecución. En estos casos, el cmdlet debe
permitir al usuario tener la oportunidad de confirmar si realiza o no el cambio.

Para admitir la confirmación, un cmdlet debe hacer dos cosas.

Declare que el cmdlet admite confirmación al especificar el atributo


System.Management.Automation.CmdletAttribute estableciendo la palabra clave
SupportsShouldProcess en true .

Llame a System.Management.Automation.Cmdlet.ShouldProcess durante la


ejecución del cmdlet (como se muestra en el ejemplo siguiente).

Al admitir la confirmación, un cmdlet expone los parámetros y proporcionados por


Windows PowerShell y también cumple las directrices de desarrollo de los cmdlets (para
obtener más información sobre las directrices de desarrollo de cmdlets, vea
Instrucciones de desarrollo de Confirm WhatIf cmdlets).

Cambiar el sistema
El acto de "cambiar el sistema" hace referencia a cualquier cmdlet que potencialmente
cambie el estado del sistema fuera de Windows PowerShell. Por ejemplo, detener un
proceso, habilitar o deshabilitar una cuenta de usuario o agregar una fila a una tabla de
base de datos son todos los cambios en el sistema que se deben confirmar. Por el
contrario, las operaciones que leen datos o establecen conexiones transitorias no
cambian el sistema y, por lo general, no requieren confirmación. La confirmación
tampoco es necesaria para las acciones cuyo efecto se limita a dentro del entorno
Windows PowerShell ejecución, como set-variable . Los cmdlets que podrían o no
realizar un cambio persistente deben declarar y llamar SupportsShouldProcess a
System.Management.Automation.Cmdlet.ShouldProcess solo si están a punto de realizar
un cambio persistente.

7 Nota

La confirmación de ShouldProcess solo se aplica a los cmdlets. Si un comando o


script modifica el estado de ejecución de un sistema llamando directamente a
métodos o propiedades de .NET o llamando a aplicaciones fuera de Windows
PowerShell, esta forma de confirmación no estará disponible.

El cmdlet StopProc
En este tema se describe un cmdlet Stop-Proc que intenta detener los procesos que se
recuperan mediante el cmdlet Get-Proc (descrito en Creación del primer cmdlet).

Definición del cmdlet


El primer paso en la creación de cmdlets es asignar siempre un nombre al cmdlet y
declarar la clase .NET que implementa el cmdlet. Dado que está escribiendo un cmdlet
para cambiar el sistema, debe denominarse en consecuencia. Este cmdlet detiene los
procesos del sistema, por lo que el nombre del verbo elegido aquí es "Stop", definido
por la clase System.Management.Automation.Verbslifecycle, con el nombre "Proc" para
indicar que el cmdlet detiene los procesos. Para obtener más información sobre los
verbos de cmdlet aprobados, vea Nombres de verbos de cmdlet.

A continuación se muestra la definición de clase para este cmdlet Stop-Proc.

C#

[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet

Tenga en cuenta que en la declaración


System.Management.Automation.CmdletAttribute, la palabra clave attribute se establece
en para permitir que el cmdlet realice llamadas a SupportsShouldProcess true
System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue. Sin este conjunto de palabras
clave, Confirm los parámetros y no WhatIf estarán disponibles para el usuario.

Acciones extremadamente destructivas


Algunas operaciones son extremadamente destructivas, como volver a formatear una
partición de disco duro activa. En estos casos, el cmdlet debe ConfirmImpact =
ConfirmImpact.High establecerse al declarar el atributo
System.Management.Automation.CmdletAttribute. Esta configuración obliga al cmdlet a
solicitar la confirmación del usuario incluso cuando el usuario no ha especificado el
Confirm parámetro . Sin embargo, los desarrolladores de cmdlets deben evitar el uso en

exceso de las operaciones que son potencialmente destructivas, como ConfirmImpact


eliminar una cuenta de usuario. Recuerde que si ConfirmImpact está establecido en
System.Management.Automation.ConfirmImpact High.

Del mismo modo, es poco probable que algunas operaciones sean destructivas, aunque
en teoría modifican el estado de ejecución de un sistema fuera de Windows PowerShell.
Estos cmdlets se pueden ConfirmImpact establecer en
System.Management.Automation.Confirmimpact.Low. Esto omitirá las solicitudes de
confirmación en las que el usuario ha pedido confirmar solo las operaciones de impacto
medio y alto impacto.

Definir parámetros para la modificación del


sistema
En esta sección se describe cómo definir los parámetros del cmdlet, incluidos los
necesarios para admitir la modificación del sistema. Consulte Adding Parameters that
Process CommandLine Input (Agregar parámetros que procesan la entrada de línea de
comandos) si necesita información general sobre cómo definir parámetros.

El cmdlet Stop-Proc define tres parámetros: Name Force , y PassThru .

El Name parámetro corresponde a la propiedad del objeto de entrada del Name proceso.
Tenga en cuenta que el parámetro de este ejemplo es obligatorio, ya que el cmdlet
producirá un error si no tiene un Name proceso con nombre para detenerse.

El Force parámetro permite al usuario invalidar las llamadas a


System.Management.Automation.Cmdlet.ShouldContinue. De hecho, cualquier cmdlet
que llame a System.Management.Automation.Cmdlet.ShouldContinue debe tener un
parámetro para que, cuando se especifique, el cmdlet omita la llamada a Force Force
System.Management.Automation.Cmdlet.ShouldContinue y continúe con la operación.
Tenga en cuenta que esto no afecta a las llamadas a
System.Management.Automation.Cmdlet.ShouldProcess.

El parámetro permite al usuario indicar si el cmdlet pasa un objeto de salida a través de


la canalización, en este caso, después de detener PassThru un proceso. Tenga en cuenta
que este parámetro está vinculado al propio cmdlet en lugar de a una propiedad del
objeto de entrada.

Esta es la declaración de parámetros para el cmdlet Stop-Proc.


C#

[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// Specify the Force parameter that allows the user to override
/// the ShouldContinue call to force the stop operation. This
/// parameter should always be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// Specify the PassThru parameter that allows the user to specify
/// that the cmdlet should pass the process object down the pipeline
/// after the process has been stopped.
/// </summary>
[Parameter]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;

Invalidar un método de procesamiento de


entrada
El cmdlet debe invalidar un método de procesamiento de entrada. El código siguiente
muestra la invalidación System.Management.Automation.Cmdlet.ProcessRecord usada
en el cmdlet de Stop-Proc ejemplo. Para cada nombre de proceso solicitado, este
método garantiza que el proceso no es un proceso especial, intenta detener el proceso
y, a continuación, envía un objeto de salida si se especifica PassThru el parámetro .
C#

protected override void ProcessRecord()


{
foreach (string name in processNames)
{
// For every process name passed to the cmdlet, get the associated
// process(es). For failures, write a non-terminating error
Process[] processes;

try
{
processes = Process.GetProcessesByName(name);
}
catch (InvalidOperationException ioe)
{
WriteError(new ErrorRecord(ioe,"Unable to access the target process by
name",
ErrorCategory.InvalidOperation, name));
continue;
}

// Try to stop the process(es) that have been retrieved for a name
foreach (Process process in processes)
{
string processName;

try
{
processName = process.ProcessName;
}

catch (Win32Exception e)
{
WriteError(new ErrorRecord(e, "ProcessNameNotFound",
ErrorCategory.ReadError, process));
continue;
}

// Call Should Process to confirm the operation first.


// This is always false if WhatIf is set.
if (!ShouldProcess(string.Format("{0} ({1})", processName,
process.Id)))
{
continue;
}
// Call ShouldContinue to make sure the user really does want
// to stop a critical process that could possibly stop the computer.
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower());

if (criticalProcess &&!force)
{
string message = String.Format
("The process \"{0}\" is a critical process and should not
be stopped. Are you sure you wish to stop the process?",
processName);

// It is possible that ProcessRecord is called multiple times


// when the Name parameter receives objects as input from the
// pipeline. So to retain YesToAll and NoToAll input that the
// user may enter across multiple calls to ProcessRecord, this
// information is stored as private members of the cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll,
ref noToAll))
{
continue;
}
} // if (criticalProcess...
// Stop the named process.
try
{
process.Kill();
}
catch (Exception e)
{
if ((e is Win32Exception) || (e is SystemException) ||
(e is InvalidOperationException))
{
// This process could not be stopped so write
// a non-terminating error.
string message = String.Format("{0} {1} {2}",
"Could not stop process \"", processName,
"\".");
WriteError(new ErrorRecord(e, message,
ErrorCategory.CloseError, process));
continue;
} // if ((e is...
else throw;
} // catch

// If the PassThru parameter argument is


// True, pass the terminated process on.
if (passThru)
{
WriteObject(process);
}
} // foreach (Process...
} // foreach (string...
} // ProcessRecord

Llamar al método ShouldProcess


El método de procesamiento de entrada del cmdlet debe llamar al método
System.Management.Automation.Cmdlet.ShouldProcess para confirmar la ejecución de
una operación antes de realizar un cambio (por ejemplo, la eliminación de archivos) en
el estado en ejecución del sistema. Esto permite que Windows PowerShell tiempo de
ejecución proporcione el comportamiento correcto "WhatIf" y "Confirm" dentro del
shell.

7 Nota

Si un cmdlet indica que admite debe procesarse y no puede realizar la llamada


System.Management.Automation.Cmdlet.ShouldProcess, el usuario podría
modificar el sistema de forma inesperada.

La llamada a System.Management.Automation.Cmdlet.ShouldProcess envía el nombre


del recurso que se va a cambiar al usuario, con el tiempo de ejecución de Windows
PowerShell teniendo en cuenta cualquier configuración de línea de comandos o
variables de preferencia para determinar lo que se debe mostrar al usuario.

En el ejemplo siguiente se muestra la llamada a


System.Management.Automation.Cmdlet.ShouldProcess desde la invalidación del
método System.Management.Automation.Cmdlet.ProcessRecord en el cmdlet Stop-Proc
ejemplo.

C#

if (!ShouldProcess(string.Format("{0} ({1})", processName,


process.Id)))
{
continue;
}

Llamar al método ShouldContinue


La llamada al método System.Management.Automation.Cmdlet.ShouldContinue envía
un mensaje secundario al usuario. Esta llamada se realiza después de que se devuelva la
llamada a System.Management.Automation.Cmdlet.ShouldProcess y si el parámetro
true no se Force estableció en true . A continuación, el usuario puede proporcionar
comentarios para decir si la operación debe continuar. El cmdlet llama a
System.Management.Automation.Cmdlet.ShouldContinue como una comprobación
adicional de las modificaciones potencialmente peligrosas del sistema o cuando quiera
proporcionar al usuario opciones "sí a todo" y "no a todo".

En el ejemplo siguiente se muestra la llamada a


System.Management.Automation.Cmdlet.ShouldContinue desde la invalidación del
método System.Management.Automation.Cmdlet.ProcessRecord en el cmdlet Stop-Proc
ejemplo.

C#

if (criticalProcess &&!force)
{
string message = String.Format
("The process \"{0}\" is a critical process and should not be
stopped. Are you sure you wish to stop the process?",
processName);

// It is possible that ProcessRecord is called multiple times


// when the Name parameter receives objects as input from the
// pipeline. So to retain YesToAll and NoToAll input that the
// user may enter across multiple calls to ProcessRecord, this
// information is stored as private members of the cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll,
ref noToAll))
{
continue;
}
} // if (criticalProcess...

Detener el procesamiento de entrada


El método de procesamiento de entrada de un cmdlet que realiza modificaciones del
sistema debe proporcionar una manera de detener el procesamiento de la entrada. En el
caso de este cmdlet Stop-Proc, se realiza una llamada desde el método
System.Management.Automation.Cmdlet.ProcessRecord al método
System.Diagnostics.Process.Kill*. Dado que el parámetro está establecido en PassThru
true , System.Management.Automation.Cmdlet.ProcessRecord también llama a

System.Management.Automation.Cmdlet.WriteObject para enviar el objeto de proceso a


la canalización.

Ejemplo de código
Para obtener el código de ejemplo completo de C#, vea Ejemplo StopProcessSample01.

Definir tipos de objeto y formato


Windows PowerShell pasa información entre cmdlets mediante objetos .Net. Por lo
tanto, es posible que un cmdlet tenga que definir su propio tipo o que el cmdlet tenga
que ampliar un tipo existente proporcionado por otro cmdlet. Para obtener más
información sobre cómo definir nuevos tipos o ampliar los tipos existentes, vea Extender
tipos de objetos y Aplicar formato a.

Compilar el cmdlet
Después de implementar un cmdlet, se debe registrar con Windows PowerShell a través
de un Windows PowerShell complemento. Para obtener más información sobre cómo
registrar cmdlets, vea How to Register Cmdlets, Providers, and Host Applications .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con Windows PowerShell, puede probarlo
ejecutándose en la línea de comandos. Estas son varias pruebas que prueban el cmdlet
Stop-Proc. Para obtener más información sobre el uso de cmdlets desde la línea de
comandos, vea el Tareas iniciales con Windows PowerShell.

Inicie Windows PowerShell y use el cmdlet Stop-Proc para detener el


procesamiento, como se muestra a continuación. Dado que el cmdlet especifica el
Name parámetro como obligatorio, el cmdlet consulta el parámetro .

PowerShell

PS> stop-proc

Aparece el siguiente resultado.

Cmdlet stop-proc at command pipeline position 1


Supply values for the following parameters:
Name[0]:

Ahora vamos a usar el cmdlet para detener el proceso denominado "NOTEPAD". El


cmdlet le pide que confirme la acción.

PowerShell

PS> stop-proc -Name notepad

Aparece el siguiente resultado.


Confirm
Are you sure you want to perform this action?
Performing operation "stop-proc" on Target "notepad (4996)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y

Use Stop-Proc como se muestra para detener el proceso crítico denominado


"WINLOGON". Se le pedirá y le advertirá sobre la realización de esta acción porque
hará que el sistema operativo se reinicie.

PowerShell

PS> stop-proc -Name Winlogon

Aparece el siguiente resultado.

Output

Confirm
Are you sure you want to perform this action?
Performing operation "stop-proc" on Target "winlogon (656)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
Warning!
The process " winlogon " is a critical process and should not be
stopped. Are you sure you wish to stop the process?
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N

Ahora vamos a intentar detener el proceso winlogon sin recibir una advertencia.
Tenga en cuenta que esta entrada de comando usa Force el parámetro para
invalidar la advertencia.

PowerShell

PS> stop-proc -Name winlogon -Force

Aparece el siguiente resultado.

Output

Confirm
Are you sure you want to perform this action?
Performing operation "stop-proc" on Target "winlogon (656)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N

Consulte también
Adición de parámetros que procesan Command-Line entrada

Extensión de tipos de objeto y formato

Cómo registrar cmdlets, proveedores y aplicaciones host

Windows PowerShell SDK

Ejemplos de cmdlet
Adición de mensajes de usuario al
cmdlet
Artículo • 24/09/2021

Los cmdlets pueden escribir varios tipos de mensajes que el entorno de ejecución de
Windows PowerShell puede mostrar al usuario. Estos mensajes incluyen los siguientes
tipos:

Mensajes detallados que contienen información general del usuario.

Depuración de mensajes que contienen información de solución de problemas.

Mensajes de advertencia que contienen una notificación de que el cmdlet está a


punto de realizar una operación que puede tener resultados inesperados.

Mensajes de informe de progreso que contienen información sobre cuánto trabajo


ha completado el cmdlet al realizar una operación que tarda mucho tiempo.

No hay límites en el número de mensajes que el cmdlet puede escribir ni en el tipo de


mensajes que escribe el cmdlet. Cada mensaje se escribe realizando una llamada
específica desde el método de procesamiento de entrada del cmdlet.

Definición del cmdlet


El primer paso en la creación de cmdlets es asignar siempre un nombre al cmdlet y
declarar la clase .NET que implementa el cmdlet. Cualquier tipo de cmdlet puede escribir
notificaciones de usuario desde sus métodos de procesamiento de entrada; por lo tanto,
en general, puede nombrar este cmdlet mediante cualquier verbo que indique qué
modificaciones del sistema realiza el cmdlet. Para obtener más información sobre los
verbos de cmdlet aprobados, vea Nombres de verbos de cmdlet.

El cmdlet Stop-Proc está diseñado para modificar el sistema; Por lo tanto, la declaración
System.Management.Automation.CmdletAttribute de la clase .NET debe incluir la
palabra clave SupportsShouldProcess attribute y establecerse en true .

El código siguiente es la definición de esta Stop-Proc cmdlet. Para obtener más


información sobre esta definición, vea Crear un cmdlet que modifica el sistema.

C#

[Cmdlet(VerbsLifecycle.Stop, "proc",
SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet

Definir parámetros para la modificación del


sistema
El cmdlet Stop-Proc define tres parámetros: Name Force , y PassThru . Para obtener más
información sobre cómo definir estos parámetros, vea Crear un cmdlet que modifica el
sistema.

Esta es la declaración de parámetros para el cmdlet Stop-Proc.

C#

[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// Specify the Force parameter that allows the user to override
/// the ShouldContinue call to force the stop operation. This
/// parameter should always be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// Specify the PassThru parameter that allows the user to specify
/// that the cmdlet should pass the process object down the pipeline
/// after the process has been stopped.
/// </summary>
[Parameter]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;

Invalidar un método de procesamiento de


entrada
El cmdlet debe invalidar un método de procesamiento de entrada, con frecuencia será
System.Management.Automation.Cmdlet.ProcessRecord. Este Stop-Proc cmdlet invalida
el método de procesamiento de entrada
System.Management.Automation.Cmdlet.ProcessRecord. En esta implementación del
cmdlet Stop-Proc, se realizan llamadas para escribir mensajes detallados, depurar
mensajes y mensajes de advertencia.

7 Nota

Para obtener más información sobre cómo este método llama a los métodos
System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue, vea Creating a Cmdlet
that Modifes the System.

Escribir un mensaje detallado


El método System.Management.Automation.Cmdlet.WriteVerbose se usa para escribir
información general de nivel de usuario que no está relacionada con condiciones de
error específicas. A continuación, el administrador del sistema puede usar esa
información para continuar procesando otros comandos. Además, cualquier información
escrita con este método debe localizarse según sea necesario.

El código siguiente de este cmdlet Stop-Proc muestra dos llamadas al método


System.Management.Automation.Cmdlet.WriteVerbose desde la invalidación del
método System.Management.Automation.Cmdlet.ProcessRecord.

C#

message = String.Format("Attempting to stop process \"{0}\".", name);


WriteVerbose(message);

C#
message = String.Format("Stopped process \"{0}\", pid {1}.",
processName, process.Id);

WriteVerbose(message);

Escribir un mensaje de depuración


El método System.Management.Automation.Cmdlet.WriteDebug se usa para escribir
mensajes de depuración que se pueden usar para solucionar problemas del
funcionamiento del cmdlet. La llamada se realiza desde un método de procesamiento
de entrada.

7 Nota

Windows PowerShell define un Debug parámetro que presenta información


detallada y de depuración. Si el cmdlet admite este parámetro, no es necesario
llamar a System.Management.Automation.Cmdlet.WriteDebug en el mismo
código que llama a System.Management.Automation.Cmdlet.WriteVerbose.

Las dos secciones de código siguientes del cmdlet Stop-Proc de ejemplo muestran
llamadas al método System.Management.Automation.Cmdlet.WriteDebug desde la
invalidación del método System.Management.Automation.Cmdlet.ProcessRecord.

Este mensaje de depuración se escribe inmediatamente antes de llamar a


System.Management.Automation.Cmdlet.ShouldProcess.

C#

message =
String.Format("Acquired name for pid {0} : \"{1}\"",
process.Id, processName);
WriteDebug(message);

Este mensaje de depuración se escribe inmediatamente antes de llamar a


System.Management.Automation.Cmdlet.WriteObject.

C#

message =
String.Format("Writing process \"{0}\" to pipeline",
processName);
WriteDebug(message);
WriteObject(process);
Windows PowerShell enruta automáticamente cualquier llamada a
System.Management.Automation.Cmdlet.WriteDebug a la infraestructura y los cmdlets
de seguimiento. Esto permite realizar un seguimiento de las llamadas de método a la
aplicación de hospedaje, un archivo o un depurador sin tener que realizar ningún
trabajo de desarrollo adicional dentro del cmdlet . La siguiente entrada de línea de
comandos implementa una operación de seguimiento.

PS> trace-expression stop-proc -file proc.log -command stop-proc notepad

Escribir un mensaje de advertencia


El método System.Management.Automation.Cmdlet.WriteWarning se usa para escribir
una advertencia cuando el cmdlet está a punto de realizar una operación que podría
tener un resultado inesperado, por ejemplo, sobrescribir un archivo de solo lectura.

El código siguiente del cmdlet Stop-Proc muestra la llamada al método


System.Management.Automation.Cmdlet.WriteWarning desde la invalidación del
método System.Management.Automation.Cmdlet.ProcessRecord.

C#

if (criticalProcess)
{
message =
String.Format("Stopping the critical process \"{0}\".",
processName);
WriteWarning(message);
} // if (criticalProcess...

Escribir un mensaje de progreso


System.Management.Automation.Cmdlet.WriteProgress se usa para escribir mensajes de
progreso cuando las operaciones de cmdlet tardaron mucho tiempo en completarse.
Una llamada a System.Management.Automation.Cmdlet.WriteProgress pasa un objeto
System.Management.Automation.Progressrecord que se envía a la aplicación de
hospedaje para representarlo al usuario.

7 Nota

Este Stop-Proc cmdlet no incluye una llamada al método


System.Management.Automation.Cmdlet.WriteProgress.
El código siguiente es un ejemplo de un mensaje de progreso escrito por un cmdlet que
está intentando copiar un elemento.

C#

int myId = 0;
string myActivity = "Copy-item: Copying *.* to c:\abc";
string myStatus = "Copying file bar.txt";
ProgressRecord pr = new ProgressRecord(myId, myActivity, myStatus);
WriteProgress(pr);

pr.RecordType = ProgressRecordType.Completed;
WriteProgress(pr);

Ejemplo de código
Para obtener el código de ejemplo completo de C#, vea StopProcessSample02 Sample.

Definir tipos de objeto y formato


Windows PowerShell pasa información entre cmdlets mediante objetos .NET. Por lo
tanto, es posible que un cmdlet tenga que definir su propio tipo o que el cmdlet tenga
que ampliar un tipo existente proporcionado por otro cmdlet. Para obtener más
información sobre cómo definir nuevos tipos o ampliar los tipos existentes, vea Extender
tipos de objetos y Aplicar formato a.

Compilar el cmdlet
Después de implementar un cmdlet, se debe registrar con Windows PowerShell a través
de un Windows PowerShell complemento. Para obtener más información sobre cómo
registrar cmdlets, vea How to Register Cmdlets, Providers, and Host Applications .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con Windows PowerShell, puede probarlo
ejecutándose en la línea de comandos. Vamos a probar el cmdlet de Stop-Proc ejemplo.
Para obtener más información sobre el uso de cmdlets desde la línea de comandos, vea
el Tareas iniciales con Windows PowerShell.

La siguiente entrada de línea de comandos usa Stop-Proc para detener el proceso


denominado "NOTEPAD", proporcionar notificaciones detalladas e imprimir
información de depuración.

PowerShell

PS> stop-proc -Name notepad -Verbose -Debug

Aparece el siguiente resultado.

VERBOSE: Attempting to stop process " notepad ".


DEBUG: Acquired name for pid 5584 : "notepad"

Confirm
Continue with this operation?
[Y] Yes [A] Yes to All [H] Halt Command [S] Suspend [?] Help
(default is "Y"): Y

Confirm
Are you sure you want to perform this action?
Performing operation "stop-proc" on Target "notepad (5584)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y
VERBOSE: Stopped process "notepad", pid 5584.

Consulte también
Creación de un cmdlet que modifica el sistema

Cómo crear un cmdlet Windows PowerShell

Extensión de tipos de objeto y formato

Cómo registrar cmdlets, proveedores y aplicaciones host

Windows PowerShell SDK


Adición de alias, expansión de
caracteres comodín y Ayuda a los
parámetros del cmdlet
Artículo • 13/05/2022

En esta sección se describe cómo agregar alias, expansión de caracteres comodín y


mensajes de Ayuda a los parámetros del Stop-Proc cmdlet (descrito en Creación de un
cmdlet que modifica el sistema).

Este Stop-Proc cmdlet intenta detener los procesos que se recuperan mediante el Get-
Proc cmdlet (descrito en Creating Your First Cmdlet).

Definición del cmdlet


El primer paso en la creación de cmdlets siempre es asignar un nombre al cmdlet y
declarar la clase .NET que implementa el cmdlet. Dado que está escribiendo un cmdlet
para cambiar el sistema, debe denominarse en consecuencia. Dado que este cmdlet
detiene los procesos del sistema, usa el verbo Stop, definido por la clase
System.Management.Automation.Verbslifecycle, con el sustantivo Proc para indicar el
proceso. Para obtener más información sobre los verbos de cmdlet aprobados, vea
Nombres de verbos de cmdlet.

El código siguiente es la definición de clase de este Stop-Proc cmdlet.

C#

[Cmdlet(VerbsLifecycle.Stop, "proc",
SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet

Definición de parámetros para la modificación


del sistema
El cmdlet debe definir parámetros que admitan modificaciones del sistema y
comentarios de los usuarios. El cmdlet debe definir un parámetro Name o equivalente
para que el cmdlet pueda modificar el sistema por algún tipo de identificador. Además,
el cmdlet debe definir los parámetros Force y PassThru . Para obtener más información
sobre estos parámetros, vea Creación de un cmdlet que modifica el sistema.
Definición de un alias de parámetro
Un alias de parámetro puede ser un nombre alternativo o un nombre corto bien
definido de 1 o 2 letras para un parámetro de cmdlet. En ambos casos, el objetivo de
usar alias es simplificar la entrada de usuario desde la línea de comandos. Windows
PowerShell admite alias de parámetro a través del atributo
System.Management.Automation.Aliasattribute, que usa la sintaxis [Alias()] de
declaración .

En el código siguiente se muestra cómo se agrega un alias al parámetro Name .

C#

/// <summary>
/// Specify the mandatory Name parameter used to identify the
/// processes to be stopped.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The name of one or more processes to stop.
Wildcards are permitted."
)]
[Alias("ProcessName")]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

Además de usar el atributo System.Management.Automation.Aliasattribute, el tiempo de


ejecución de Windows PowerShell realiza la coincidencia de nombres parciales, incluso
si no se especifica ningún alias. Por ejemplo, si el cmdlet tiene un parámetro FileName y
que es el único parámetro que comienza con F , el usuario podría escribir Filename , ,
File``Filenam``Fi , o y F seguir reconocendo la entrada como parámetro FileName.

Creación de ayuda para parámetros


Windows PowerShell permite crear ayuda para parámetros de cmdlet. Haga esto para
cualquier parámetro que se use para la modificación del sistema y los comentarios de
los usuarios. Para cada parámetro que admita ayuda, puede establecer la palabra clave
del atributo HelpMessage en la declaración de atributo
System.Management.Automation.Parameterattribute. Esta palabra clave define el texto
que se va a mostrar al usuario para obtener ayuda al usar el parámetro . También puede
establecer la palabra clave HelpMessageBaseName para identificar el nombre base de
un recurso que se va a usar para el mensaje. Si establece esta palabra clave, también
debe establecer la palabra clave HelpMessageResourceId para especificar el
identificador de recurso.

El código siguiente de este Stop-Proc cmdlet define la palabra clave del atributo
HelpMessage para el parámetro Name .

C#

/// <summary>
/// Specify the mandatory Name parameter used to identify the
/// processes to be stopped.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The name of one or more processes to stop.
Wildcards are permitted."
)]

Invalidación de un método de procesamiento


de entrada
El cmdlet debe invalidar un método de procesamiento de entrada, normalmente será
System.Management.Automation.Cmdlet.ProcessRecord. Al modificar el sistema, el
cmdlet debe llamar a los métodos
System.Management.Automation.Cmdlet.ShouldProcess y
System.Management.Automation.Cmdlet.ShouldContinue para permitir al usuario
proporcionar comentarios antes de realizar un cambio. Para obtener más información
sobre estos métodos, vea Creación de un cmdlet que modifica el sistema.

Compatibilidad con la expansión de caracteres


comodín
Para permitir la selección de varios objetos, el cmdlet puede usar las clases
System.Management.Automation.WildcardPattern y
System.Management.Automation.WildcardOptions para proporcionar compatibilidad
con la expansión de caracteres comodín para la entrada de parámetros. Algunos
ejemplos de patrones de caracteres comodín son lsa* , *.txt y [a-c]* . Use el carácter
de comillas inversas ( ` ) como carácter de escape cuando el patrón contenga un
carácter que se debe usar literalmente.

Las expansiones con caracteres comodín de nombres de archivo y ruta de acceso son
ejemplos de escenarios comunes en los que el cmdlet puede permitir la compatibilidad
con las entradas de ruta de acceso cuando se requiere la selección de varios objetos. Un
caso común es en el sistema de archivos, donde un usuario quiere ver todos los archivos
que residen en la carpeta actual.

Debe necesitar una implementación personalizada de coincidencia de patrones


comodín solo en raras ocasiones. En este caso, el cmdlet debe admitir la especificación
POSIX 1003.2, 3.13 completa para la expansión de caracteres comodín o el siguiente
subconjunto simplificado:

Signo de interrogación ( ? ). Coincide con cualquier carácter en la ubicación


especificada.
Asterisco ( * ). Coincide con cero o más caracteres a partir de la ubicación
especificada.
Corchete abierto ( [ ). Presenta una expresión de corchete de patrón que puede
contener caracteres o un intervalo de caracteres. Si se requiere un intervalo, se usa
un guión ( - ) para indicar el intervalo.
Corchete de cierre ( ] ). Finaliza una expresión de corchete de patrón.
Carácter de escape entre comillas inversas ( ` ). Indica que se debe tomar
literalmente el siguiente carácter. Tenga en cuenta que al especificar el carácter de
comillas inversas de la línea de comandos (en lugar de especificarlo mediante
programación), el carácter de escape entre comillas inversas debe especificarse
dos veces.

7 Nota

Para obtener más información sobre los patrones de caracteres comodín, consulte
Compatibilidad con caracteres comodín en parámetros de cmdlet.

En el código siguiente se muestra cómo establecer las opciones de caracteres comodín


y definir el patrón de caracteres comodín que se usa para resolver el parámetro Name
para este cmdlet.

C#
WildcardOptions options = WildcardOptions.IgnoreCase |
WildcardOptions.Compiled;
WildcardPattern wildcard = new WildcardPattern(name,options);

En el código siguiente se muestra cómo probar si el nombre del proceso coincide con el
patrón de caracteres comodín definido. Tenga en cuenta que, en este caso, si el nombre
del proceso no coincide con el patrón, el cmdlet continúa para obtener el siguiente
nombre de proceso.

C#

if (!wildcard.IsMatch(processName))
{
continue;
}

Ejemplo de código
Para obtener el código de ejemplo de C# completo, consulte Ejemplo
StopProcessSample03.

Definir tipos de objeto y formato


Windows PowerShell pasa información entre cmdlets mediante objetos .Net. Por lo
tanto, es posible que un cmdlet tenga que definir su propio tipo o que el cmdlet
necesite ampliar un tipo existente proporcionado por otro cmdlet. Para obtener más
información sobre cómo definir nuevos tipos o extender los tipos existentes, vea
Extensión de tipos de objetos y formato .

Compilación del cmdlet


Después de implementar un cmdlet, debe registrarse con Windows PowerShell a través
de un complemento de Windows PowerShell. Para obtener más información sobre cómo
registrar cmdlets, consulte Registro de cmdlets, proveedores y aplicaciones host .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con Windows PowerShell, puede probarlo
ejecutándolo en la línea de comandos. Vamos a probar el cmdlet Stop-Proc de ejemplo.
Para obtener más información sobre el uso de cmdlets desde la línea de comandos,
consulte la Introducción con Windows PowerShell.

Inicie Windows PowerShell y use Stop-Proc para detener un proceso mediante el


alias ProcessName para el parámetro Name.

PowerShell

PS> Stop-Proc -ProcessName notepad

Aparece el siguiente resultado.

Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Proc" on Target "notepad (3496)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y

Realice la siguiente entrada en la línea de comandos. Dado que el parámetro


Name es obligatorio, se le pedirá. Al escribir !? se abre el texto de ayuda asociado
al parámetro .

PowerShell

PS> Stop-Proc

Aparece el siguiente resultado.

Cmdlet Stop-Proc at command pipeline position 1


Supply values for the following parameters:
(Type !? for Help.)
Name[0]: !?
The name of one or more processes to stop. Wildcards are permitted.
Name[0]: notepad

Ahora, realice la siguiente entrada para detener todos los procesos que coincidan
con el patrón *note* de caracteres comodín . Se le pedirá antes de detener cada
proceso que coincida con el patrón.

PowerShell
PS> Stop-Proc -Name *note*

Aparece el siguiente resultado.

Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Proc" on Target "notepad (1112)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y

Aparece el siguiente resultado.

Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Proc" on Target "ONENOTEM (3712)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N

Aparece el siguiente resultado.

Confirm
Are you sure you want to perform this action?
Performing operation "Stop-Proc" on Target "ONENOTE (3592)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N

Consulte también
Crear un cmdlet que modifique el sistema
Creación de un cmdlet de Windows PowerShell
Extensión de tipos de objeto y formato
Cómo registrar cmdlets, proveedores y aplicaciones host
Compatibilidad con caracteres comodín en parámetros de cmdlet
Windows PowerShell SDK
Adición de conjuntos de parámetros a
un cmdlet
Artículo • 27/09/2021

Aspectos que debe saber sobre los conjuntos


de parámetros
Windows PowerShell define un conjunto de parámetros como un grupo de parámetros
que funcionan juntos. Al agrupar los parámetros de un cmdlet, puede crear un único
cmdlet que pueda cambiar su funcionalidad en función del grupo de parámetros que
especifique el usuario.

Un ejemplo de un cmdlet que usa dos conjuntos de parámetros para definir


funcionalidades diferentes es el cmdlet proporcionado Get-EventLog por Windows
PowerShell. Este cmdlet devuelve información diferente cuando el usuario especifica el
List parámetro LogName o . Si se LogName especifica el parámetro , el cmdlet devuelve

información sobre los eventos de un registro de eventos determinado. Si se especifica el


parámetro , el cmdlet devuelve información sobre los propios archivos de List registro
(no la información del evento que contienen). En este caso, los parámetros List y
identifican dos conjuntos de parámetros LogName independientes.

Dos aspectos importantes que hay que recordar sobre los conjuntos de parámetros es
que el entorno de ejecución de Windows PowerShell solo usa un conjunto de
parámetros para una entrada determinada y que cada conjunto de parámetros debe
tener al menos un parámetro que sea único para ese conjunto de parámetros.

Para ilustrar ese último punto, este cmdlet Stop-Proc usa tres conjuntos de parámetros:
ProcessName ProcessId , y InputObject . Cada uno de estos conjuntos de parámetros
tiene un parámetro que no está en los otros conjuntos de parámetros. Los conjuntos de
parámetros podrían compartir otros parámetros, pero el cmdlet usa los parámetros
únicos , y para identificar qué conjunto de parámetros debe usar el entorno Windows
PowerShell ProcessName ProcessId InputObject runtime.

Declarar la clase cmdlet


El primer paso en la creación de cmdlets es asignar siempre un nombre al cmdlet y
declarar la clase de .NET que implementa el cmdlet. Para este cmdlet, se usa el verbo de
ciclo de vida "Stop" porque el cmdlet detiene los procesos del sistema. El nombre "Proc"
se usa porque el cmdlet funciona en procesos. En la declaración siguiente, tenga en
cuenta que el verbo del cmdlet y el nombre del sustantivo se reflejan en el nombre de la
clase de cmdlet.

7 Nota

Para obtener más información sobre los nombres de verbos de cmdlet aprobados,
vea Nombres de verbos de cmdlet.

El código siguiente es la definición de clase para este cmdlet Stop-Proc.

C#

[Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName = "ProcessId",
SupportsShouldProcess = true)]
public class StopProcCommand : PSCmdlet

VB

<Cmdlet(VerbsLifecycle.Stop, "Proc", DefaultParameterSetName:="ProcessId", _


SupportsShouldProcess:=True)> _
Public Class StopProcCommand
Inherits PSCmdlet

Declarar los parámetros del cmdlet


Este cmdlet define tres parámetros necesarios como entrada para el cmdlet (estos
parámetros también definen los conjuntos de parámetros), así como un parámetro que
administra lo que hace el cmdlet y un parámetro que determina si el cmdlet envía un
objeto de salida a través de la Force PassThru canalización. De forma predeterminada,
este cmdlet no pasa un objeto a través de la canalización. Para obtener más información
sobre estos dos últimos parámetros, vea Crear un cmdlet que modifica el sistema.

Declarar el parámetro Name


Este parámetro de entrada permite al usuario especificar los nombres de los procesos
que se deben detener. Tenga en cuenta que la palabra clave attribute del atributo
ParameterSetName System.Management.Automation.Parameterattribute especifica el

ProcessName conjunto de parámetros para este parámetro.


C#

[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The name of one or more processes to stop. Wildcards are
permitted."
)]
[Alias("ProcessName")]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

VB

<Parameter(Position:=0, ParameterSetName:="ProcessName", _
Mandatory:=True, _
ValueFromPipeline:=True, ValueFromPipelineByPropertyName:=True, _
HelpMessage:="The name of one or more processes to stop. " & _
"Wildcards are permitted."), [Alias]("ProcessName")> _
Public Property Name() As String()
Get
Return processNames
End Get
Set(ByVal value As String())
processNames = value
End Set
End Property

Private processNames() As String

Tenga en cuenta también que el alias "ProcessName" se proporciona a este parámetro.

Declarar el parámetro Id
Este parámetro de entrada permite al usuario especificar los identificadores de los
procesos que se deben detener. Tenga en cuenta que la palabra clave de atributo del
atributo ParameterSetName System.Management.Automation.Parameterattribute
especifica el conjunto ProcessId de parámetros.

C#
[Parameter(
ParameterSetName = "ProcessId",
Mandatory = true,
ValueFromPipelineByPropertyName = true,
ValueFromPipeline = true
)]
[Alias("ProcessId")]
public int[] Id
{
get { return processIds; }
set { processIds = value; }
}
private int[] processIds;

VB

<Parameter(ParameterSetName:="ProcessId", _
Mandatory:=True, _
ValueFromPipelineByPropertyName:=True, _
ValueFromPipeline:=True), [Alias]("ProcessId")> _
Public Property Id() As Integer()
Get
Return processIds
End Get
Set(ByVal value As Integer())
processIds = value
End Set
End Property
Private processIds() As Integer

Tenga en cuenta también que el alias "ProcessId" se proporciona a este parámetro.

Declarar el parámetro InputObject


Este parámetro de entrada permite al usuario especificar un objeto de entrada que
contiene información sobre los procesos que se deben detener. Tenga en cuenta que la
palabra clave attribute del atributo ParameterSetName
System.Management.Automation.Parameterattribute especifica el InputObject conjunto
de parámetros para este parámetro.

C#

[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
public Process[] InputObject
{
get { return inputObject; }
set { inputObject = value; }
}
private Process[] inputObject;

VB

<Parameter(ParameterSetName:="InputObject", _
Mandatory:=True, ValueFromPipeline:=True)> _
Public Property InputObject() As Process()
Get
Return myInputObject
End Get
Set(ByVal value As Process())
myInputObject = value
End Set
End Property
Private myInputObject() As Process

Tenga en cuenta también que este parámetro no tiene ningún alias.

Declarar parámetros en varios conjuntos de parámetros


Aunque debe haber un parámetro único para cada conjunto de parámetros, los
parámetros pueden pertenecer a más de un conjunto de parámetros. En estos casos, dé
al parámetro compartido una declaración de atributo
System.Management.Automation.Parameterattribute para cada conjunto al que
pertenece el parámetro. Si un parámetro está en todos los conjuntos de parámetros,
solo tiene que declarar el atributo de parámetro una vez y no es necesario especificar el
nombre del conjunto de parámetros.

Invalidar un método de procesamiento de


entrada
Cada cmdlet debe invalidar un método de procesamiento de entrada, que suele ser el
método System.Management.Automation.Cmdlet.ProcessRecord. En este cmdlet, el
método System.Management.Automation.Cmdlet.ProcessRecord se invalida para que el
cmdlet pueda procesar cualquier número de procesos. Contiene una instrucción Select
que llama a un método diferente en función del conjunto de parámetros que haya
especificado el usuario.

C#
protected override void ProcessRecord()
{
switch (ParameterSetName)
{
case "ProcessName":
ProcessByName();
break;

case "ProcessId":
ProcessById();
break;

case "InputObject":
foreach (Process process in inputObject)
{
SafeStopProcess(process);
}
break;

default:
throw new ArgumentException("Bad ParameterSet Name");
} // switch (ParameterSetName...
} // ProcessRecord

VB

Protected Overrides Sub ProcessRecord()


Select Case ParameterSetName
Case "ProcessName"
ProcessByName()

Case "ProcessId"
ProcessById()

Case "InputObject"
Dim process As Process
For Each process In myInputObject
SafeStopProcess(process)
Next process

Case Else
Throw New ArgumentException("Bad ParameterSet Name")
End Select

End Sub 'ProcessRecord ' ProcessRecord

Los métodos auxiliares a los que llama la instrucción Select no se describen aquí, pero
puede ver su implementación en el ejemplo de código completo en la sección siguiente.
Ejemplo de código
Para obtener el código de ejemplo de C# completo, vea StopProcessSample04 Sample.

Definir tipos de objeto y formato


Windows PowerShell pasa información entre cmdlets mediante objetos .NET. Por lo
tanto, es posible que un cmdlet tenga que definir su propio tipo o que el cmdlet tenga
que extender un tipo existente proporcionado por otro cmdlet. Para obtener más
información sobre cómo definir nuevos tipos o extender los tipos existentes, vea
Extender tipos de objeto y aplicar formato a.

Compilar el cmdlet
Después de implementar un cmdlet, debe registrarlo con Windows PowerShell a través
de un Windows PowerShell complemento. Para obtener más información sobre el
registro de cmdlets, vea How to Register Cmdlets, Providers, and Host Applications .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con Windows PowerShell, ejec cándalo en la línea
de comandos. Estas son algunas pruebas que muestran cómo se pueden usar los
parámetros y para ProcessId probar sus conjuntos de parámetros para detener un
InputObject proceso.

Una Windows PowerShell, ejecute el cmdlet Stop-Proc con el parámetro


establecido para detener ProcessId un proceso basado en su identificador. En este
caso, el cmdlet usa el ProcessId parámetro establecido para detener el proceso.

PS> stop-proc -Id 444


Confirm
Are you sure you want to perform this action?
Performing operation "stop-proc" on Target "notepad (444)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): Y

Con Windows PowerShell, ejecute el cmdlet Stop-Proc con el parámetro


establecido para detener los procesos en el objeto Bloc de notas recuperado
InputObject por el Get-Process comando .
PS> get-process notepad | stop-proc
Confirm
Are you sure you want to perform this action?
Performing operation "stop-proc" on Target "notepad (444)".
[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help
(default is "Y"): N

Consulte también
Creación de un cmdlet que modifica el sistema

Cómo crear un cmdlet Windows PowerShell aplicación

Extensión de tipos de objeto y formato

Cómo registrar cmdlets, proveedores y aplicaciones host

Windows PowerShell SDK


Tutorial de SelectStr
Artículo • 27/09/2021

En esta sección se proporciona un tutorial para crear el cmdlet Select-Str, que es muy
similar al cmdlet Select-String proporcionado por Windows PowerShell. En este tutorial
se proporcionan fragmentos de código que ilustran cómo se implementan los cmdlets y
una explicación del código.

Tema de este tutorial


Creación de un cmdlet para acceder a un almacén de datos En esta sección se describe
cómo crear un cmdlet que seleccione cadenas que se encuentran en un archivo u
objeto.

Consulte también
Creación de un cmdlet para obtener acceso a un almacén de datos

Windows PowerShell SDK


Creación de un cmdlet para obtener
acceso a un almacén de datos
Artículo • 27/09/2021

En esta sección se describe cómo crear un cmdlet que tiene acceso a los datos
almacenados mediante un proveedor Windows PowerShell datos. Este tipo de cmdlet
usa la infraestructura del proveedor de Windows PowerShell del entorno de ejecución
de Windows PowerShell y, por lo tanto, la clase de cmdlet debe derivar de la clase base
System.Management.Automation.PSCmdlet.

El cmdlet Select-Str que se describe aquí puede buscar y seleccionar cadenas en un


archivo u objeto. Los patrones usados para identificar la cadena se pueden especificar
explícitamente a través del parámetro del Path cmdlet o implícitamente a través del
Script parámetro .

El cmdlet está diseñado para usar cualquier Windows PowerShell que se derive de
System.Management.Automation.Provider.Icontentcmdletprovider. Por ejemplo, el
cmdlet puede especificar el proveedor FileSystem o el proveedor de variables
proporcionado por Windows PowerShell. Para obtener más información sobre los
proveedores de PowerShell de Windows, vea Designing Your Windows PowerShell
provider.

Definición de la clase cmdlet


El primer paso en la creación de cmdlets es asignar siempre un nombre al cmdlet y
declarar la clase .NET que implementa el cmdlet. Este cmdlet detecta ciertas cadenas,
por lo que el nombre del verbo elegido aquí es "Select", definido por la clase
System.Management.Automation.Verbscommon. El nombre "Str" se usa porque el
cmdlet actúa sobre cadenas. En la declaración siguiente, tenga en cuenta que el verbo
del cmdlet y el nombre del sustantivo se reflejan en el nombre de la clase de cmdlet.
Para obtener más información sobre los verbos de cmdlet aprobados, vea Nombres de
verbos de cmdlet.

La clase .NET para este cmdlet debe derivar de la clase base


System.Management.Automation.PSCmdlet, ya que proporciona la compatibilidad
necesaria para que el entorno de ejecución de Windows PowerShell exponga la
infraestructura del proveedor Windows PowerShell. Tenga en cuenta que este cmdlet
también usa las .NET Framework de expresiones regulares, como
System.Text.Regularexpressions.Regex.
El código siguiente es la definición de clase para este cmdlet Select-Str.

C#

[Cmdlet(VerbsCommon.Select, "Str",
DefaultParameterSetName="PatternParameterSet")]
public class SelectStringCommand : PSCmdlet

Este cmdlet define un conjunto de parámetros predeterminado agregando la palabra


DefaultParameterSetName clave attribute a la declaración de clase. El conjunto de

parámetros PatternParameterSet predeterminado se usa cuando no se especifica el


parámetro Script . Para obtener más información sobre este conjunto de parámetros,
vea la explicación Pattern de los parámetros y en la sección Script siguiente.

Definición de parámetros para el acceso a


datos
Este cmdlet define varios parámetros que permiten al usuario acceder a los datos
almacenados y examinar los datos almacenados. Estos parámetros incluyen un
parámetro que indica la ubicación del almacén de datos, un parámetro que especifica el
patrón que se va a usar en la búsqueda y otros parámetros que admiten cómo se realiza
la Path Pattern búsqueda.

7 Nota

Para obtener más información sobre los conceptos básicos de la definición de


parámetros, vea Adding Parameters that Process Command Line Input.

Declarar el parámetro path


Para buscar el almacén de datos, este cmdlet debe usar una ruta de acceso Windows
PowerShell para identificar el proveedor de Windows PowerShell que está diseñado para
acceder al almacén de datos. Por lo tanto, define un Path parámetro de tipo matriz de
cadenas para indicar la ubicación del proveedor.

C#

[Parameter(
Position = 0,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
[Parameter(
Position = 0,
ParameterSetName = "PatternParameterSet",
ValueFromPipeline = true,
Mandatory = true)]
[Alias("PSPath")]
public string[] Path
{
get { return paths; }
set { paths = value; }
}
private string[] paths;

Tenga en cuenta que este parámetro pertenece a dos conjuntos de parámetros


diferentes y que tiene un alias.

Dos atributos System.Management.Automation.Parameterattribute declaran que Path el


parámetro pertenece a y ScriptParameterSet PatternParameterSet . Para obtener más
información sobre los conjuntos de parámetros, vea Adding Parameter Sets to a Cmdlet.

El atributo System.Management.Automation.Aliasattribute declara un PSPath alias para


el parámetro Path . Se recomienda encarecidamente declarar este alias para mantener
la coherencia con otros cmdlets que acceden a Windows PowerShell proveedores. Para
obtener más información sobre las rutas de acceso de PowerShell de Windows, vea
"Conceptos de la ruta de acceso de PowerShell" en How Windows PowerShell Works .

Declarar el parámetro pattern


Para especificar los patrones que se deben buscar, este cmdlet declara un Pattern
parámetro que es una matriz de cadenas. Se devuelve un resultado positivo cuando se
encuentra cualquiera de los patrones en el almacén de datos. Tenga en cuenta que estos
patrones se pueden compilar en una matriz de expresiones regulares compiladas o en
una matriz de patrones de caracteres comodín que se usan para las búsquedas de
literales.

C#

[Parameter(
Position = 1,
ParameterSetName = "PatternParameterSet",
Mandatory = true)]
public string[] Pattern
{
get { return patterns; }
set { patterns = value; }
}
private string[] patterns;
private Regex[] regexPattern;
private WildcardPattern[] wildcardPattern;

Cuando se especifica este parámetro, el cmdlet usa el conjunto de parámetros


predeterminado PatternParameterSet . En este caso, el cmdlet usa los patrones
especificados aquí para seleccionar cadenas. En cambio, Script el parámetro también
se podría usar para proporcionar un script que contenga los patrones. Los Script
parámetros y definen dos conjuntos de parámetros Pattern independientes, por lo que
son mutuamente excluyentes.

Declarar parámetros de compatibilidad de búsqueda


Este cmdlet define los siguientes parámetros de compatibilidad que se pueden usar
para modificar las funcionalidades de búsqueda del cmdlet.

El Script parámetro especifica un bloque de script que se puede usar para


proporcionar un mecanismo de búsqueda alternativo para el cmdlet. El script debe
contener los patrones usados para buscar coincidencias y devolver un objeto
System.Management.Automation.PSObject. Tenga en cuenta que este parámetro
también es el único que identifica el ScriptParameterSet conjunto de parámetros.
Cuando el Windows PowerShell de ejecución ve este parámetro, solo usa parámetros
que pertenecen al conjunto ScriptParameterSet de parámetros.

C#

[Parameter(
Position = 1,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
public ScriptBlock Script
{
set { script = value; }
get { return script; }
}
ScriptBlock script;

El parámetro es un parámetro switch que indica si el cmdlet debe coincidir


explícitamente con los patrones a SimpleMatch medida que se proporcionan. Cuando el
usuario especifica el parámetro en la línea de comandos ( ), el cmdlet usa los true
patrones a medida que se proporcionan. Si no se especifica el parámetro ( false ), el
cmdlet usa expresiones regulares. El valor predeterminado de este parámetro es false .

C#
[Parameter]
public SwitchParameter SimpleMatch
{
get { return simpleMatch; }
set { simpleMatch = value; }
}
private bool simpleMatch;

El parámetro es un parámetro switch que indica si se realiza una búsqueda que


distingue CaseSensitive mayúsculas de minúsculas. Cuando el usuario especifica el
parámetro en la línea de comandos ( ), el cmdlet comprueba si hay caracteres en
mayúsculas y minúsculas al true comparar patrones. Si no se especifica el parámetro (
false ), el cmdlet no distingue entre mayúsculas y minúsculas. Por ejemplo, "MyFile" y
"myfile" se devolverían como aciertos positivos. El valor predeterminado de este
parámetro es false .

C#

[Parameter]
public SwitchParameter CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
private bool caseSensitive;

Los Exclude parámetros y identifican los elementos que se Include excluyen


explícitamente o se incluyen en la búsqueda. De forma predeterminada, el cmdlet
buscará en todos los elementos del almacén de datos. Sin embargo, para limitar la
búsqueda realizada por el cmdlet , estos parámetros se pueden usar para indicar
explícitamente los elementos que se incluirán en la búsqueda o se omitirán.

C#

[Parameter]
public SwitchParameter CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
private bool caseSensitive;

C#

[Parameter]
[ValidateNotNullOrEmpty]
public string[] Include
{
get
{
return includeStrings;
}
set
{
includeStrings = value;

this.include = new WildcardPattern[includeStrings.Length];


for (int i = 0; i < includeStrings.Length; i++)
{
this.include[i] = new WildcardPattern(includeStrings[i],
WildcardOptions.IgnoreCase);
}
}
}

internal string[] includeStrings = null;


internal WildcardPattern[] include = null;

Declarar conjuntos de parámetros


Este cmdlet usa dos conjuntos de parámetros ( y , que es el valor predeterminado) como
nombres de dos conjuntos de parámetros ScriptParameterSet PatternParameterSet
usados en el acceso a datos. PatternParameterSet es el conjunto de parámetros
predeterminado y se usa cuando Pattern se especifica el parámetro .
ScriptParameterSet se usa cuando el usuario especifica un mecanismo de búsqueda

alternativo a través del Script parámetro . Para obtener más información sobre los
conjuntos de parámetros, vea Adding Parameter Sets to a Cmdlet.

Invalidar métodos de procesamiento de


entrada
Los cmdlets deben invalidar uno o varios de los métodos de procesamiento de entrada
para la clase System.Management.Automation.PSCmdlet. Para obtener más información
sobre los métodos de procesamiento de entrada, vea Creating Your First Cmdlet.

Este cmdlet invalida el método


System.Management.Automation.Cmdlet.BeginProcessing para compilar una matriz de
expresiones regulares compiladas en el inicio. Esto aumenta el rendimiento durante las
búsquedas que no usan coincidencias simples.

C#
protected override void BeginProcessing()
{
WriteDebug("Validating patterns.");
if (patterns != null)
{
foreach(string pattern in patterns)
{
if (pattern == null)
ThrowTerminatingError(new ErrorRecord(
new ArgumentNullException(
"Search pattern cannot be null."),
"NullSearchPattern",
ErrorCategory.InvalidArgument,
pattern)
);
}

WriteVerbose("Search pattern(s) are valid.");

// If a simple match is not specified, then


// compile the regular expressions once.
if (!simpleMatch)
{
WriteDebug("Compiling search regular expressions.");

RegexOptions regexOptions = RegexOptions.Compiled;


if (!caseSensitive)
regexOptions |= RegexOptions.Compiled;
regexPattern = new Regex[patterns.Length];

for (int i = 0; i < patterns.Length; i++)


{
try
{
regexPattern[i] = new Regex(patterns[i], regexOptions);
}
catch (ArgumentException ex)
{
ThrowTerminatingError(new ErrorRecord(
ex,
"InvalidRegularExpression",
ErrorCategory.InvalidArgument,
patterns[i]
));
}
} //Loop through patterns to create RegEx objects.

WriteVerbose("Pattern(s) compiled into regular expressions.");


}// If not a simple match.

// If a simple match is specified, then compile the


// wildcard patterns once.
else
{
WriteDebug("Compiling search wildcards.");

WildcardOptions wildcardOptions = WildcardOptions.Compiled;

if (!caseSensitive)
{
wildcardOptions |= WildcardOptions.IgnoreCase;
}

wildcardPattern = new WildcardPattern[patterns.Length];


for (int i = 0; i < patterns.Length; i++)
{
wildcardPattern[i] =
new WildcardPattern(patterns[i], wildcardOptions);
}

WriteVerbose("Pattern(s) compiled into wildcard expressions.");


}// If match is a simple match.
}// If valid patterns are available.
}// End of function BeginProcessing().

Este cmdlet también invalida el método


System.Management.Automation.Cmdlet.ProcessRecord para procesar las selecciones
de cadena que el usuario realiza en la línea de comandos. Escribe los resultados de la
selección de cadenas en forma de objeto personalizado llamando a un método
MatchString privado.

C#

protected override void ProcessRecord()


{
UInt64 lineNumber = 0;
MatchInfo result;
ArrayList nonMatches = new ArrayList();

// Walk the list of paths and search the contents for


// any of the specified patterns.
foreach (string psPath in paths)
{
// Once the filepaths are expanded, we may have more than one
// path, so process all referenced paths.
foreach(PathInfo path in
SessionState.Path.GetResolvedPSPathFromPSPath(psPath)
)
{
WriteVerbose("Processing path " + path.Path);

// Check if the path represents one of the items to be


// excluded. If so, continue to next path.
if (!MeetsIncludeExcludeCriteria(path.ProviderPath))
continue;
// Get the content reader for the item(s) at the
// specified path.
Collection<IContentReader> readerCollection = null;
try
{
readerCollection =
this.InvokeProvider.Content.GetReader(path.Path);
}
catch (PSNotSupportedException ex)
{
WriteError(new ErrorRecord(ex,
"ContentAccessNotSupported",
ErrorCategory.NotImplemented,
path.Path)
);
return;
}

foreach(IContentReader reader in readerCollection)


{
// Reset the line number for this path.
lineNumber = 0;

// Read in a single block (line in case of a file)


// from the object.
IList items = reader.Read(1);

// Read and process one block(line) at a time until


// no more blocks(lines) exist.
while (items != null && items.Count == 1)
{
// Increment the line number each time a line is
// processed.
lineNumber++;

String message = String.Format("Testing line {0} : {1}",


lineNumber, items[0]);

WriteDebug(message);

result = SelectString(items[0]);

if (result != null)
{
result.Path = path.Path;
result.LineNumber = lineNumber;

WriteObject(result);
}
else
{
// Add the block(line) that did not match to the
// collection of non matches , which will be stored
// in the SessionState variable $NonMatches
nonMatches.Add(items[0]);
}

// Get the next line from the object.


items = reader.Read(1);

}// While loop for reading one line at a time.


}// Foreach loop for reader collection.
}// Foreach loop for processing referenced paths.
}// Foreach loop for walking of path list.

// Store the list of non-matches in the


// session state variable $NonMatches.
try
{
this.SessionState.PSVariable.Set("NonMatches", nonMatches);
}
catch (SessionStateUnauthorizedAccessException ex)
{
WriteError(new ErrorRecord(ex,
"CannotWriteVariableNonMatches",
ErrorCategory.InvalidOperation,
nonMatches)
);
}

}// End of protected override void ProcessRecord().

Acceso al contenido
El cmdlet debe abrir el proveedor indicado por la ruta de acceso Windows PowerShell
para que pueda acceder a los datos. El objeto
System.Management.Automation.Sessionstate del espacio de ejecución se usa para el
acceso al proveedor, mientras que la propiedad
System.Management.Automation.PSCmdlet.Invokeprovider* del cmdlet se usa para abrir
el proveedor. El acceso al contenido se proporciona mediante la recuperación del objeto
System.Management.Automation.Providerintrinsics para el proveedor abierto.

Este cmdlet Select-Str ejemplo usa la propiedad


System.Management.Automation.Providerintrinsics.Content* para exponer el contenido
que se va a examinar. A continuación, puede llamar al método
System.Management.Automation.Contentcmdletproviderintrinsics.Getreader*, pasando
la ruta de acceso Windows PowerShell necesaria.

Ejemplo de código
En el código siguiente se muestra la implementación de esta versión de Select-Str
cmdlet. Tenga en cuenta que este código incluye la clase de cmdlet, los métodos
privados usados por el cmdlet y el Windows PowerShell complemento que se usa para
registrar el cmdlet. Para obtener más información sobre cómo registrar el cmdlet, vea
Building the Cmdlet.

C#

//
// Copyright (c) 2006 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Text.RegularExpressions;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;

namespace Microsoft.Samples.PowerShell.Commands
{
#region SelectStringCommand
/// <summary>
/// This cmdlet searches through PSObjects for particular patterns.
/// </summary>
/// <remarks>
/// This cmdlet can be used to search any object, such as a file or a
/// variable, whose provider exposes methods for reading and writing
/// content.
/// </remarks>
[Cmdlet(VerbsCommon.Select, "Str",
DefaultParameterSetName="PatternParameterSet")]
public class SelectStringCommand : PSCmdlet
{
#region Parameters
/// <summary>
/// Declare a Path parameter that specifies where the data is stored.
/// This parameter must specify a PowerShell that indicates the
/// PowerShell provider that is used to access the objects to be
/// searched for matching patterns. This parameter should also have
/// a PSPath alias to provide consistency with other cmdlets that use
/// PowerShell providers.
/// </summary>
/// <value>Path of the object(s) to search.</value>
[Parameter(
Position = 0,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
[Parameter(
Position = 0,
ParameterSetName = "PatternParameterSet",
ValueFromPipeline = true,
Mandatory = true)]
[Alias("PSPath")]
public string[] Path
{
get { return paths; }
set { paths = value; }
}
private string[] paths;

/// <summary>
/// Declare a Pattern parameter that specifies the pattern(s)
/// used to find matching patterns in the string representation
/// of the objects. A positive result will be returned
/// if any of the patterns are found in the objects.
/// </summary>
/// <remarks>
/// The patterns will be compiled into an array of wildcard
/// patterns for a simple match (literal string matching),
/// or the patterns will be converted into an array of compiled
/// regular expressions.
/// </remarks>
/// <value>Array of patterns to search.</value>
[Parameter(
Position = 1,
ParameterSetName = "PatternParameterSet",
Mandatory = true)]
public string[] Pattern
{
get { return patterns; }
set { patterns = value; }
}
private string[] patterns;
private Regex[] regexPattern;
private WildcardPattern[] wildcardPattern;

/// <summary>
/// Declare a Script parameter that specifies a script block
/// that is called to perform the matching operations
/// instead of the matching performed by the cmdlet.
/// </summary>
/// <value>Script block that will be called for matching</value>
[Parameter(
Position = 1,
ParameterSetName = "ScriptParameterSet",
Mandatory = true)]
public ScriptBlock Script
{
set { script = value; }
get { return script; }
}
ScriptBlock script;
/// <summary>
/// Declare a switch parameter that specifies if the pattern(s) are used
/// literally. If not (default), searching is
/// done using regular expressions.
/// </summary>
/// <value>If True, a literal pattern is used.</value>
[Parameter]
public SwitchParameter SimpleMatch
{
get { return simpleMatch; }
set { simpleMatch = value; }
}
private bool simpleMatch;

/// <summary>
/// Declare a switch parameter that specifies if a case-sensitive
/// search is performed. If not (default), a case-insensitive search
/// is performed.
/// </summary>
/// <value>If True, a case-sensitive search is made.</value>
[Parameter]
public SwitchParameter CaseSensitive
{
get { return caseSensitive; }
set { caseSensitive = value; }
}
private bool caseSensitive;

/// <summary>
/// Declare an Include parameter that species which
/// specific items are searched. When this parameter
/// is used, items that are not listed here are omitted
/// from the search.
/// </summary>
[Parameter]
[ValidateNotNullOrEmpty]
public string[] Include
{
get
{
return includeStrings;
}
set
{
includeStrings = value;

this.include = new WildcardPattern[includeStrings.Length];


for (int i = 0; i < includeStrings.Length; i++)
{
this.include[i] = new WildcardPattern(includeStrings[i],
WildcardOptions.IgnoreCase);
}
}
}
internal string[] includeStrings = null;
internal WildcardPattern[] include = null;

/// <summary>
/// Declare an Exclude parameter that species which
/// specific items are omitted from the search.
/// </summary>
///
[Parameter]
[ValidateNotNullOrEmpty]
public string[] Exclude
{
get
{
return excludeStrings;
}
set
{
excludeStrings = value;

this.exclude = new WildcardPattern[excludeStrings.Length];


for (int i = 0; i < excludeStrings.Length; i++)
{
this.exclude[i] = new WildcardPattern(excludeStrings[i],
WildcardOptions.IgnoreCase);
}
}
}
internal string[] excludeStrings;
internal WildcardPattern[] exclude;

#endregion Parameters

#region Overrides
/// <summary>
/// If regular expressions are used for pattern matching,
/// then build an array of compiled regular expressions
/// at startup. This increases performance during scanning
/// operations when simple matching is not used.
/// </summary>
protected override void BeginProcessing()
{
WriteDebug("Validating patterns.");
if (patterns != null)
{
foreach(string pattern in patterns)
{
if (pattern == null)
ThrowTerminatingError(new ErrorRecord(
new ArgumentNullException(
"Search pattern cannot be null."),
"NullSearchPattern",
ErrorCategory.InvalidArgument,
pattern)
);
}

WriteVerbose("Search pattern(s) are valid.");

// If a simple match is not specified, then


// compile the regular expressions once.
if (!simpleMatch)
{
WriteDebug("Compiling search regular expressions.");

RegexOptions regexOptions = RegexOptions.Compiled;


if (!caseSensitive)
regexOptions |= RegexOptions.Compiled;
regexPattern = new Regex[patterns.Length];

for (int i = 0; i < patterns.Length; i++)


{
try
{
regexPattern[i] = new Regex(patterns[i], regexOptions);
}
catch (ArgumentException ex)
{
ThrowTerminatingError(new ErrorRecord(
ex,
"InvalidRegularExpression",
ErrorCategory.InvalidArgument,
patterns[i]
));
}
} //Loop through patterns to create RegEx objects.

WriteVerbose("Pattern(s) compiled into regular expressions.");


}// If not a simple match.

// If a simple match is specified, then compile the


// wildcard patterns once.
else
{
WriteDebug("Compiling search wildcards.");

WildcardOptions wildcardOptions = WildcardOptions.Compiled;

if (!caseSensitive)
{
wildcardOptions |= WildcardOptions.IgnoreCase;
}

wildcardPattern = new WildcardPattern[patterns.Length];


for (int i = 0; i < patterns.Length; i++)
{
wildcardPattern[i] =
new WildcardPattern(patterns[i], wildcardOptions);
}
WriteVerbose("Pattern(s) compiled into wildcard expressions.");
}// If match is a simple match.
}// If valid patterns are available.
}// End of function BeginProcessing().

/// <summary>
/// Process the input and search for the specified patterns.
/// </summary>
protected override void ProcessRecord()
{
UInt64 lineNumber = 0;
MatchInfo result;
ArrayList nonMatches = new ArrayList();

// Walk the list of paths and search the contents for


// any of the specified patterns.
foreach (string psPath in paths)
{
// Once the filepaths are expanded, we may have more than one
// path, so process all referenced paths.
foreach(PathInfo path in
SessionState.Path.GetResolvedPSPathFromPSPath(psPath)
)
{
WriteVerbose("Processing path " + path.Path);

// Check if the path represents one of the items to be


// excluded. If so, continue to next path.
if (!MeetsIncludeExcludeCriteria(path.ProviderPath))
continue;

// Get the content reader for the item(s) at the


// specified path.
Collection<IContentReader> readerCollection = null;
try
{
readerCollection =
this.InvokeProvider.Content.GetReader(path.Path);
}
catch (PSNotSupportedException ex)
{
WriteError(new ErrorRecord(ex,
"ContentAccessNotSupported",
ErrorCategory.NotImplemented,
path.Path)
);
return;
}

foreach(IContentReader reader in readerCollection)


{
// Reset the line number for this path.
lineNumber = 0;
// Read in a single block (line in case of a file)
// from the object.
IList items = reader.Read(1);

// Read and process one block(line) at a time until


// no more blocks(lines) exist.
while (items != null && items.Count == 1)
{
// Increment the line number each time a line is
// processed.
lineNumber++;

String message = String.Format("Testing line {0} : {1}",


lineNumber, items[0]);

WriteDebug(message);

result = SelectString(items[0]);

if (result != null)
{
result.Path = path.Path;
result.LineNumber = lineNumber;

WriteObject(result);
}
else
{
// Add the block(line) that did not match to the
// collection of non matches , which will be stored
// in the SessionState variable $NonMatches
nonMatches.Add(items[0]);
}

// Get the next line from the object.


items = reader.Read(1);

}// While loop for reading one line at a time.


}// Foreach loop for reader collection.
}// Foreach loop for processing referenced paths.
}// Foreach loop for walking of path list.

// Store the list of non-matches in the


// session state variable $NonMatches.
try
{
this.SessionState.PSVariable.Set("NonMatches", nonMatches);
}
catch (SessionStateUnauthorizedAccessException ex)
{
WriteError(new ErrorRecord(ex,
"CannotWriteVariableNonMatches",
ErrorCategory.InvalidOperation,
nonMatches)
);
}

}// End of protected override void ProcessRecord().


#endregion Overrides

#region PrivateMethods
/// <summary>
/// Check for a match using the input string and the pattern(s)
/// specified.
/// </summary>
/// <param name="input">The string to test.</param>
/// <returns>MatchInfo object containing information about
/// result of a match</returns>
private MatchInfo SelectString(object input)
{
string line = null;

try
{
// Convert the object to a string type
// safely using language support methods
line = (string)LanguagePrimitives.ConvertTo(
input,
typeof(string)
);
line = line.Trim(' ','\t');
}
catch (PSInvalidCastException ex)
{
WriteError(new ErrorRecord(
ex,
"CannotCastObjectToString",
ErrorCategory.InvalidOperation,
input)
);

return null;
}

MatchInfo result = null;

// If a scriptblock has been specified, call it


// with the path for processing. It will return
// one object.
if (script != null)
{
WriteDebug("Executing script block.");

Collection<PSObject> psObjects =
script.Invoke(
line,
simpleMatch,
caseSensitive
);
foreach (PSObject psObject in psObjects)
{
if (LanguagePrimitives.IsTrue(psObject))
{
result = new MatchInfo();
result.Line = line;
result.IgnoreCase = !caseSensitive;

break;
} //End of If.
} //End ForEach loop.
} // End of If if script exists.

// If script block exists, see if this line matches any


// of the match patterns.
else
{
int patternIndex = 0;

while (patternIndex < patterns.Length)


{
if ((simpleMatch &&
wildcardPattern[patternIndex].IsMatch(line))
|| (regexPattern != null
&& regexPattern[patternIndex].IsMatch(line))
)
{
result = new MatchInfo();
result.IgnoreCase = !caseSensitive;
result.Line = line;
result.Pattern = patterns[patternIndex];

break;
}

patternIndex++;

}// While loop through patterns.


}// Else for no script block specified.

return result;

}// End of SelectString

/// <summary>
/// Check whether the supplied name meets the include/exclude criteria.
/// That is - it's on the include list if the include list was
/// specified, and not on the exclude list if the exclude list was
specified.
/// </summary>
/// <param name="path">path to validate</param>
/// <returns>True if the path is acceptable.</returns>
private bool MeetsIncludeExcludeCriteria(string path)
{
bool ok = false;
// See if the file is on the include list.
if (this.include != null)
{
foreach (WildcardPattern patternItem in this.include)
{
if (patternItem.IsMatch(path))
{
ok = true;
break;
}
}
}
else
{
ok = true;
}

if (!ok)
return false;

// See if the file is on the exclude list.


if (this.exclude != null)
{
foreach (WildcardPattern patternItem in this.exclude)
{
if (patternItem.IsMatch(path))
{
ok = false;
break;
}
}
}

return ok;
} //MeetsIncludeExcludeCriteria
#endregion Private Methods

}// class SelectStringCommand

#endregion SelectStringCommand

#region MatchInfo

/// <summary>
/// Class representing the result of a pattern/literal match
/// that is passed through the pipeline by the Select-Str cmdlet.
/// </summary>
public class MatchInfo
{
/// <summary>
/// Indicates if the match was done ignoring case.
/// </summary>
/// <value>True if case was ignored.</value>
public bool IgnoreCase
{
get { return ignoreCase; }
set { ignoreCase = value; }
}
private bool ignoreCase;

/// <summary>
/// Specifies the number of the matching line.
/// </summary>
/// <value>The number of the matching line.</value>
public UInt64 LineNumber
{
get { return lineNumber; }
set { lineNumber = value; }
}
private UInt64 lineNumber;

/// <summary>
/// Specifies the text of the matching line.
/// </summary>
/// <value>The text of the matching line.</value>
public string Line
{
get { return line; }
set { line = value; }
}
private string line;

/// <summary>
/// Specifies the full path of the object(file) containing the
/// matching line.
/// </summary>
/// <remarks>
/// It will be "inputStream" if the object came from the input
/// stream.
/// </remarks>
/// <value>The path name</value>
public string Path
{
get { return path; }
set
{
pathSet = true;
path = value;
}
}
private string path;
private bool pathSet;

/// <summary>
/// Specifies the pattern that was used in the match.
/// </summary>
/// <value>The pattern string</value>
public string Pattern
{
get { return pattern; }
set { pattern = value; }
}
private string pattern;

private const string MatchFormat = "{0}:{1}:{2}";

/// <summary>
/// Returns the string representation of this object. The format
/// depends on whether a path has been set for this object or
/// not.
/// </summary>
/// <remarks>
/// If the path component is set, as would be the case when
/// matching in a file, ToString() returns the path, line
/// number and line text. If path is not set, then just the
/// line text is presented.
/// </remarks>
/// <returns>The string representation of the match object.</returns>
public override string ToString()
{
if (pathSet)
return String.Format(
System.Threading.Thread.CurrentThread.CurrentCulture,
MatchFormat,
this.path,
this.lineNumber,
this.line
);
else
return this.line;
}
}// End class MatchInfo

#endregion

#region PowerShell snap-in

/// <summary>
/// Create a PowerShell snap-in for the Select-Str cmdlet.
/// </summary>
[RunInstaller(true)]
public class SelectStringPSSnapIn : PSSnapIn
{
/// <summary>
/// Create an instance of the SelectStrPSSnapin class.
/// </summary>
public SelectStringPSSnapIn()
: base()
{
}

/// <summary>
/// Specify the name of the PowerShell snap-in.
/// </summary>
public override string Name
{
get
{
return "SelectStrPSSnapIn";
}
}

/// <summary>
/// Specify the vendor of the PowerShell snap-in.
/// </summary>
public override string Vendor
{
get
{
return "Microsoft";
}
}

/// <summary>
/// Specify the localization resource information for the vendor.
/// Use the format: SnapinName,VendorName.
/// </summary>
public override string VendorResource
{
get
{
return "SelectStrSnapIn,Microsoft";
}
}

/// <summary>
/// Specify the description of the PowerShell snap-in.
/// </summary>
public override string Description
{
get
{
return "This is a PowerShell snap-in for the Select-Str cmdlet.";
}
}

/// <summary>
/// Specify the localization resource information for the description.
/// Use the format: SnapinName,Description.

/// </summary>
public override string DescriptionResource
{
get
{
return "SelectStrSnapIn,This is a PowerShell snap-in for the
Select-Str cmdlet.";
}
}
}
#endregion PowerShell snap-in

} //namespace Microsoft.Samples.PowerShell.Commands;

Compilar el cmdlet
Después de implementar un cmdlet, debe registrarlo con Windows PowerShell a través
de Windows PowerShell complemento. Para obtener más información sobre el registro
de cmdlets, vea How to Register Cmdlets, Providers, and Host Applications .

Prueba del cmdlet


Cuando el cmdlet se haya registrado con Windows PowerShell, puede probarlo
ejecutándose en la línea de comandos. El siguiente procedimiento se puede usar para
probar el cmdlet de Select-Str ejemplo.

1. Inicie Windows PowerShell y busque en el archivo Notes apariciones de líneas con


la expresión ".NET". Tenga en cuenta que las comillas alrededor del nombre de la
ruta de acceso solo son necesarias si la ruta de acceso consta de más de una
palabra.

PowerShell

select-str -Path "notes" -Pattern ".NET" -SimpleMatch=$false

Aparece el siguiente resultado.

Resultados

IgnoreCase : True
LineNumber : 8
Line : Because Windows PowerShell works directly with .NET
objects, there is often a .NET object
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : .NET
IgnoreCase : True
LineNumber : 21
Line : You should normally define the class for a cmdlet in a
.NET namespace
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : .NET
2. Busque en el archivo Notes las apariciones de líneas con la palabra "over",
seguidas de cualquier otro texto. El SimpleMatch parámetro usa el valor
predeterminado de false . La búsqueda no tiene en cuenta las mayúsculas y
minúsculas porque CaseSensitive el parámetro está establecido en false .

PowerShell

select-str -Path notes -Pattern "over*" -SimpleMatch -


CaseSensitive:$false

Aparece el siguiente resultado.

Resultados

IgnoreCase : True
LineNumber : 45
Line : Override StopProcessing
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : over*
IgnoreCase : True
LineNumber : 49
Line : overriding the StopProcessing method
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : over*

3. Busque en el archivo Notes con una expresión regular como patrón. El cmdlet
busca caracteres alfabéticos y espacios en blanco entre paréntesis.

PowerShell

select-str -Path notes -Pattern "\([A-Za-z:blank:]" -SimpleMatch:$false

Aparece el siguiente resultado.

Resultados

IgnoreCase : True
LineNumber : 1
Line : Advisory Guidelines (Consider Following)
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : \([A-Za-z:blank:]
IgnoreCase : True
LineNumber : 53
Line : If your cmdlet has objects that are not disposed of
(written to the pipeline)
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : \([A-Za-z:blank:]
4. Realice una búsqueda que distingue mayúsculas de minúsculas del archivo Notes
en busca de repeticiones de la palabra "Parameter".

PowerShell

select-str -Path notes -Pattern Parameter -CaseSensitive

Aparece el siguiente resultado.

Resultados

IgnoreCase : False
LineNumber : 6
Line : Support an InputObject Parameter
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : Parameter
IgnoreCase : False
LineNumber : 30
Line : Support Force Parameter
Path : C:\PowerShell-Progs\workspace\Samples\SelectStr\notes
Pattern : Parameter

5. Busque en el proveedor de variables incluido Windows PowerShell variables que


tengan valores numéricos de 0 a 9.

PowerShell

select-str -Path * -Pattern "[0-9]"

Aparece el siguiente resultado.

Resultados

IgnoreCase : True
LineNumber : 1
Line : 64
Path : Variable:\MaximumHistoryCount
Pattern : [0-9]

6. Use un bloque de script para buscar en el archivo SelectStrCommandSample.cs la


cadena "Pos". La función cmatch del script realiza una coincidencia de patrones
que no tiene en cuenta las mayúsculas y minúsculas.

PowerShell
select-str -Path "SelectStrCommandSample.cs" -Script { if ($args[0] -
cmatch "Pos"){ return $true } return $false }

Aparece el siguiente resultado.

Resultados

IgnoreCase : True
LineNumber : 37
Line : Position = 0.
Path : C:\PowerShell-
Progs\workspace\Samples\SelectStr\SelectStrCommandSample.cs
Pattern :

Consulte también
Cómo crear un cmdlet Windows PowerShell aplicación

Creación del primer cmdlet

Creación de un cmdlet que modifica el sistema

Diseñar el proveedor de Windows PowerShell personalizado

Funcionamiento de Windows PowerShell

Cómo registrar cmdlets, proveedores y aplicaciones host

Windows PowerShell SDK


Ejemplos de cmdlet
Artículo • 27/09/2021

En esta sección se describe el código de ejemplo que se proporciona en el SDK de


Windows PowerShell 2.0.

En esta sección
Ejemplo GetProcessSample01 Este ejemplo muestra cómo escribir un cmdlet que
recupere los procesos en el equipo local.

Ejemplo GetProcessSample02 Este ejemplo muestra cómo escribir un cmdlet que


recupere los procesos en el equipo local. Proporciona un parámetro Name que se
puede utilizar para especificar los procesos que se van a recuperar.

Ejemplo GetProcessSample03 Este ejemplo muestra cómo escribir un cmdlet que


recupere los procesos en el equipo local. Proporciona un parámetro Name que puede
aceptar un objeto de la canalización o un valor de una propiedad de un objeto cuyo
nombre de propiedad es el mismo que el nombre del parámetro.

Ejemplo GetProcessSample04 Este ejemplo muestra cómo escribir un cmdlet que


recupere los procesos en el equipo local. Genera un error de no terminación si se
produce un error al recuperar un proceso.

Ejemplo GetProcessSample05 Este ejemplo muestra una versión completa del cmdlet
Get-Proc.

Ejemplo StopProcessSample01 Este ejemplo muestra cómo escribir un cmdlet que


solicita información al usuario antes de intentar detener un proceso y cómo
implementar un parámetro PassThru que indica que el usuario desea que el cmdlet
devuelva un objeto.

Ejemplo StopProcessSample02 Este ejemplo muestra cómo escribir un cmdlet que


escriba mensajes de depuración, detallado y advertencia al detener procesos en el
equipo local.

Ejemplo StopProcessSample03 Este ejemplo muestra cómo escribir un cmdlet cuyos


parámetros tienen alias y que admiten caracteres comodín.

Ejemplo StopProcessSample04 Este ejemplo muestra cómo escribir un cmdlet que


declara conjuntos de parámetros, especifica el conjunto de parámetros predeterminado
y puede aceptar un objeto de entrada.
Ejemplo Events01 Este ejemplo muestra cómo crear un cmdlet que permite al usuario
registrarse para eventos generados por System.IO.Filesystemwatcher. Con este cmdlet,
los usuarios pueden, por ejemplo, registrar una acción para que se ejecute cuando se
cree un archivo en un directorio específico. Este ejemplo se deriva de la clase base
Microsoft.PowerShell.Commands.Objecteventregistrationbase.

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo GetProcessSample01
Artículo • 24/09/2021

En este ejemplo se muestra cómo implementar un cmdlet que recupera los procesos en
el equipo local. Este cmdlet es una versión simplificada del Get-Process cmdlet que
proporciona Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual


Studio.
1. Con el Windows PowerShell SDK de 2.0 instalado, vaya a la carpeta
GetProcessSample01. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\GetProcessSa
mple01.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Microsoft Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Abra una ventana de símbolo del sistema.

2. Vaya al directorio que contiene el archivo de .dll ejemplo.

3. Ejecute installutil "GetProcessSample01.dll".

4. Inicie Windows PowerShell.

5. Ejecute el siguiente comando para agregar el complemento al shell.

Add-PSSnapin GetProcPSSnapIn01

6. Escriba el siguiente comando para ejecutar el cmdlet . get-proc

get-proc
Esta es una salida de ejemplo que resulta de seguir estos pasos.

Resultados

Id Name State HasMoreData Location


Command
-- ---- ----- ----------- --------
-------
1 26932870-d3b... NotStarted False
Write-Host "A f...

PowerShell

Set-Content $env:temp\test.txt "This is a test file"

Resultados

A file was created in the TEMP directory

Requisitos
Este ejemplo requiere Windows PowerShell 1.0 o posterior.

Muestra
En este ejemplo se muestra lo siguiente.

Creación de un cmdlet de ejemplo básico.

Definición de una clase de cmdlet mediante el atributo Cmdlet.

Crear un complemento que funcione con Windows PowerShell 1.0 y Windows


PowerShell 2.0. Los ejemplos posteriores usan módulos en lugar de complementos,
por lo que Windows PowerShell 2.0.

Ejemplo
En este ejemplo se muestra cómo crear un cmdlet simple y su complemento.

C#
using System;
using System.Diagnostics;
using System.Management.Automation; //Windows PowerShell
namespace
using System.ComponentModel;

namespace Microsoft.Samples.PowerShell.Commands
{

#region GetProcCommand

/// <summary>
/// This class implements the Get-Proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes of the local computer.
/// Then, the WriteObject method writes the associated processes
/// to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// Retrieve the current processes.
Process[] processes = Process.GetProcesses();

// Write the processes to the pipeline to make them available


// to the next cmdlet. The second argument (true) tells Windows
// PowerShell to enumerate the array and to send one process
// object at a time to the pipeline.
WriteObject(processes, true);
}

#endregion Overrides

} //GetProcCommand

#endregion GetProcCommand

#region PowerShell snap-in

/// <summary>
/// Create this sample as an PowerShell snap-in
/// </summary>
[RunInstaller(true)]
public class GetProcPSSnapIn01 : PSSnapIn
{
/// <summary>
/// Create an instance of the GetProcPSSnapIn01
/// </summary>
public GetProcPSSnapIn01()
: base()
{
}

/// <summary>
/// Get a name for this PowerShell snap-in. This name will be used in
registering
/// this PowerShell snap-in.
/// </summary>
public override string Name
{
get
{
return "GetProcPSSnapIn01";
}
}

/// <summary>
/// Vendor information for this PowerShell snap-in.
/// </summary>
public override string Vendor
{
get
{
return "Microsoft";
}
}

/// <summary>
/// Gets resource information for vendor. This is a string of format:
/// resourceBaseName,resourceName.
/// </summary>
public override string VendorResource
{
get
{
return "GetProcPSSnapIn01,Microsoft";
}
}

/// <summary>
/// Description of this PowerShell snap-in.
/// </summary>
public override string Description
{
get
{
return "This is a PowerShell snap-in that includes the get-
proc cmdlet.";
}
}
}
#endregion PowerShell snap-in
}

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo GetProcessSample02
Artículo • 27/09/2021

En este ejemplo se muestra cómo escribir un cmdlet que recupera los procesos en el
equipo local. Proporciona un parámetro Name que se puede usar para especificar los
procesos que se recuperarán. Este cmdlet es una versión simplificada del Get-Process
cmdlet proporcionada por Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual


Studio.
1. Con el Windows PowerShell SDK de 2.0 instalado, vaya a la carpeta
GetProcessSample02. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\GetProcessSa
mple02.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Cree la siguiente carpeta de módulos:

[user]/documents/windowspowershell/modules/GetProcessSample02

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

import-module getprossessample02

5. Ejecute el siguiente comando para ejecutar el cmdlet :

get-proc
Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar un parámetro de cmdlet mediante el atributo Parameter.

Especificación de la posición del parámetro.

Declarar un atributo de validación para la entrada del parámetro.

Ejemplo
En este ejemplo se muestra una implementación del cmdlet Get-Proc que incluye un
Name parámetro .

C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell namespace

#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// The names of the processes retrieved by the cmdlet.
/// </summary>
private string[] processNames;

/// <summary>
/// Gets or sets the list of process names on which
/// the Get-Proc cmdlet will work.
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes specified by the Name
/// parameter. Then, the WriteObject method writes the
/// associated process objects to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// If no process names are passed to the cmdlet, get all
// processes.
if (this.processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to cmdlet, get and write
// the associated processes.
foreach (string name in this.processNames)
{
WriteObject(Process.GetProcessesByName(name), true);
}
} // End if (processNames...).
} // End ProcessRecord.
#endregion Cmdlet Overrides
} // End GetProcCommand class.
#endregion GetProcCommand
}

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo GetProcessSample03
Artículo • 24/09/2021

En este ejemplo se muestra cómo implementar un cmdlet que recupera los procesos en
el equipo local. Proporciona un parámetro que puede aceptar un objeto de la
canalización o un valor de una propiedad de un objeto cuyo nombre de propiedad es el
mismo que el Name nombre del parámetro. Este cmdlet es una versión simplificada del
Get-Process cmdlet proporcionada por Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual


Studio.
1. Con el Windows PowerShell SDK de 2.0 instalado, vaya a la carpeta
GetProcessSample03. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\GetProcessSa
mple03.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Cree la siguiente carpeta de módulos:

[user]/documents/windowspowershell/modules/GetProcessSample03

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

Import-module getprossessample03

5. Ejecute el siguiente comando para ejecutar el cmdlet :


get-proc

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar un parámetro de cmdlet mediante el atributo Parameter.

Especificación de la posición del parámetro.

Especificación de que el parámetro toma la entrada de la canalización. La entrada


se puede tomar de un objeto o un valor de una propiedad de un objeto cuyo
nombre de propiedad es el mismo que el nombre del parámetro.

Declarar un atributo de validación para la entrada del parámetro.

Ejemplo
En este ejemplo se muestra una implementación del cmdlet Get-Proc que incluye un
Name parámetro que acepta la entrada de la canalización.

C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell
namespace
#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// The names of the processes retrieved by the cmdlet.
/// </summary>
private string[] processNames;

/// <summary>
/// Gets or sets the names of the
/// process that the cmdlet will retrieve.
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes specified by the Name
/// parameter. Then, the WriteObject method writes the
/// associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// If no process names are passed to the cmdlet, get all
// processes.
if (this.processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to the cmdlet, get and write
// the associated processes.
foreach (string name in this.processNames)
{
WriteObject(Process.GetProcessesByName(name), true);
}
} // End if (processNames ...)
} // End ProcessRecord.

#endregion Overrides
} // End GetProcCommand.
#endregion GetProcCommand
}
Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo GetProcessSample04
Artículo • 27/09/2021

En este ejemplo se muestra cómo implementar un cmdlet que recupera los procesos en
el equipo local. Genera un error de no terminación si se produce un error al recuperar
un proceso. Este cmdlet es una versión simplificada del Get-Process cmdlet
proporcionado por Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual


Studio.
1. Con el Windows PowerShell SDK de 2.0 instalado, vaya a la carpeta
GetProcessSample04. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\GetProcessSa
mple04.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Cree la carpeta del módulo siguiente:

[user]/documents/windowspowershell/modules/GetProcessSample04

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

Import-module getprossessample04

5. Ejecute el siguiente comando para ejecutar el cmdlet :

get-proc
Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar un parámetro de cmdlet mediante el atributo Parameter.

Especificación de la posición del parámetro.

Especificación de que el parámetro toma la entrada de la canalización. La entrada


se puede tomar de un objeto o un valor de una propiedad de un objeto cuyo
nombre de propiedad es el mismo que el nombre del parámetro.

Declarar un atributo de validación para la entrada del parámetro.

Captura de un error no terminal y escritura de un mensaje de error en la secuencia


de errores.

Ejemplo
En este ejemplo se muestra cómo crear un cmdlet que controle los errores no
terminales y escriba mensajes de error en la secuencia de errores.

C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell
namespace.
#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// The names of the processes to act on.
/// </summary>
private string[] processNames;

/// <summary>
/// Gets or sets the list of process names on
/// which the Get-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes specified by the Name
/// parameter. Then, the WriteObject method writes the
/// associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// If no process names are passed to cmdlet, get all
// processes.
if (this.processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to the cmdlet, get and write
// the associated processes.
// If a nonterminating error occurs while retrieving
processes,
// call the WriteError method to send an error record to the
// error stream.
foreach (string name in this.processNames)
{
Process[] processes;

try
{
processes = Process.GetProcessesByName(name);
}
catch (InvalidOperationException ex)
{
WriteError(new ErrorRecord(
ex,
"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation,
name));
continue;
}

WriteObject(processes, true);
} // foreach (string name...
} // else
} // ProcessRecord

#endregion Overrides
} // End GetProcCommand class.

#endregion GetProcCommand
}

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo GetProcessSample05
Artículo • 27/09/2021

En este ejemplo se muestra una versión completa del cmdlet Get-Proc.

Cómo compilar el ejemplo mediante Visual


Studio.
1. Abra Windows Explorador de aplicaciones y vaya al directorio GetProcessSample05
en el directorio Samples.

Con el Windows PowerShell SDK de 2.0 instalado, vaya a la carpeta


GetProcessSample05. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\GetProcessSa
mple05.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en los directorios \bin o \bin\debug


predeterminados.

Ejecución del ejemplo


1. Cree la siguiente carpeta de módulos:

[user]/documents/windowspowershell/modules/GetProcessSample05

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

Import-module getprossessample05

5. Ejecute el siguiente comando para ejecutar el cmdlet :

get-proc
Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar un parámetro de cmdlet mediante el atributo Parameter.

Especificar posiciones para los parámetros.

Especificar que los parámetros pueden tomar la entrada de la canalización. La


entrada se puede tomar de un objeto o un valor de una propiedad de un objeto
cuyo nombre de propiedad es el mismo que el nombre del parámetro.

Declarar un atributo de validación para la entrada del parámetro.

Control de errores y excepciones.

Escribir mensajes de depuración.

Ejemplo
En este ejemplo se muestra cómo crear un cmdlet que muestra una lista de procesos
especificados.

C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell namespace.
using System.Security.Permissions;
using Win32Exception = System.ComponentModel.Win32Exception;
#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc",
DefaultParameterSetName = "ProcessName")]
public class GetProcCommand : PSCmdlet
{
#region Fields
/// <summary>
/// The names of the processes to act on.
/// </summary>
private string[] processNames;

/// <summary>
/// The identifiers of the processes to act on.
/// </summary>
private int[] processIds;

/// <summary>
/// The process objects to act on.
/// </summary>
private Process[] inputObjects;

#endregion Fields

#region Parameters

/// <summary>
/// Gets or sets the list of process names on
/// which the Get-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

/// <summary>
/// Gets or sets the list of process identifiers on
/// which the Get-Proc cmdlet will work.
/// </summary>
[Parameter(
ParameterSetName = "Id",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The unique id of the process to get.")]
public int[] Id
{
get { return this.processIds; }
set { this.processIds = value; }
}

/// <summary>
/// Gets or sets Process objects directly. If the input is a
/// stream of [collection of] Process objects, the cmdlet bypasses the
/// ProcessName and Id parameters and reads the Process objects
/// directly. This allows the cmdlet to deal with processes that have
/// wildcard characters in their name.
/// <value>Process objects</value>
/// </summary>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
public Process[] Input
{
get { return this.inputObjects; }
set { this.inputObjects = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes. Then, the WriteObject
/// method writes the associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
List<Process> matchingProcesses;

WriteDebug("Obtaining the list of matching process objects.");

switch (ParameterSetName)
{
case "Id":
matchingProcesses = this.GetMatchingProcessesById();
break;
case "ProcessName":
matchingProcesses = this.GetMatchingProcessesByName();
break;
case "InputObject":
matchingProcesses = this.GetProcessesByInput();
break;
default:
ThrowTerminatingError(
new ErrorRecord(
new ArgumentException("Bad ParameterSetName"),
"UnableToAccessProcessList",
ErrorCategory.InvalidOperation,
null));
return;
} // switch (ParameterSetName)

WriteDebug("Outputting the matching process objects.");

matchingProcesses.Sort(ProcessComparison);
foreach (Process process in matchingProcesses)
{
WriteObject(process);
}
} // ProcessRecord

#endregion Overrides

#region protected Methods and Data

/// <summary>
/// Retrieves the list of all processes matching the ProcessName
/// parameter and generates a nonterminating error for each
/// specified process name which is not found even though the name
/// contains no wildcards.
/// </summary>
/// <returns>The matching processes.</returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
private List<Process> GetMatchingProcessesByName()
{
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();

List<Process> allProcesses =
new List<Process>(Process.GetProcesses());

// The keys dictionary is used for rapid lookup of


// processes that are already in the matchingProcesses list.
Dictionary<int, byte> keys = new Dictionary<int, byte>();

List<Process> matchingProcesses = new List<Process>();

if (null == this.processNames)
{
matchingProcesses.AddRange(allProcesses);
}
else
{
foreach (string pattern in this.processNames)
{
WriteVerbose("Finding matches for process name \""
+ pattern + "\".");

// WildCard search on the available processes


WildcardPattern wildcard =
new WildcardPattern(
pattern,
WildcardOptions.IgnoreCase);

bool found = false;

foreach (Process process in allProcesses)


{
if (!keys.ContainsKey(process.Id))
{
string processName = SafeGetProcessName(process);

// Remove the process from the allProcesses list


// so that it is not tested again.
if (processName.Length == 0)
{
allProcesses.Remove(process);
}

// Perform a wildcard search on this particular


// process name and check whether it matches the
// pattern specified.
if (!wildcard.IsMatch(processName))
{
continue;
}

WriteDebug("Found matching process id "


+ process.Id + ".");

// A match is found.
found = true;

// Store the process identifier so that the same


process
// is not added twice.
keys.Add(process.Id, 0);

// Add the process to the processes list.


matchingProcesses.Add(process);
}
} // foreach (Process...

if (!found &&
!WildcardPattern.ContainsWildcardCharacters(pattern))
{
WriteError(new ErrorRecord(
new ArgumentException("Cannot find process name "
+ "\"" + pattern + "\"."),
"ProcessNameNotFound",
ErrorCategory.ObjectNotFound,
pattern));
}
} // foreach (string...
} // if (null...

return matchingProcesses;
} // GetMatchingProcessesByName

/// <summary>
/// Returns the name of a process. If an error occurs, a blank
/// string is returned.
/// </summary>
/// <param name="process">The process whose name is
/// returned.</param>
/// <returns>The name of the process.</returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand, Unrestricted = true)]
protected static string SafeGetProcessName(Process process)
{
new EnvironmentPermission(PermissionState.Unrestricted).Assert();
string name = String.Empty;

if (process != null)
{
try
{
return process.ProcessName;
}
catch (Win32Exception)
{
}
catch (InvalidOperationException)
{
}
}

return name;
} // SafeGetProcessName

#endregion Cmdlet Overrides

#region Private Methods

/// <summary>
/// Function to sort by process name first, and then by
/// the process identifier.
/// </summary>
/// <param name="x">First process object.</param>
/// <param name="y">Second process object.</param>
/// <returns>
/// Returns less than zero if x is less than y,
/// greater than 0 if x is greater than y, and 0 if x == y.
/// </returns>
private static int ProcessComparison(Process x, Process y)
{
int diff = String.Compare(
SafeGetProcessName(x),
SafeGetProcessName(y),
StringComparison.CurrentCultureIgnoreCase);

if (0 != diff)
{
return diff;
}
else
{
return x.Id.CompareTo(y.Id);
}
}

/// <summary>
/// Retrieves the list of all processes matching the Id
/// parameter and generates a nonterminating error for
/// each specified process identifier which is not found.
/// </summary>
/// <returns>
/// An array of processes that match the given identifier.
/// </returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
private List<Process> GetMatchingProcessesById()
{
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();

List<Process> matchingProcesses = new List<Process>();

if (null != this.processIds)
{
// The keys dictionary is used for rapid lookup of the
// processes already in the matchingProcesses list.
Dictionary<int, byte> keys = new Dictionary<int, byte>();

foreach (int processId in this.processIds)


{
WriteVerbose("Finding match for process id "
+ processId + ".");

if (!keys.ContainsKey(processId))
{
Process process;
try
{
process = Process.GetProcessById(processId);
}
catch (ArgumentException ex)
{
WriteError(new ErrorRecord(
ex,
"ProcessIdNotFound",
ErrorCategory.ObjectNotFound,
processId));
continue;
}

WriteDebug("Found matching process.");

matchingProcesses.Add(process);
keys.Add(processId, 0);
}
}
}

return matchingProcesses;
} // GetMatchingProcessesById

/// <summary>
/// Retrieves the list of all processes matching the InputObject
/// parameter.
/// </summary>
/// <returns>The matching processes.</returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
private List<Process> GetProcessesByInput()
{
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();

List<Process> matchingProcesses = new List<Process>();

if (null != this.Input)
{
// The keys dictionary is used for rapid lookup of the
// processes already in the matchingProcesses list.
Dictionary<int, byte> keys = new Dictionary<int, byte>();

foreach (Process process in this.Input)


{
WriteVerbose("Refreshing process object.");

if (!keys.ContainsKey(process.Id))
{
try
{
process.Refresh();
}
catch (Win32Exception)
{
}
catch (InvalidOperationException)
{
}

matchingProcesses.Add(process);
}
}
}

return matchingProcesses;
} // GetProcessesByInput
#endregion Private Methods
} // End GetProcCommand class.
#endregion GetProcCommand
}

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo StopProcessSample01
Artículo • 27/09/2021

En este ejemplo se muestra cómo escribir un cmdlet que solicita comentarios al usuario
antes de intentar detener un proceso y cómo implementar un parámetro que indica que
el usuario quiere que el cmdlet devuelva un PassThru objeto. Este cmdlet es similar al
Stop-Process cmdlet proporcionado por Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual Studio.


1. Con el Windows PowerShell SDK de 2.0 instalado, vaya a la carpeta
StopProcessSample01. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\StopProcessSa
mple01.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Microsoft Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Cree la carpeta del módulo siguiente:

[user]/documents/windowspowershell/modules/StopProcessSample01

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

import-module stopprossessample01

5. Ejecute el siguiente comando para ejecutar el cmdlet :

stop-proc
Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar parámetros de cmdlet mediante el atributo Parameter.

Llamar al método ShouldProcess para solicitar confirmación.

Implementar un PassThru parámetro que indica si el usuario quiere que el cmdlet


devuelva un objeto . De forma predeterminada, este cmdlet no devuelve un objeto
a la canalización.

Ejemplo
En este ejemplo se muestra cómo implementar un parámetro que indica que el usuario
quiere que el cmdlet devuelva un objeto y cómo solicitar comentarios del usuario
mediante llamadas a PassThru los métodos ShouldProcess y ShouldContinue .

C#

using System;
using System.Diagnostics;
using System.Collections;
using Win32Exception = System.ComponentModel.Win32Exception;
using System.Management.Automation; // Windows PowerShell namespace
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Commands
{
#region StopProcCommand

/// <summary>
/// This class implements the stop-proc cmdlet.
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// This parameter provides the list of process names on
/// which the Stop-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// This parameter overrides the ShouldContinue call to force
/// the cmdlet to stop its operation. This parameter should always
/// be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// This parameter indicates that the cmdlet should return
/// an object to the pipeline after the processing has been
/// completed.
/// </summary>
[Parameter]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method does the following for each of the
/// requested process names:
/// 1) Check that the process is not a critical process.
/// 2) Attempt to stop that process.
/// If no process is requested then nothing occurs.
/// </summary>
protected override void ProcessRecord()
{
foreach (string name in processNames)
{
// For every process name passed to the cmdlet, get the
associated
// processes.
// Write a nonterminating error for failure to retrieve
// a process.
Process[] processes;

try
{
processes = Process.GetProcessesByName(name);
}
catch (InvalidOperationException ioe)
{
WriteError(new
ErrorRecord(ioe,"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation, name));

continue;
}

// Try to stop the processes that have been retrieved.


foreach (Process process in processes)
{
string processName;

try
{
processName = process.ProcessName;
}
catch (Win32Exception e)
{
WriteError(new ErrorRecord(e, "ProcessNameNotFound",
ErrorCategory.ReadError,
process));
continue;
}

// Confirm the operation with the user first.


// This is always false if the WhatIf parameter is set.
if
(!ShouldProcess(string.Format(CultureInfo.CurrentCulture,"{0} ({1})",
processName,
process.Id)))
{
continue;
}

// Make sure that the user really wants to stop a


critical
// process that could possibly stop the computer.
bool criticalProcess =

criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));

if (criticalProcess &&!force)
{
string message = String.Format
(CultureInfo.CurrentCulture,
"The process \"{0}\" is a critical process
and should not be stopped. Are you sure you wish to stop the process?",
processName);

// It is possible that the ProcessRecord method is


called
// multiple times when objects are received as inputs
from
// the pipeline. So to retain YesToAll and NoToAll
input that
// the user may enter across multiple calls to this
function,
// they are stored as private members of the cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll, ref noToAll))
{
continue;
}
} // if (criticalProcess...

// Stop the named process.


try
{
process.Kill();
}
catch (Exception e)
{
if ((e is Win32Exception) || (e is SystemException)
||
(e is InvalidOperationException))
{
// This process could not be stopped so write
// a nonterminating error.
WriteError(new ErrorRecord(e,
"CouldNotStopProcess",
ErrorCategory.CloseError,
process));
continue;
} // if ((e is...
else throw;
} // catch

// If the PassThru parameter is


// specified, return the terminated process.
if (passThru)
{
WriteObject(process);
}
} // foreach (Process...
} // foreach (string...
} // ProcessRecord

#endregion Cmdlet Overrides

#region Private Data

private bool yesToAll, noToAll;

/// <summary>
/// Partial list of critical processes that should not be
/// stopped. Lower case is used for case insensitive matching.
/// </summary>
private ArrayList criticalProcessNames = new ArrayList(
new string[] { "system", "winlogon", "spoolsv" }
);

#endregion Private Data

} // StopProcCommand

#endregion StopProcCommand
}

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo StopProcessSample02
Artículo • 25/09/2021

En este ejemplo se muestra cómo escribir un cmdlet que escribe mensajes debug
(WriteDebug), verbose (WriteVerbose) y warning (WriteWarning) al detener procesos en
el equipo local. Este cmdlet es similar al Stop-Process cmdlet proporcionado por
Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual Studio.


1. Abra Windows Internet Explorer y vaya al directorio StopProcessSample02 en el
directorio Samples.

Con el Windows PowerShell SDK de 2.0 instalado, vaya a la carpeta


StopProcessSample02. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\StopProcessSa
mple02.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Microsoft Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Cree la carpeta del módulo siguiente:

[user]/documents/windowspowershell/modules/StopProcessSample02

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

import-module stopprossessample02

5. Ejecute el siguiente comando para ejecutar el cmdlet :


stop-proc

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar parámetros de cmdlet mediante el atributo Parameter.

Escribir mensajes detallados. Para obtener más información sobre el método usado
para escribir mensajes detallados, vea
System.Management.Automation.Cmdlet.WriteVerbose.

Escribir mensajes de error. Para obtener más información sobre el método usado
para escribir mensajes de error, vea
System.Management.Automation.Cmdlet.WriteError.

Escribir mensajes de advertencia. Para obtener más información sobre el método


usado para escribir mensajes de advertencia, vea
System.Management.Automation.Cmdlet.WriteWarning.

Ejemplo
En este ejemplo se muestra cómo escribir mensajes de depuración, detallado y de
advertencia mediante WriteDebug los métodos WriteVerbose , y WriteWarning .

C#

using System;
using System.Diagnostics;
using System.Collections;
using Win32Exception = System.ComponentModel.Win32Exception;
using System.Management.Automation; //Windows PowerShell
namespace
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Commands
{
#region StopProcCommand
/// <summary>
/// This class implements the stop-proc cmdlet.
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// This parameter provides the list of process names on
/// which the Stop-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// This parameter overrides the ShouldContinue call to force
/// the cmdlet to stop its operation. This parameter should always
/// be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// This parameter indicates that the cmdlet should return
/// an object to the pipeline after the processing has been
/// completed.
/// </summary>
[Parameter]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;

#endregion Parameters

#region Cmdlet Overrides


/// <summary>
/// The ProcessRecord method does the following for each of the
/// requested process names:
/// 1) Check that the process is not a critical process.
/// 2) Attempt to stop that process.
/// If no process is requested then nothing occurs.
/// </summary>
protected override void ProcessRecord()
{
foreach (string name in processNames)
{
string message = null;

// For every process name passed to the cmdlet, get the


associated
// processes.
// Write a nonterminating error for failure to retrieve
// a process.

// Write a user-friendly verbose message to the pipeline.


These
// messages are intended to give the user detailed
information
// on the operations performed by the cmdlet. These messages
will
// appear with the -Verbose option.
message = String.Format(CultureInfo.CurrentCulture,
"Attempting to stop process \"{0}\".", name);
WriteVerbose(message);

Process[] processes;

try
{
processes = Process.GetProcessesByName(name);
}
catch (InvalidOperationException ioe)
{
WriteError(new ErrorRecord(ioe,
"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation,
name));
continue;
}

// Try to stop the processes that have been retrieved.


foreach (Process process in processes)
{
string processName;

try
{
processName = process.ProcessName;
}
catch (Win32Exception e)
{
WriteError(new ErrorRecord(e, "ProcessNameNotFound",
ErrorCategory.ObjectNotFound,
process));
continue;
}

// Write a debug message to the host that can be used


when
// troubleshooting a problem. All debug messages will
appear
// with the -Debug option.
message = String.Format(CultureInfo.CurrentCulture,
"Acquired name for pid {0} : \"{1}\"",
process.Id, processName);
WriteDebug(message);

// Confirm the operation first.


// This is always false if the WhatIf parameter is
specified.
if
(!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
"{0} ({1})",
processName, process.Id)))
{
continue;
}

// Make sure that the user really wants to stop a


critical
// process that can possibly stop the computer.
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));

if (criticalProcess && !force)


{
message = String.Format(CultureInfo.CurrentCulture,
"The process \"{0}\" is a critical
process and should not be stopped. Are you sure you wish to stop the
process?",
processName);

// It is possible that the ProcessRecord method is


called
// multiple times when objects are received as inputs
from
// the pipeline. So to retain YesToAll and NoToAll
input that
// the user may enter across multiple calls to this
function,
// they are stored as private members of the cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll, ref noToAll))
{
continue;
}
} // if (criticalProcess...

// Display a warning message if the cmdlet is stopping a


// critical process.
if (criticalProcess)
{
message = String.Format(CultureInfo.CurrentCulture,
"Stopping the critical process \"
{0}\".",
processName);
WriteWarning(message);
} // if (criticalProcess...

// Stop the named process.


try
{
process.Kill();
}
catch (Exception e)
{
if ((e is Win32Exception) || (e is SystemException)
||
(e is InvalidOperationException))
{
// This process could not be stopped so write
// a nonterminating error.
WriteError(new ErrorRecord(
e,
"CouldNotStopProcess",
ErrorCategory.CloseError,
process)
);
continue;
} // if ((e is...
else throw;
} // catch

message = String.Format(CultureInfo.CurrentCulture,
"Stopped process \"{0}\", pid {1}.",
processName, process.Id);

WriteVerbose(message);

// If the PassThru parameter is specified,


// return the terminated process object to the pipeline.
if (passThru)
{
message = String.Format(CultureInfo.CurrentCulture,
"Writing process \"{0}\" to pipeline",
processName);
WriteDebug(message);
WriteObject(process);
} // if (passThru...
} // foreach (Process...
} // foreach (string...
} // ProcessRecord

#endregion Cmdlet Overrides

#region Private Data

private bool yesToAll, noToAll;

/// <summary>
/// Partial list of critical processes that should not be
/// stopped. Lower case is used for case insensitive matching.
/// </summary>
private ArrayList criticalProcessNames = new ArrayList(
new string[] { "system", "winlogon", "spoolsv" }
);

#endregion Private Data

} // StopProcCommand

#endregion StopProcCommand
}

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo StopProcessSample03
Artículo • 27/09/2021

En este ejemplo se muestra cómo escribir un cmdlet cuyos parámetros tienen alias y
cuyos parámetros admiten caracteres comodín. Este cmdlet es similar al Stop-Process
cmdlet proporcionado por Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual Studio.


1. Con el SDK Windows PowerShell 2.0 instalado, vaya a la carpeta
StopProcessSample03. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\StopProcessSa
mple03.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Microsoft Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Cree la siguiente carpeta de módulos:

[user]/documents/windowspowershell/modules/StopProcessSample03

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

import-module stopprossessample03

5. Ejecute el siguiente comando para ejecutar el cmdlet :

stop-proc

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar parámetros de cmdlet mediante el atributo Parameter.

Agregar alias a declaraciones de parámetros.

Agregar compatibilidad con caracteres comodín a los parámetros.

Ejemplo
En este ejemplo se muestra cómo declarar alias de parámetro y admitir caracteres
comodín.

C#

using System;
using System.Diagnostics;
using System.Collections;
using Win32Exception = System.ComponentModel.Win32Exception;
using System.Management.Automation; //Windows PowerShell
namespace
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Commands
{

#region StopProcCommand

/// <summary>
/// This class implements the stop-proc cmdlet.
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// This parameter provides the list of process names on
/// which the Stop-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The name of one or more processes to stop.
Wildcards are permitted."
)]
[Alias("ProcessName")]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// This parameter overrides the ShouldContinue call to force
/// the cmdlet to stop its operation. This parameter should always
/// be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// This parameter indicates that the cmdlet should return
/// an object to the pipeline after the processing has been
/// completed.
/// </summary>
[Parameter(
ValueFromPipelineByPropertyName = true,
HelpMessage = "If set, the process(es) will be passed to the
pipeline after stopped."
)]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;

#endregion Parameters

#region Cmdlet Overrides


/// <summary>
/// The ProcessRecord method does the following for each of the
/// requested process names:
/// 1) Check that the process is not a critical process.
/// 2) Attempt to stop that process.
/// If no process is requested then nothing occurs.
/// </summary>
protected override void ProcessRecord()
{
Process[] processes = null;

try
{
processes = Process.GetProcesses();
}
catch (InvalidOperationException ioe)
{
base.ThrowTerminatingError(new ErrorRecord(ioe,
"UnableToAccessProcessList",
ErrorCategory.InvalidOperation,
null));
}

// For every process name passed to the cmdlet, get the


associated
// processes.
// Write a nonterminating error for failure to retrieve
// a process.
foreach (string name in processNames)
{
// Write a user-friendly verbose message to the pipeline.
These
// messages are intended to give the user detailed
information
// on the operations performed by the cmdlet. These messages
will
// appear with the -Verbose option.
string message = String.Format(CultureInfo.CurrentCulture,
"Attempting to stop process \"{0}\".",
name);
WriteVerbose(message);

// Validate the process name against a wildcard pattern.


// If the name does not contain any wildcard patterns, it
// will be treated as an exact match.
WildcardOptions options = WildcardOptions.IgnoreCase |
WildcardOptions.Compiled;
WildcardPattern wildcard = new WildcardPattern(name,options);

foreach (Process process in processes)


{
string processName;

try
{
processName = process.ProcessName;
}
catch (Win32Exception e)
{
WriteError(new ErrorRecord(
e, "ProcessNameNotFound",

ErrorCategory.ObjectNotFound,
process)
);
continue;
}

// Write a debug message to the host that can be used


when
// troubleshooting a problem. All debug messages will
appear
// with the -Debug option.
message = String.Format(CultureInfo.CurrentCulture,
"Acquired name for pid {0} : \"{1}\"",
process.Id, processName);
WriteDebug(message);

// Check to see if this process matches the current


process
// name pattern. Skip this process if it does not.
if (!wildcard.IsMatch(processName))
{
continue;
}

// Stop the process.


SafeStopProcess(process);
} // foreach (Process...
} // foreach (string...
} // ProcessRecord

#endregion Cmdlet Overrides

#region Helper Methods

/// <summary>
/// Safely stops a named process. Used as standalone function
/// to declutter the ProcessRecord method.
/// </summary>
/// <param name="process">The process to stop.</param>
private void SafeStopProcess(Process process)
{
string processName = null;
try
{
processName = process.ProcessName;
}
catch (Win32Exception e)
{
WriteError(new ErrorRecord(e, "ProcessNameNotFound",
ErrorCategory.ObjectNotFound, process));
return;
}

string message = null;

// Confirm the operation first.


// This is always false if the WhatIf parameter is specified.
if (!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
"{0} ({1})", processName, process.Id)))
{
return;
}

// Make sure that the user really wants to stop a critical


// process that could possibly stop the computer.
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));

if (criticalProcess && !force)


{
message = String.Format(CultureInfo.CurrentCulture,
"The process \"{0}\" is a critical process and
should not be stopped. Are you sure you wish to stop the process?",
processName);

// It is possible that ProcessRecord is called multiple


// when objects are received as inputs from a pipeline.
// So, to retain YesToAll and NoToAll input that the
// user may enter across multiple calls to this
// function, they are stored as private members of the
// Cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll, ref noToAll))
{
return;
}
} // if (criticalProcess...

// Display a warning message if stopping a critical


// process.
if (criticalProcess)
{
message = String.Format(CultureInfo.CurrentCulture,
"Stopping the critical process \"{0}\".",
processName);
WriteWarning(message);
} // if (criticalProcess...

try
{
// Stop the process.
process.Kill();
}
catch (Exception e)
{
if ((e is Win32Exception) || (e is SystemException) ||
(e is InvalidOperationException))
{
// This process could not be stopped so write
// a non-terminating error.
WriteError(new ErrorRecord(e, "CouldNotStopProcess",
ErrorCategory.CloseError,
process)
);
return;
} // if ((e is...
else throw;
} // catch

message = String.Format(CultureInfo.CurrentCulture,
"Stopped process \"{0}\", pid {1}.",
processName, process.Id);

WriteVerbose(message);

// If the PassThru parameter is specified,


// return the terminated process to the pipeline.
if (passThru)
{
message = String.Format(CultureInfo.CurrentCulture,
"Writing process \"{0}\" to pipeline",
processName);
WriteDebug(message);
WriteObject(process);
} // if (passThru...
} // SafeStopProcess

#endregion Helper Methods

#region Private Data

private bool yesToAll, noToAll;

/// <summary>
/// Partial list of the critical processes that should not be
/// stopped. Lower case is used for case insensitive matching.
/// </summary>
private ArrayList criticalProcessNames = new ArrayList(
new string[] { "system", "winlogon", "spoolsv" }
);

#endregion Private Data

} // StopProcCommand

#endregion StopProcCommand
} // namespace Microsoft.Samples.PowerShell.Commands

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo StopProcessSample04
Artículo • 25/09/2021

En este ejemplo se muestra cómo escribir un cmdlet que declara conjuntos de


parámetros, especifica el conjunto de parámetros predeterminado y puede aceptar un
objeto de entrada. Este cmdlet es similar al Stop-Process cmdlet proporcionado por
Windows PowerShell 2.0.

Cómo compilar el ejemplo mediante Visual Studio.


1. Con el SDK Windows PowerShell 2.0 instalado, vaya a la carpeta
StopProcessSample04. La ubicación predeterminada es C:\Archivos de programa
(x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\StopProcessSa
mple04.

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Microsoft Visual Studio.

3. En el menú Compilar, seleccione Compilar solución.

La biblioteca del ejemplo se compilará en las carpetas predeterminadas \bin o


\bin\debug.

Ejecución del ejemplo


1. Cree la siguiente carpeta de módulos:

[user]/documents/windowspowershell/modules/StopProcessSample04

2. Copie el ensamblado de ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el ensamblado en Windows PowerShell:

import-module stopprossessample04

5. Ejecute el siguiente comando para ejecutar el cmdlet :

stop-proc
Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Declarar una clase de cmdlet mediante el atributo Cmdlet.

Declarar parámetros de cmdlet mediante el atributo Parameter.

Agregar un parámetro que acepta el objeto de entrada.

Agregar parámetros a conjuntos de parámetros

Especificación del conjunto de parámetros predeterminado.

Ejemplo
El código siguiente muestra una implementación del cmdlet Stop-Proc que declara
conjuntos de parámetros, especifica el conjunto de parámetros predeterminado y puede
aceptar un objeto de entrada.

En este ejemplo se muestra el objeto de entrada, cómo declarar conjuntos de


parámetros y cómo especificar el conjunto de parámetros predeterminado que se va a
usar.

C#

using System;
using System.Diagnostics;
using System.Collections;
using Win32Exception = System.ComponentModel.Win32Exception;
using System.Management.Automation; //Windows PowerShell
namespace
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Commands
{
#region StopProcCommand

/// <summary>
/// This class implements the stop-proc cmdlet.
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName = "ProcessId",
SupportsShouldProcess = true)]
public class StopProcCommand : PSCmdlet
{
#region Parameters

/// <summary>
/// This parameter provides the list of process names on
/// which the Stop-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The name of one or more processes to stop.
Wildcards are permitted."
)]
[Alias("ProcessName")]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// This parameter overrides the ShouldContinue call to force
/// the cmdlet to stop its operation. This parameter should always
/// be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// This parameter indicates that the cmdlet should return
/// an object to the pipeline after the processing has been
/// completed.
/// </summary>
[Parameter(
HelpMessage = "If set the process(es) will be passed to the
pipeline after stopped."
)]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;
/// This parameter provides the list of process identifiers on
/// which the Stop-Proc cmdlet will work.
[Parameter(
ParameterSetName = "ProcessId",
Mandatory = true,
ValueFromPipelineByPropertyName = true,
ValueFromPipeline = true
)]
[Alias("ProcessId")]
public int[] Id
{
get { return processIds; }
set { processIds = value; }
}
private int[] processIds;

/// <summary>
/// This parameter accepts an array of Process objects from the
/// the pipeline. This object contains the processes to stop.
/// </summary>
/// <value>Process objects</value>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
public Process[] InputObject
{
get { return inputObject; }
set { inputObject = value; }
}
private Process[] inputObject;

#endregion Parameters

#region CmdletOverrides

/// <summary>
/// The ProcessRecord method does the following for each of the
/// requested process names:
/// 1) Check that the process is not a critical process.
/// 2) Attempt to stop that process.
/// If no process is requested then nothing occurs.
/// </summary>
protected override void ProcessRecord()
{
switch (ParameterSetName)
{
case "ProcessName":
ProcessByName();
break;

case "ProcessId":
ProcessById();
break;
case "InputObject":
foreach (Process process in inputObject)
{
SafeStopProcess(process);
}
break;

default:
throw new ArgumentException("Bad ParameterSet Name");
} // switch (ParameterSetName...
} // ProcessRecord

#endregion Cmdlet Overrides

#region Helper Methods

/// <summary>
/// Returns all processes with matching names.
/// </summary>
/// <param name="processName">
/// The name of the processes to return.
/// </param>
/// <param name="allProcesses">An array of all
/// computer processes.</param>
/// <returns>An array of matching processes.</returns>
internal ArrayList SafeGetProcessesByName(string processName,
ref ArrayList allProcesses)
{
// Create and array to store the matching processes.
ArrayList matchingProcesses = new ArrayList();

// Create the wildcard for pattern matching.


WildcardOptions options = WildcardOptions.IgnoreCase |
WildcardOptions.Compiled;
WildcardPattern wildcard = new WildcardPattern(processName,
options);

// Walk all of the machine processes.


foreach(Process process in allProcesses)
{
string processNameToMatch = null;
try
{
processNameToMatch = process.ProcessName;
}
catch (Win32Exception e)
{
// Remove the process from the list so that it is not
// checked again.
allProcesses.Remove(process);

string message =
String.Format(CultureInfo.CurrentCulture, "The
process \"{0}\" could not be found",
processName);
WriteVerbose(message);
WriteError(new ErrorRecord(e, "ProcessNotFound",
ErrorCategory.ObjectNotFound,
processName));

continue;
}

if (!wildcard.IsMatch(processNameToMatch))
{
continue;
}

matchingProcesses.Add(process);
} // foreach(Process...

return matchingProcesses;
} // SafeGetProcessesByName

/// <summary>
/// Safely stops a named process. Used as standalone function
/// to declutter the ProcessRecord method.
/// </summary>
/// <param name="process">The process to stop.</param>
private void SafeStopProcess(Process process)
{
string processName = null;

try
{
processName = process.ProcessName;
}
catch (Win32Exception e)
{
WriteError(new ErrorRecord(e, "ProcessNotFound",
ErrorCategory.OpenError, processName));

return;
}

// Confirm the operation first.


// This is always false if the WhatIf parameter is specified.
if (!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
"{0} ({1})", processName, process.Id)))
{
return;
}

// Make sure that the user really wants to stop a critical


// process that can possibly stop the computer.
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));

string message = null;


if (criticalProcess && !force)
{
message = String.Format(CultureInfo.CurrentCulture,
"The process \"{0}\" is a
critical process and should not be stopped. Are you sure you wish to stop
the process?",
processName);
// It is possible that the ProcessRecord method is called
// multiple times when objects are received as inputs from
// the pipeline. So to retain YesToAll and NoToAll input that
// the user may enter across multiple calls to this function,
// they are stored as private members of the cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll, ref noToAll))
{
return;
}
} // if (criticalProcess...

// Display a warning message if stopping a critical


// process.
if (criticalProcess)
{
message =
String.Format(CultureInfo.CurrentCulture,
"Stopping the critical process \"{0}\".",
processName);
WriteWarning(message);
} // if (criticalProcess...

try
{
// Stop the process.
process.Kill();
}
catch (Exception e)
{
if ((e is Win32Exception) || (e is SystemException) ||
(e is InvalidOperationException))
{
// This process could not be stopped so write
// a non-terminating error.
WriteError(new ErrorRecord(e, "CouldNotStopProcess",
ErrorCategory.CloseError,
process)
);

return;
} // if ((e is...
else throw;
} // catch

// Write a user-level verbose message to the pipeline. These are


// intended to give the user detailed information on the
// operations performed by the cmdlet. These messages will
// appear with the -Verbose option.
message = String.Format(CultureInfo.CurrentCulture,
"Stopped process \"{0}\", pid {1}.",
processName, process.Id);

WriteVerbose(message);

// If the PassThru parameter is specified, return the terminated


// process to the pipeline.
if (passThru)
{
// Write a debug message to the host that can be used
// when troubleshooting a problem. All debug messages
// will appear with the -Debug option
message =
String.Format(CultureInfo.CurrentCulture,
"Writing process \"{0}\" to pipeline",
processName);
WriteDebug(message);
WriteObject(process);
} // if (passThru..
} // SafeStopProcess

/// <summary>
/// Stop processes based on their names (using the
/// ParameterSetName as ProcessName)
/// </summary>
private void ProcessByName()
{
ArrayList allProcesses = null;

// Get a list of all processes.


try
{
allProcesses = new ArrayList(Process.GetProcesses());
}
catch (InvalidOperationException ioe)
{
base.ThrowTerminatingError(new ErrorRecord(
ioe, "UnableToAccessProcessList",
ErrorCategory.InvalidOperation, null));
}

// If a process name is passed to the cmdlet, get


// the associated processes.
// Write a nonterminating error for failure to
// retrieve a process.
foreach (string name in processNames)
{
// The allProcesses array list is passed as a reference
because
// any process whose name cannot be obtained will be removed
// from the list so that its not compared the next time.
ArrayList processes =
SafeGetProcessesByName(name, ref allProcesses);
// If no processes were found write a non-
// terminating error.
if (processes.Count == 0)
{
WriteError(new ErrorRecord(
new Exception("Process not found."),
"ProcessNotFound",
ErrorCategory.ObjectNotFound,
name));
} // if (processes...
// Otherwise terminate all processes in the list.
else
{
foreach (Process process in processes)
{
SafeStopProcess(process);
} // foreach (Process...
} // else
} // foreach (string...
} // ProcessByName

/// <summary>
/// Stop processes based on their identifiers (using the
/// ParameterSetName as ProcessIds)
/// </summary>
internal void ProcessById()
{
foreach (int processId in processIds)
{
Process process = null;
try
{
process = Process.GetProcessById(processId);

// Write a debug message to the host that can be used


// when troubleshooting a problem. All debug messages
// will appear with the -Debug option
string message =
String.Format(CultureInfo.CurrentCulture,
"Acquired process for pid : {0}",
process.Id);
WriteDebug(message);
}
catch (ArgumentException ae)
{
string
message = String.Format(CultureInfo.CurrentCulture,
"The process id {0} could not be
found",
processId);
WriteVerbose(message);
WriteError(new ErrorRecord(ae, "ProcessIdNotFound",
ErrorCategory.ObjectNotFound,
processId));
continue;
}

SafeStopProcess(process);
} // foreach (int...
} // ProcessById

#endregion Helper Methods

#region Private Data

private bool yesToAll, noToAll;

/// <summary>
/// Partial list of critical processes that should not be
/// stopped. Lower case is used for case insensitive matching.
/// </summary>
private ArrayList criticalProcessNames = new ArrayList(
new string[] { "system", "winlogon", "spoolsv", "calc" }
);

#endregion Private Data

} // StopProcCommand

#endregion StopProcCommand
}

Vea también
Escribir un cmdlet de Windows PowerShell
Ejemplo Events01
Artículo • 24/09/2021

En este ejemplo se muestra cómo crear un cmdlet que permita al usuario registrarse
para los eventos que genera System.IO.FileSystemWatcher. Con este cmdlet, los usuarios
pueden registrar una acción para ejecutarla cuando se crea un archivo en un directorio
específico. Este ejemplo se deriva de la clase base
Microsoft.PowerShell.Commands.ObjectEventRegistrationBase.

Cómo compilar el ejemplo mediante Visual


Studio.
1. Con el SDK Windows PowerShell 2.0 instalado, vaya a la carpeta Events01. La
ubicación predeterminada es C:\Program Files (x86)\Microsoft
SDKs\Windows\v7.0\Samples\sysmgmt\WindowsPowerShell\csharp\Events01 .

2. Haga doble clic en el icono del archivo de solución (.sln). Se abre el proyecto de
ejemplo en Microsoft Visual Studio.

3. En el menú Compilar, seleccione Compilar solución. La biblioteca del ejemplo se


basará en las carpetas \bin o \bin\debug predeterminadas.

Ejecución del ejemplo


1. Cree la siguiente carpeta de módulos:

[user]/documents/windowspowershell/modules/events01

2. Copie el archivo de biblioteca del ejemplo en la carpeta del módulo.

3. Inicie Windows PowerShell.

4. Ejecute el siguiente comando para cargar el cmdlet en Windows PowerShell:

PowerShell

import-module events01

5. Use el cmdlet Register-FileSystemEvent para registrar una acción que escribirá un


mensaje cuando se cree un archivo en el directorio TEMP.
PowerShell

Register-FileSystemEvent $env:temp Created -filter "*.txt" -action {


Write-Host "A file was created in the TEMP directory" }

6. Cree un archivo en el directorio TEMP y observe que se ejecuta la acción (se


muestra el mensaje).

Se trata de una salida de ejemplo que se genera siguiendo estos pasos.

Resultados

Id Name State HasMoreData Location


Command
-- ---- ----- ----------- --------
-------
1 26932870-d3b... NotStarted False
Write-Host "A f...

PowerShell

Set-Content $env:temp\test.txt "This is a test file"

Resultados

A file was created in the TEMP directory

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Escritura de un cmdlet para el registro de eventos


El cmdlet se deriva de la clase
Microsoft.PowerShell.Commands.ObjectEventRegistrationBase, que proporciona
compatibilidad con parámetros comunes a Register-*Event los cmdlets. Los cmdlets
que se derivan de Microsoft.PowerShell.Commands.ObjectEventRegistrationBase solo
necesitan definir sus parámetros concretos e invalidar los métodos GetSourceObject
GetSourceObjectEventName abstractos y .

Ejemplo
En este ejemplo se muestra cómo registrarse para los eventos que genera
System.IO.FileSystemWatcher.

C#

namespace Sample
{
using System;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell.Commands;

[Cmdlet(VerbsLifecycle.Register, "FileSystemEvent")]
public class RegisterObjectEventCommand : ObjectEventRegistrationBase
{
/// <summary>The FileSystemWatcher that exposes the events.
</summary>
private FileSystemWatcher fileSystemWatcher = new
FileSystemWatcher();

/// <summary>Name of the event to which the cmdlet registers.


</summary>
private string eventName = null;

/// <summary>
/// Gets or sets the path that will be monitored by the
FileSystemWatcher.
/// </summary>
[Parameter(Mandatory = true, Position = 0)]
public string Path
{
get
{
return this.fileSystemWatcher.Path;
}

set
{
this.fileSystemWatcher.Path = value;
}
}

/// <summary>
/// Gets or sets the name of the event to which the cmdlet
registers.
/// <para>
/// Currently System.IO.FileSystemWatcher exposes 6 events: Changed,
Created,
/// Deleted, Disposed, Error, and Renamed. Check the documentation
of
/// FileSystemWatcher for details on each event.
/// </para>
/// </summary>
[Parameter(Mandatory = true, Position = 1)]
public string EventName
{
get
{
return this.eventName;
}

set
{
this.eventName = value;
}
}

/// <summary>
/// Gets or sets the filter that will be user by the
FileSystemWatcher.
/// </summary>
[Parameter(Mandatory = false)]
public string Filter
{
get
{
return this.fileSystemWatcher.Filter;
}

set
{
this.fileSystemWatcher.Filter = value;
}
}

/// <summary>
/// Derived classes must implement this method to return the object
that generates
/// the events to be monitored.
/// </summary>
/// <returns> This sample returns an instance of
System.IO.FileSystemWatcher</returns>
protected override object GetSourceObject()
{
return this.fileSystemWatcher;
}

/// <summary>
/// Derived classes must implement this method to return the name of
the event to
/// be monitored. This event must be exposed by the input object.
/// </summary>
/// <returns> This sample returns the event specified by the user
with the -EventName parameter.</returns>
protected override string GetSourceObjectEventName()
{
return this.eventName;
}
}
}

Vea también
Escribir un cmdlet de Windows PowerShell
Escritura de un módulo de Windows
PowerShell
Artículo • 25/09/2021

Este documento está escrito para administradores, desarrolladores de scripts y


desarrolladores de cmdlets que necesitan empaquetar y distribuir sus Windows
PowerShell cmdlets. Al usar Windows PowerShell módulos, puede empaquetar y
distribuir las soluciones de Windows PowerShell sin usar un lenguaje compilado.

Windows PowerShell módulos permiten particionar, organizar y abstraer el código


Windows PowerShell en unidades reutilizables independientes. Con estas unidades
reutilizables, puede compartir fácilmente los módulos directamente con otros usuarios.
Si es desarrollador de scripts, también puede volver a empaquetar módulos de terceros
para crear aplicaciones personalizadas basadas en scripts. Los módulos, similares a los
de otros lenguajes de scripting como Perl y Python, permiten soluciones de scripting
listas para producción que usan componentes reutilizables y redistribuibles, con la
ventaja adicional de permitirle volver a empaquetar y abstraer varios componentes para
crear soluciones personalizadas.

En su nivel más básico, Windows PowerShell tratará cualquier código de script de


Windows PowerShell válido guardado en .psm1 un archivo como un módulo. PowerShell
también tratará automáticamente cualquier ensamblado de cmdlet binario como un
módulo. Sin embargo, también puede usar un módulo (o más específicamente, un
manifiesto de módulo) para agrupar una solución completa. En los escenarios siguientes
se describen los usos típicos Windows PowerShell módulos.

Bibliotecas
Los módulos se pueden usar para empaquetar y distribuir bibliotecas cohesivas de
funciones que realizan tareas comunes. Normalmente, los nombres de estas funciones
comparten uno o varios nombres que reflejan la tarea común para la que se usan. Estas
funciones también pueden ser similares a .NET Framework clases en que pueden tener
miembros públicos y privados. Por ejemplo, una biblioteca puede contener un conjunto
de funciones para las transferencias de archivos. En este caso, el nombre que refleja la
tarea común podría ser "file".

Configuración
Los módulos se pueden usar para personalizar el entorno mediante la adición de
cmdlets, proveedores, funciones y variables específicos.

Desarrollo y distribución de código compilado


Los desarrolladores de cmdlets y proveedores pueden usar módulos para probar y
distribuir su código compilado sin necesidad de crear complementos. Pueden importar
el ensamblado que contiene el código compilado como un módulo (un módulo binario)
sin necesidad de crear y registrar complementos.

Consulte también
Descripción de un módulo de Windows PowerShell

Cómo escribir un módulo de script de PowerShell

Cómo escribir un módulo binario de PowerShell

Cómo escribir un manifiesto de módulo de PowerShell

acerca de_about_PSModulePath

Importación de un módulo de PowerShell

Instalación de un módulo de PowerShell


Descripción de un módulo de
Windows PowerShell
Artículo • 27/09/2021

Un módulo es un conjunto de funcionalidades Windows PowerShell relacionadas,


agrupadas como una unidad cómoda (normalmente guardada en un único directorio).
Al definir un conjunto de archivos de script relacionados, ensamblados y recursos
relacionados como un módulo, puede hacer referencia, cargar, conservar y compartir el
código mucho más fácil de lo que haría de lo contrario.

El propósito principal de un módulo es permitir la modularización (es decir, reutilización


y abstracción) de Windows PowerShell código. Por ejemplo, la manera más básica de
crear un módulo es simplemente guardar un script Windows PowerShell como un
archivo .psm1. Esto le permite controlar (es decir, hacer públicas o privadas) las
funciones y variables contenidas en el script. Guardar el script como un archivo .psm1
también permite controlar el ámbito de determinadas variables. Por último, también
puede usar cmdlets como Install-Module para organizar, instalar y usar el script como
bloques de creación para soluciones más grandes.

Componentes y tipos de módulos


Un módulo se integra en cuatro componentes básicos:

1. Algún tipo de archivo de código: normalmente un script de PowerShell o un


ensamblado de cmdlet administrado.

2. Cualquier otra cosa que el archivo de código anterior pueda necesitar, como
ensamblados adicionales, archivos de ayuda o scripts.

3. Un archivo de manifiesto que describe los archivos anteriores, así como almacena
metadatos como información de creación y control de versiones.

4. Un directorio que contiene todo el contenido anterior y se encuentra donde


PowerShell puede encontrarlo razonablemente.

7 Nota

ninguno de estos componentes, por sí mismos, son realmente necesarios. Por


ejemplo, un módulo puede ser técnicamente solo un script almacenado en un
archivo .psm1. También puede tener un módulo que no es más que un
archivo de manifiesto, que se usa principalmente con fines organizativos.
También puede escribir un script que cree dinámicamente un módulo y, como
tal, no necesita realmente un directorio en el que almacenar nada. En las
secciones siguientes se describen los tipos de módulos que puede obtener
combinando y haciendo coincidir las distintas partes posibles de un módulo.

Módulos de script
Como su nombre indica, un módulo de script es un archivo ( ) que contiene cualquier
código Windows PowerShell .psm1 válido. Los desarrolladores y administradores de
scripts pueden usar este tipo de módulo para crear módulos cuyos miembros incluyen
funciones, variables, etc. En el fondo, un módulo de script es simplemente un script
Windows PowerShell con una extensión diferente, lo que permite a los administradores
usar funciones de importación, exportación y administración en él.

Además, puede usar un archivo de manifiesto para incluir otros recursos en el módulo,
como archivos de datos, otros módulos dependientes o scripts en tiempo de ejecución.
Los archivos de manifiesto también son útiles para realizar el seguimiento de metadatos,
como la información de creación y control de versiones.

Por último, un módulo de script, como cualquier otro módulo que no se crea
dinámicamente, debe guardarse en una carpeta que PowerShell pueda detectar
razonablemente. Normalmente, se encuentra en la ruta de acceso del módulo de
PowerShell. pero, si es necesario, puede describir explícitamente dónde está instalado el
módulo. Para obtener más información, vea How to Write a PowerShell Script Module.

Módulos binarios
Un módulo binario es un ensamblado .NET Framework ( ) que contiene código .dll
compilado, como C#. Los desarrolladores de cmdlets pueden usar este tipo de módulo
para compartir cmdlets, proveedores y mucho más. (Los complementos existentes
también se pueden usar como módulos binarios). En comparación con un módulo de
script, un módulo binario permite crear cmdlets que son más rápidos o usar
características (como multithreading) que no son tan fáciles de codificar en scripts
Windows PowerShell scripts.

Al igual que con los módulos de script, puede incluir un archivo de manifiesto para
describir los recursos adicionales que usa el módulo y para realizar un seguimiento de
los metadatos sobre el módulo. De forma similar, probablemente debería instalar el
módulo binario en una carpeta en algún lugar a lo largo de la ruta de acceso del
módulo de PowerShell. Para obtener más información, vea How to Write a PowerShell
Binary Module.

Módulos de manifiesto
Un módulo de manifiesto es un módulo que usa un archivo de manifiesto para describir
todos sus componentes, pero no tiene ningún tipo de ensamblado o script principal.
(Formalmente, un módulo de manifiesto deja vacío el elemento ModuleToProcess
RootModule o del manifiesto). Sin embargo, todavía puede usar las otras características
de un módulo, como la capacidad de cargar ensamblados dependientes o ejecutar
automáticamente determinados scripts de procesamiento previo. También puede usar
un módulo de manifiesto como una manera cómoda de empaquetar los recursos que
usarán otros módulos, como módulos anidados, ensamblados, tipos o formatos. Para
obtener más información, vea How to Write a PowerShell Module Manifest.

Módulos dinámicos
Un módulo dinámico es un módulo que no se carga desde un archivo ni se guarda en
este. En su lugar, se crean dinámicamente mediante un script, mediante el cmdlet New-
Module. Este tipo de módulo permite a un script crear un módulo a petición que no es
necesario cargar ni guardar en el almacenamiento persistente. Por su naturaleza, un
módulo dinámico está pensado para ser de corta duración y, por tanto, el cmdlet no
puede acceder a Get-Module él. De forma similar, normalmente no necesitan manifiestos
de módulo, ni es probable que necesiten carpetas permanentes para almacenar sus
ensamblados relacionados.

Manifiestos de módulo
Un manifiesto de módulo es un archivo que contiene una tabla .psd1 hash. Las claves y
los valores de la tabla hash hacen lo siguiente:

Describir el contenido y los atributos del módulo.

Defina los requisitos previos.

Determine cómo se procesan los componentes.

No es obligatorio que un módulo tenga manifiestos. Los módulos pueden hacer


referencia a archivos de script ( ), archivos de módulo de script ( ), archivos de
manifiesto ( ), archivos de formato y de tipo ( ), ensamblados de cmdlet y
proveedor (), archivos de recursos, archivos de Ayuda, archivos de localización o
cualquier otro tipo de archivo o recurso que se incluye como parte .ps1 .psm1 del
.psd1 .ps1xml .dll módulo. Para un script internacionalizado, la carpeta del
módulo también contiene un conjunto de archivos de catálogo de mensajes. Si
agrega un archivo de manifiesto a la carpeta del módulo, puede hacer referencia a
los varios archivos como una sola unidad haciendo referencia al manifiesto.

El propio manifiesto describe las siguientes categorías de información:

Metadatos sobre el módulo, como el número de versión del módulo, el autor y la


descripción.

Requisitos previos necesarios para importar el módulo, como la versión Windows


PowerShell, la versión de Common Language Runtime (CLR) y los módulos
necesarios.

Directivas de procesamiento, como los scripts, formatos y tipos que se procesarán.

Restricciones en los miembros del módulo que se exportarán, como los alias, las
funciones, las variables y los cmdlets que se exportarán.

Para obtener más información, vea How to Write a PowerShell Module Manifest.

Almacenar e instalar un módulo


Una vez que haya creado un módulo de script, binario o manifiesto, puede guardar el
trabajo en una ubicación a la que otros usuarios puedan acceder a él. Por ejemplo, el
módulo se puede almacenar en la carpeta del sistema donde Windows PowerShell está
instalado o se puede almacenar en una carpeta de usuario.

Por lo general, puede determinar dónde debe instalar el módulo mediante una de las
rutas de acceso almacenadas en la $ENV:PSModulePath variable . El uso de una de estas
rutas de acceso significa que PowerShell puede buscar y cargar automáticamente el
módulo cuando un usuario realiza una llamada a él en su código. Si almacena el módulo
en otro lugar, puede hacer que PowerShell lo sepa explícitamente pasando la ubicación
del módulo como un parámetro al llamar a Install-Module .

Independientemente de ello, la ruta de acceso de la carpeta se conoce como la base del


módulo (ModuleBase) y el nombre del archivo de módulo de script, binario o manifiesto
debe ser el mismo que el nombre de la carpeta del módulo, con las siguientes
excepciones:

Los módulos dinámicos creados por New-Module el cmdlet se pueden denominar


mediante el parámetro del cmdlet Name .
Los módulos importados desde objetos de ensamblado Import-Module -Assembly
mediante el comando se denominan según la sintaxis siguiente:
"dynamic_code_module_" + assembly.GetName() .

Para obtener más información, vea Instalación de un módulo de PowerShell y


about_PSModulePath.

Cmdlets y variables de módulo


Los siguientes cmdlets y variables se proporcionan mediante Windows PowerShell para
la creación y administración de módulos.

Cmdlet New-Module Este cmdlet crea un nuevo módulo dinámico que solo existe en
memoria. El módulo se crea a partir de un bloque de script y sus miembros exportados,
como sus funciones y variables, están disponibles inmediatamente en la sesión y
permanecen disponibles hasta que se cierra la sesión.

Cmdlet New-ModuleManifest Este cmdlet crea un nuevo archivo de manifiesto de


módulo (.psd1), rellena sus valores y guarda el archivo de manifiesto en la ruta de
acceso especificada. Este cmdlet también se puede usar para crear una plantilla de
manifiesto de módulo que se puede rellenar manualmente.

Cmdlet Import-Module Este cmdlet agrega uno o varios módulos a la sesión actual.

Cmdlet Get-Module Este cmdlet recupera información sobre los módulos que se han
importado o que se pueden importar en la sesión actual.

Cmdlet Export-ModuleMember Este cmdlet especifica los miembros del módulo (como
cmdlets, funciones, variables y alias) que se exportan desde un archivo de módulo de
script (.psm1) o desde un módulo dinámico creado mediante el New-Module cmdlet .

Cmdlet Remove-Module Este cmdlet quita módulos de la sesión actual.

Cmdlet Test-ModuleManifest Este cmdlet comprueba que un manifiesto de módulo


describe con precisión los componentes de un módulo comprobando que los archivos
que aparecen en el archivo de manifiesto del módulo (.psd1) existen realmente en las
rutas de acceso especificadas.

$PSScriptRoot esta variable contiene el directorio desde el que se ejecuta el módulo de


script. Permite que los scripts usen la ruta de acceso del módulo para acceder a otros
recursos.

$env:PSModulePath Esta variable de entorno contiene una lista de los directorios en los
que Windows PowerShell se almacenan los módulos. Windows PowerShell usa el valor
de esta variable al importar módulos automáticamente y actualizar los temas de Ayuda
de los módulos.

Consulte también
Escritura de un módulo de Windows PowerShell
Cómo escribir un módulo de script de
PowerShell
Artículo • 13/06/2022

Un módulo de script es cualquier script de PowerShell válido guardado en una .psm1


extensión. Esta extensión permite al motor de PowerShell usar reglas y cmdlets de
módulo en el archivo. La mayoría de estas funcionalidades están disponibles para
ayudarle a instalar el código en otros sistemas, así como para administrar el ámbito.
También puede usar un archivo de manifiesto de módulo, que describe instalaciones y
soluciones más complejas.

Escritura de un módulo de script de PowerShell


Para crear un módulo de script, guarde un script de PowerShell válido en un .psm1
archivo. El script y el directorio donde se almacena deben usar el mismo nombre. Por
ejemplo, un script denominado MyPsScript.psm1 se almacena en un directorio
denominado MyPsScript .

El directorio del módulo debe estar en una ruta de acceso especificada en


$env:PSModulePath . El directorio del módulo puede contener los recursos necesarios
para ejecutar el script y un archivo de manifiesto de módulo que describe a PowerShell
cómo funciona el módulo.

Creación de un módulo básico de PowerShell


En los pasos siguientes se describe cómo crear un módulo de PowerShell.

1. Guarde un script de PowerShell con una .psm1 extensión. Use el mismo nombre
para el script y el directorio donde se guarda el script.

Guardar un script con la .psm1 extensión significa que puede usar los cmdlets del
módulo, como Import-Module. Los cmdlets del módulo existen principalmente
para que pueda importar y exportar el código a los sistemas de otros usuarios. La
solución alternativa sería cargar el código en otros sistemas y, a continuación, dot-
source it en memoria activa, que no es una solución escalable. Para obtener más
información, consulte Descripción de un módulo de Windows PowerShell. De
forma predeterminada, cuando los usuarios importan el .psm1 archivo, todas las
funciones del script son accesibles, pero las variables no.
Un script de PowerShell de ejemplo, titulado Show-Calendar , está disponible al final
de este artículo.

PowerShell

function Show-Calendar {
param(
[DateTime] $start = [DateTime]::Today,
[DateTime] $end = $start,
$firstDayOfWeek,
[int[]] $highlightDay,
[string[]] $highlightDate = [DateTime]::Today.ToString('yyyy-MM-
dd')
)

#actual code for the function goes here see the end of the topic
for the complete code sample
}

2. Para controlar el acceso de usuario a determinadas funciones o variables, llame a


Export-ModuleMember al final del script.

El código de ejemplo de la parte inferior del artículo tiene solo una función, que de
forma predeterminada se expondría. Sin embargo, se recomienda llamar
explícitamente las funciones que desea exponer, como se describe en el código
siguiente:

PowerShell

function Show-Calendar {
}
Export-ModuleMember -Function Show-Calendar

Puede restringir lo que se importa mediante un manifiesto de módulo. Para


obtener más información, consulte Importación de un módulo de PowerShell y
Cómo escribir un manifiesto de módulo de PowerShell.

3. Si tiene módulos que su propio módulo necesita cargar, puede usar Import-
Module , en la parte superior del módulo.

El Import-Module cmdlet importa un módulo de destino en un sistema y se puede


usar más adelante en el procedimiento para instalar su propio módulo. El código
de ejemplo de la parte inferior de este artículo no usa ningún módulo de
importación. Pero, si lo hiciera, se mostrarán en la parte superior del archivo, como
se muestra en el código siguiente:
PowerShell

Import-Module GenericModule

4. Para describir el módulo al sistema de ayuda de PowerShell, puede usar


comentarios de ayuda estándar dentro del archivo o crear un archivo de Ayuda
adicional.

El ejemplo de código de la parte inferior de este artículo incluye la información de


ayuda en los comentarios. También puede escribir archivos XML expandidos que
contengan contenido de ayuda adicional. Para obtener más información, vea
Escribir ayuda para Windows PowerShell módulos.

5. Si tiene módulos adicionales, archivos XML u otro contenido que quiera


empaquetar con el módulo, puede usar un manifiesto de módulo.

Un manifiesto de módulo es un archivo que contiene los nombres de otros


módulos, diseños de directorio, números de control de versiones, datos de autor y
otros fragmentos de información. PowerShell usa el archivo de manifiesto del
módulo para organizar e implementar la solución. Para obtener más información,
consulte Cómo escribir un manifiesto de módulo de PowerShell.

6. Para instalar y ejecutar el módulo, guarde el módulo en una de las rutas de acceso
de PowerShell adecuadas y use Import-Module .

Las rutas de acceso en las que puede instalar el módulo se encuentran en la


$env:PSModulePath variable global. Por ejemplo, una ruta de acceso común para
guardar un módulo en un sistema sería
%SystemRoot%/users/<user>/Documents/PowerShell/Modules/<moduleName> .
Asegúrese de crear un directorio para el módulo que use el mismo nombre que el
módulo de script, incluso si solo es un único .psm1 archivo. Si no guardó el
módulo en una de estas rutas de acceso, tendría que especificar la ubicación del
módulo en el Import-Module comando . De lo contrario, PowerShell no podría
encontrar el módulo.

7 Nota

A partir de PowerShell 3.0, si ha colocado el módulo en una de las rutas de


acceso del módulo de PowerShell, no es necesario importarlo explícitamente.
El módulo se carga automáticamente cuando un usuario llama a la función.
Para obtener más información sobre la ruta de acceso del módulo, consulte
Importación de un módulo de PowerShell y about_PSModulePath.
7. Para quitar un módulo del servicio activo en la sesión actual de PowerShell, use
Remove-Module.

7 Nota

Remove-Module quita un módulo de la sesión actual de PowerShell, pero no


desinstala el módulo ni elimina los archivos del módulo.

ejemplo de código de Show-Calendar


El ejemplo siguiente es un módulo de script que contiene una sola función denominada
Show-Calendar . Esta función muestra una representación visual de un calendario. El

ejemplo contiene las cadenas de ayuda de PowerShell para la synopsis, la descripción,


los valores de parámetro y el código. Cuando se importa el módulo, el Export-
ModuleMember comando garantiza que la Show-Calendar función se exporte como
miembro del módulo.

PowerShell

<#
.Synopsis
Displays a visual representation of a calendar.

.Description
Displays a visual representation of a calendar. This function supports
multiple months
and lets you highlight specific date ranges or days.

.Parameter Start
The first month to display.

.Parameter End
The last month to display.

.Parameter FirstDayOfWeek
The day of the month on which the week begins.

.Parameter HighlightDay
Specific days (numbered) to highlight. Used for date ranges like (25..31).
Date ranges are specified by the Windows PowerShell range syntax. These
dates are
enclosed in square brackets.

.Parameter HighlightDate
Specific days (named) to highlight. These dates are surrounded by
asterisks.
.Example
# Show a default display of this month.
Show-Calendar

.Example
# Display a date range.
Show-Calendar -Start "March, 2010" -End "May, 2010"

.Example
# Highlight a range of days.
Show-Calendar -HighlightDay (1..10 + 22) -HighlightDate "2008-12-25"
#>
function Show-Calendar {
param(
[DateTime] $start = [DateTime]::Today,
[DateTime] $end = $start,
$firstDayOfWeek,
[int[]] $highlightDay,
[string[]] $highlightDate = [DateTime]::Today.ToString('yyyy-MM-dd')
)

## Determine the first day of the start and end months.


$start = New-Object DateTime $start.Year,$start.Month,1
$end = New-Object DateTime $end.Year,$end.Month,1

## Convert the highlighted dates into real dates.


[DateTime[]] $highlightDate = [DateTime[]] $highlightDate

## Retrieve the DateTimeFormat information so that the


## calendar can be manipulated.
$dateTimeFormat = (Get-Culture).DateTimeFormat
if($firstDayOfWeek)
{
$dateTimeFormat.FirstDayOfWeek = $firstDayOfWeek
}

$currentDay = $start

## Process the requested months.


while($start -le $end)
{
## Return to an earlier point in the function if the first day of the
month
## is in the middle of the week.
while($currentDay.DayOfWeek -ne $dateTimeFormat.FirstDayOfWeek)
{
$currentDay = $currentDay.AddDays(-1)
}

## Prepare to store information about this date range.


$currentWeek = New-Object PsObject
$dayNames = @()
$weeks = @()

## Continue processing dates until the function reaches the end of the
month.
## The function continues until the week is completed with
## days from the next month.
while(($currentDay -lt $start.AddMonths(1)) -or
($currentDay.DayOfWeek -ne $dateTimeFormat.FirstDayOfWeek))
{
## Determine the day names to use to label the columns.
$dayName = "{0:ddd}" -f $currentDay
if($dayNames -notcontains $dayName)
{
$dayNames += $dayName
}

## Pad the day number for display, highlighting if necessary.


$displayDay = " {0,2} " -f $currentDay.Day

## Determine whether to highlight a specific date.


if($highlightDate)
{
$compareDate = New-Object DateTime $currentDay.Year,
$currentDay.Month,$currentDay.Day
if($highlightDate -contains $compareDate)
{
$displayDay = "*" + ("{0,2}" -f $currentDay.Day) + "*"
}
}

## Otherwise, highlight as part of a date range.


if($highlightDay -and ($highlightDay[0] -eq $currentDay.Day))
{
$displayDay = "[" + ("{0,2}" -f $currentDay.Day) + "]"
$null,$highlightDay = $highlightDay
}

## Add the day of the week and the day of the month as note
properties.
$currentWeek | Add-Member NoteProperty $dayName $displayDay

## Move to the next day of the month.


$currentDay = $currentDay.AddDays(1)

## If the function reaches the next week, store the current week
## in the week list and continue.
if($currentDay.DayOfWeek -eq $dateTimeFormat.FirstDayOfWeek)
{
$weeks += $currentWeek
$currentWeek = New-Object PsObject
}
}

## Format the weeks as a table.


$calendar = $weeks | Format-Table $dayNames -AutoSize | Out-String

## Add a centered header.


$width = ($calendar.Split("`n") | Measure-Object -Maximum
Length).Maximum
$header = "{0:MMMM yyyy}" -f $start
$padding = " " * (($width - $header.Length) / 2)
$displayCalendar = " `n" + $padding + $header + "`n " + $calendar
$displayCalendar.TrimEnd()

## Move to the next month.


$start = $start.AddMonths(1)

}
}
Export-ModuleMember -Function Show-Calendar
Cómo escribir un módulo binario de
PowerShell
Artículo • 24/09/2021

Un módulo binario puede ser cualquier ensamblado (.dll) que contenga clases de
cmdlet. De forma predeterminada, todos los cmdlets del ensamblado se importan
cuando se importa el módulo binario. Sin embargo, puede restringir los cmdlets que se
importan mediante la creación de un manifiesto de módulo cuyo módulo raíz es el
ensamblado. (Por ejemplo, la clave CmdletsToExport del manifiesto se puede usar para
exportar solo los cmdlets necesarios). Además, un módulo binario puede contener
archivos adicionales, una estructura de directorios y otros fragmentos de información de
administración útiles que un solo cmdlet no puede.

En el procedimiento siguiente se describe cómo crear e instalar un módulo binario de


PowerShell.

Creación e instalación de un módulo binario de


PowerShell
1. Cree una solución binaria de PowerShell (por ejemplo, un cmdlet escrito en C#),
con las funcionalidades que necesita y asegúrese de que se ejecuta correctamente.

Desde la perspectiva del código, el núcleo de un módulo binario es simplemente


un ensamblado de cmdlet. De hecho, PowerShell tratará un único ensamblado de
cmdlet como un módulo, en términos de carga y descarga, sin ningún esfuerzo
adicional por parte del desarrollador. Para obtener más información sobre cómo
escribir un cmdlet, vea Escribir un cmdlet Windows PowerShell .

2. Si es necesario, cree el resto de la solución: (cmdlets adicionales, archivos XML,


entre otros) y describenlos con un manifiesto de módulo.

Además de describir los ensamblados de cmdlet de la solución, un manifiesto de


módulo puede describir cómo quiere que el módulo se exporte e importe, qué
cmdlets se exponen y qué archivos adicionales se van a agregar al módulo. Sin
embargo, como se indicó anteriormente, PowerShell puede tratar un cmdlet
binario como un módulo sin ningún esfuerzo adicional. Por lo tanto, un manifiesto
de módulo es útil principalmente para combinar varios archivos en un único
paquete o para controlar explícitamente la publicación de un ensamblado
determinado. Para obtener más información, vea How to Write a PowerShell
Module Manifest.

El código siguiente es un bloque de código de C# extremadamente sencillo que


contiene tres cmdlets en el mismo archivo que se pueden usar como módulo.

C#

using System.Management.Automation; // Windows PowerShell


namespace.

namespace ModuleCmdlets
{
[Cmdlet(VerbsDiagnostic.Test,"BinaryModuleCmdlet1")]
public class TestBinaryModuleCmdlet1Command : Cmdlet
{
protected override void BeginProcessing()
{
WriteObject("BinaryModuleCmdlet1 exported by the ModuleCmdlets
module.");
}
}

[Cmdlet(VerbsDiagnostic.Test, "BinaryModuleCmdlet2")]
public class TestBinaryModuleCmdlet2Command : Cmdlet
{
protected override void BeginProcessing()
{
WriteObject("BinaryModuleCmdlet2 exported by the
ModuleCmdlets module.");
}
}

[Cmdlet(VerbsDiagnostic.Test, "BinaryModuleCmdlet3")]
public class TestBinaryModuleCmdlet3Command : Cmdlet
{
protected override void BeginProcessing()
{
WriteObject("BinaryModuleCmdlet3 exported by the
ModuleCmdlets module.");
}
}

3. Empaquete la solución y guarde el paquete en algún lugar de la ruta de acceso del


módulo de PowerShell.

La PSModulePath variable de entorno global describe las rutas de acceso


predeterminadas que Usará PowerShell para buscar el módulo. Por ejemplo, una
ruta de acceso común para guardar un módulo en un sistema sería
%SystemRoot%\users\<user>\Documents\WindowsPowerShell\Modules\<moduleName> . Si

no usa las rutas de acceso predeterminadas, deberá especificar explícitamente la


ubicación del módulo durante la instalación. Asegúrese de crear una carpeta en la
que guardar el módulo, ya que puede que necesite la carpeta para almacenar
varios ensamblados y archivos para la solución.

Tenga en cuenta que, técnicamente, no es necesario instalar el módulo en ningún


lugar de ; son simplemente las ubicaciones predeterminadas que PSModulePath
PowerShell buscará para el módulo. Sin embargo, se considera un procedimiento
recomendado hacerlo, a menos que tenga una buena razón para almacenar el
módulo en otro lugar. Para obtener más información, vea Instalación de un
módulo de PowerShell y about_PSModulePath.

4. Importe el módulo en PowerShell con una llamada a Import-Module.

Al llamar a Import-Module, el módulo se cargará en la memoria activa. Si usa


PowerShell 3.0 y versiones posteriores, llamar simplemente al nombre del módulo
en el código también lo importará. Para obtener más información, vea Importar un
módulo de PowerShell.

Importar ensamblados de complemento como


módulos
Los cmdlets y proveedores que existen en ensamblados de complemento se pueden
cargar como módulos binarios. Cuando los ensamblados de complemento se cargan
como módulos binarios, los cmdlets y proveedores del complemento están disponibles
para el usuario, pero la clase de complemento del ensamblado se omite y el
complemento no está registrado. Como resultado, los cmdlets de complemento
proporcionados por Windows PowerShell no pueden detectar el complemento aunque
los cmdlets y proveedores estén disponibles para la sesión.

Además, los archivos de formato o tipos a los que hace referencia el complemento no
se pueden importar como parte de un módulo binario. Para importar los archivos de
formato y tipos, debe crear un manifiesto de módulo. Vea How to Write a PowerShell
Module Manifest (Cómo escribir un manifiesto de módulo de PowerShell).

Consulte también
Escritura de un módulo de Windows PowerShell
Cómo escribir un manifiesto de módulo
de PowerShell
Artículo • 25/09/2021

Después de escribir el módulo de PowerShell, puede agregar un manifiesto de módulo


opcional que incluya información sobre el módulo. Por ejemplo, puede describir el
autor, especificar archivos en el módulo (por ejemplo, módulos anidados), ejecutar
scripts para personalizar el entorno del usuario, cargar archivos de tipo y formato,
definir requisitos del sistema y limitar los miembros que exporta el módulo.

Creación de un manifiesto de módulo


Un manifiesto de módulo es un archivo de datos de PowerShell ( ) que describe el
contenido de un módulo y determina cómo se procesa un .psd1 módulo. El archivo de
manifiesto es un archivo de texto que contiene una tabla hash de claves y valores. Para
vincular un archivo de manifiesto a un módulo, debe asignar al manifiesto el mismo
nombre que al módulo y almacenar el manifiesto en el directorio raíz del módulo.

Para los módulos simples que contienen solo un ensamblado .psm1 único o binario, un
manifiesto de módulo es opcional. Sin embargo, la recomendación es usar un
manifiesto de módulo siempre que sea posible, ya que son útiles para ayudarle a
organizar el código y mantener la información de control de versiones. Además, se
requiere un manifiesto de módulo para exportar un ensamblado instalado en la caché
global de ensamblados. También se requiere un manifiesto de módulo para los módulos
que admiten la característica Ayuda actualizable. La Ayuda actualizable usa la clave
HelpInfoUri del manifiesto del módulo para buscar el archivo de información de Ayuda
(HelpInfo XML) que contiene la ubicación de los archivos de ayuda actualizados para el
módulo. Para obtener más información sobre la Ayuda actualizable, vea Supporting
Updatable Help.

Para crear y usar un manifiesto de módulo


1. El procedimiento recomendado para crear un manifiesto de módulo es usar el
cmdlet New-ModuleManifest. Puede usar parámetros para especificar una o varias
de las claves y valores predeterminados del manifiesto. El único requisito es dar
nombre al archivo. New-ModuleManifest crea un manifiesto de módulo con los
valores especificados e incluye las claves restantes y sus valores predeterminados.
Si necesita crear varios módulos, use para crear una plantilla de New-
ModuleManifest manifiesto de módulo que se pueda modificar para los distintos

módulos. Para obtener un ejemplo de un manifiesto de módulo predeterminado,


consulte el manifiesto del módulo de ejemplo.

New-ModuleManifest -Path C:\myModuleName.psd1 -ModuleVersion "2.0" -Author


"YourNameHere"

Una alternativa es crear manualmente la tabla hash del manifiesto del módulo con
la información mínima necesaria, ModuleVersion. Guarde el archivo con el mismo
nombre que el módulo y use la .psd1 extensión de archivo. A continuación, puede
editar el archivo y agregar las claves y los valores adecuados.

2. Agregue los elementos adicionales que desee en el archivo de manifiesto.

Para editar el archivo de manifiesto, use el editor de texto que prefiera. Pero el
archivo de manifiesto es un archivo de script que contiene código, por lo que es
posible que desee editarlo en un entorno de scripting o desarrollo, como Visual
Studio Code. Todos los elementos de un archivo de manifiesto son opcionales,
excepto el número ModuleVersion.

Para obtener descripciones de las claves y los valores que puede incluir en un
manifiesto de módulo, vea la tabla Module manifest elements (Elementos del
manifiesto del módulo). Para obtener más información, vea las descripciones de
parámetros en el cmdlet New-ModuleManifest.

3. Para solucionar los escenarios que podrían no estar cubiertos por los elementos de
manifiesto del módulo base, tiene la opción de agregar código adicional al
manifiesto del módulo.

Por motivos de seguridad, PowerShell solo ejecuta un pequeño subconjunto de las


operaciones disponibles en un archivo de manifiesto de módulo. Por lo general,
puede usar la instrucción , los operadores aritméticos if y de comparación, y los
tipos de datos básicos de PowerShell.

4. Después de crear el manifiesto del módulo, puede probarlo para confirmar que las
rutas de acceso descritas en el manifiesto son correctas. Para probar el manifiesto
del módulo, use Test-ModuleManifest.

Test-ModuleManifest myModuleName.psd1

5. Asegúrese de que el manifiesto del módulo se encuentra en el nivel superior del


directorio que contiene el módulo.
Al copiar el módulo en un sistema e importarlo, PowerShell usa el manifiesto del
módulo para importar el módulo.

6. Opcionalmente, puede probar directamente el manifiesto del módulo con una


llamada a Import-Module mediante el dot-sourcing del propio manifiesto.

Import-Module .\myModuleName.psd1

Elementos de manifiesto de módulo


En la tabla siguiente se describen los elementos que puede incluir en un manifiesto de
módulo.

Elemento Valor Descripción


predeterminado

RootModule <empty string> Script de módulo o archivo de módulo


Tipo: String binario asociado a este manifiesto. Las
versiones anteriores de PowerShell
denominan a este elemento
ModuleToProcess.
Los tipos posibles para el módulo raíz
pueden estar vacíos, lo que crea un módulo
Manifiesto, el nombre de un módulo de
script ( ) o el nombre de .psm1 un módulo
binario ( o .exe .dll ). Al colocar el nombre
de un manifiesto de módulo ( .psd1 ) o un
archivo de script ( ) en este elemento se
produce un .ps1 error.
Ejemplo: RootModule = 'ScriptModule.psm1'

ModuleVersion '0.0.1' Número de versión de este módulo. Si no se


Tipo: Version especifica un valor, New-ModuleManifest usa
el valor predeterminado. La cadena debe ser
capaz de convertir al tipo Version , por
#.#.#.# ejemplo. Import-Module carga el
primer módulo que encuentra en el
$PSModulePath que coincide con el nombre
y tiene al menos una moduleVersion tan alta
como el parámetro MinimumVersion. Para
importar una versión específica, use el
Import-Module parámetro RequiredVersion
del cmdlet.
Ejemplo: ModuleVersion = '1.0'
Elemento Valor Descripción
predeterminado

GUID '<GUID>' Identificador que se usa para identificar de


Tipo: GUID forma única este módulo. Si no se especifica
un valor, New-ModuleManifest genera
automáticamente el valor. Actualmente no
se puede importar un módulo por GUID.
Ejemplo: GUID = 'cfc45206-1e49-459d-a8ad-
5b571ef94857'

Autor '<Current Autor de este módulo. Si no se especifica un


Tipo: String user>' valor, New-ModuleManifest usa el usuario
actual.
Ejemplo: Author = 'AuthorNameHere'

CompanyName 'Unknown' Empresa o proveedor de este módulo. Si no


Tipo: String se especifica un valor, New-ModuleManifest
usa el valor predeterminado.
Ejemplo: CompanyName = 'Fabrikam'

Copyright '(c) <Author>. Instrucción copyright de este módulo. Si no


Tipo: String All rights se especifica un valor, usa el valor New-
reserved.' ModuleManifest predeterminado con el
usuario actual como <Author> . Para
especificar un autor, use el parámetro
Author.
Ejemplo: Copyright = '2019 AuthorName. All
rights reserved.'

Descripción <empty string> Descripción de la funcionalidad


Tipo: String proporcionada por este módulo.
Ejemplo: Description = 'This is the
module's description.'

PowerShellVersion <empty string> Versión mínima del motor de PowerShell


Tipo: Version requerida por este módulo. Los valores
válidos son 1.0, 2.0, 3.0, 4.0, 5.0, 5.1, 6.0, 6.1,
6.2, 7.0 y 7.1.
Ejemplo: PowerShellVersion = '5.0'

PowerShellHostName <empty string> Nombre del host de PowerShell requerido


Tipo: String por este módulo. PowerShell proporciona
este nombre. Para buscar el nombre de un
programa host, en el programa, escriba:
$host.name .
Ejemplo: PowerShellHostName =
'ConsoleHost'
Elemento Valor Descripción
predeterminado

PowerShellHostVersion <empty string> Versión mínima del host de PowerShell


Tipo: Version requerida por este módulo.
Ejemplo: PowerShellHostVersion = '2.0'

DotNetFrameworkVersion <empty string> Versión mínima de Microsoft .NET


Tipo: Version Framework requiere este módulo. Este
requisito previo solo es válido para la
edición de PowerShell Desktop, como
PowerShell 5.1.
Ejemplo: DotNetFrameworkVersion = '3.5'

CLRVersion <empty string> Versión mínima de Common Language


Tipo: Version Runtime (CLR) requerida por este módulo.
Este requisito previo solo es válido para la
edición de PowerShell Desktop, como
PowerShell 5.1.
Ejemplo: CLRVersion = '3.5'

ProcessorArchitecture <empty string> Arquitectura del procesador (None, X86,


Tipo: ProcessorArchitecture Amd64) requerida por este módulo. Los
valores válidos son x86, AMD64, Arm, IA64,
MSIL y None (desconocido o no
especificado).
Ejemplo: ProcessorArchitecture = 'x86'
Elemento Valor Descripción
predeterminado

RequiredModules @() Módulos que deben importarse en el


Tipo: Object[] entorno global antes de importar este
módulo. Esto carga los módulos
enumerados a menos que ya se hayan
cargado. (por ejemplo, es posible que un
módulo diferente ya haya cargado algunos
módulos). Es posible especificar una versión
específica para cargar mediante
RequiredVersion en lugar de ModuleVersion
. Cuando ModuleVersion se usa, cargará la
versión más reciente disponible con un
mínimo de la versión especificada. Puede
combinar las cadenas y las tablas hash en el
valor del parámetro.
Ejemplo: RequiredModules = @("MyModule",
@{ModuleName="MyDependentModule";
ModuleVersion="2.0"; GUID="cfc45206-1e49-
459d-a8ad-5b571ef94857"})
Ejemplo: RequiredModules = @("MyModule",
@{ModuleName="MyDependentModule";
RequiredVersion="1.5"; GUID="cfc45206-
1e49-459d-a8ad-5b571ef94857"})

RequiredAssemblies @() Ensamblados que se deben cargar antes de


Tipo: String[] importar este módulo. Especifica los
nombres de archivo del ensamblado ( .dll )
que requiere el módulo.
PowerShell carga los ensamblados
especificados antes de actualizar tipos o
formatos, importar módulos anidados o
importar el archivo de módulo especificado
en el valor de la clave RootModule. Use este
parámetro para enumerar todos los
ensamblados que requiere el módulo.
Ejemplo: RequiredAssemblies =
@("assembly1.dll", "assembly2.dll",
"assembly3.dll")
Elemento Valor Descripción
predeterminado

ScriptsToProcess @() Archivos de script ( ) que se ejecutan en el


Tipo: String[] estado de sesión del autor de la .ps1
llamada cuando se importa el módulo.
Podría ser el estado de sesión global o, para
los módulos anidados, el estado de sesión
de otro módulo. Puede usar estos scripts
para preparar un entorno tal como podría
usar un script de inicio de sesión.
Estos scripts se ejecutan antes de que se
cargue cualquiera de los módulos
enumerados en el manifiesto.
Ejemplo: ScriptsToProcess =
@("script1.ps1", "script2.ps1",
"script3.ps1")

TypesToProcess @() Escriba los archivos ( .ps1xml ) que se


Tipo: String[] cargarán al importar este módulo.
Ejemplo: TypesToProcess =
@("type1.ps1xml", "type2.ps1xml",
"type3.ps1xml")

FormatsToProcess @() Dar formato a los archivos ( .ps1xml ) que se


Tipo: String[] cargarán al importar este módulo.
Ejemplo: FormatsToProcess =
@("format1.ps1xml", "format2.ps1xml",
"format3.ps1xml")

NestedModules @() Módulos que se importarán como módulos


Tipo: Object[] anidados del módulo especificado en
RootModule (alias:ModuleToProcess).
Agregar un nombre de módulo a este
elemento es similar a llamar Import-Module
desde el código de script o ensamblado. La
principal diferencia al usar un archivo de
manifiesto es que es más fácil ver lo que se
carga. Y, si no se puede cargar un módulo,
aún no habrá cargado el módulo real.
Además de otros módulos, también puede
cargar archivos de script ( .ps1 ) aquí. Estos
archivos se ejecutarán en el contexto del
módulo raíz. Esto equivale a dot sourcing
del script en el módulo raíz.
Ejemplo: NestedModules = @("script.ps1",
@{ModuleName="MyModule";
ModuleVersion="1.0.0.0"; GUID="50cdb55f-
5ab7-489f-9e94-4ec21ff51e59"})
Elemento Valor Descripción
predeterminado

FunctionsToExport @() Especifica las funciones que se van a


Tipo: String[] exportar desde este módulo, para obtener el
mejor rendimiento, no usar caracteres
comodín y no eliminar la entrada, usar una
matriz vacía si no hay ninguna función para
exportar. De forma predeterminada, no se
exporta ninguna función. Puede usar esta
clave para enumerar las funciones
exportadas por el módulo.
El módulo exporta las funciones al estado de
sesión del autor de la llamada. El estado de
sesión del autor de la llamada puede ser el
estado de sesión global o, para los módulos
anidados, el estado de sesión de otro
módulo. Al encadenar módulos anidados,
todas las funciones exportadas por un
módulo anidado se exportarán al estado de
sesión global a menos que un módulo de la
cadena restrinja la función mediante la clave
FunctionsToExport.
Si el manifiesto exporta alias para las
funciones, esta clave puede quitar funciones
cuyos alias se enumeran en la clave
AliasesToExport, pero esta clave no puede
agregar alias de función a la lista.
Ejemplo: FunctionsToExport =
@("function1", "function2", "function3")
Elemento Valor Descripción
predeterminado

CmdletsToExport @() Especifica los cmdlets que se van a exportar


Tipo: String[] desde este módulo, para obtener el mejor
rendimiento, no usar caracteres comodín y
no eliminar la entrada, usar una matriz vacía
si no hay cmdlets para exportar. De forma
predeterminada, no se exporta ningún
cmdlet. Puede usar esta clave para enumerar
los cmdlets exportados por el módulo.
El estado de sesión del autor de la llamada
puede ser el estado de sesión global o, para
los módulos anidados, el estado de sesión
de otro módulo. Al encadenar módulos
anidados, todos los cmdlets exportados por
un módulo anidado se exportarán al estado
de sesión global a menos que un módulo de
la cadena restrinja el cmdlet mediante la
clave CmdletsToExport.
Si el manifiesto exporta alias para los
cmdlets, esta clave puede quitar cmdlets
cuyos alias se enumeran en la clave
AliasesToExport, pero esta clave no puede
agregar alias de cmdlet a la lista.
Ejemplo: CmdletsToExport = @("Get-
MyCmdlet", "Set-MyCmdlet", "Test-
MyCmdlet")
Elemento Valor Descripción
predeterminado

VariablesToExport '*' Especifica las variables que exporta el


Tipo: String[] módulo al estado de sesión del autor de la
llamada. Se permite el uso de caracteres
comodín. De forma predeterminada, se
exportan todas las variables ( '*' ). Puede
usar esta clave para restringir las variables
exportadas por el módulo.
El estado de sesión del autor de la llamada
puede ser el estado de sesión global o, para
los módulos anidados, el estado de sesión
de otro módulo. Al encadenar módulos
anidados, todas las variables exportadas por
un módulo anidado se exportarán al estado
de sesión global a menos que un módulo de
la cadena restrinja la variable mediante la
clave VariablesToExport.
Si el manifiesto también exporta alias para
las variables, esta clave puede quitar
variables cuyos alias se enumeran en la clave
AliasesToExport, pero esta clave no puede
agregar alias de variable a la lista.
Ejemplo: VariablesToExport =
@('$MyVariable1', '$MyVariable2',
'$MyVariable3')
Elemento Valor Descripción
predeterminado

AliasesToExport @() Especifica los alias que se van a exportar


Tipo: String[] desde este módulo, para obtener el mejor
rendimiento, no usar caracteres comodín y
no eliminar la entrada, usar una matriz vacía
si no hay ningún alias para exportar. De
forma predeterminada, no se exporta
ningún alias. Puede usar esta clave para
enumerar los alias exportados por el
módulo.
El módulo exporta los alias al estado de
sesión del autor de la llamada. El estado de
sesión del autor de la llamada puede ser el
estado de sesión global o, para los módulos
anidados, el estado de sesión de otro
módulo. Al encadenar módulos anidados,
todos los alias exportados por un módulo
anidado se exportarán en última instancia al
estado de sesión global a menos que un
módulo de la cadena restrinja el alias
mediante la clave AliasesToExport.
Ejemplo: AliasesToExport = @("MyAlias1",
"MyAlias2", "MyAlias3")

DscResourcesToExport @() Especifica los recursos de DSC que se


Tipo: String[] exportarán desde este módulo. Se permiten
los caracteres comodín.
Ejemplo: DscResourcesToExport =
@("DscResource1", "DscResource2",
"DscResource3")

ModuleList @() Especifica todos los módulos que se


Tipo: Object[] empaquetan con este módulo. Estos
módulos se pueden especificar por nombre,
mediante una cadena separada por comas o
como una tabla hash con claves
ModuleName y GUID. La tabla hash
también puede tener una clave
ModuleVersion opcional. La clave
ModuleList está diseñada para actuar como
un inventario de módulos. Estos módulos no
se procesan automáticamente.
Ejemplo: ModuleList = @("SampleModule",
"MyModule", @{ModuleName="MyModule";
ModuleVersion="1.0.0.0"; GUID="50cdb55f-
5ab7-489f-9e94-4ec21ff51e59"})
Elemento Valor Descripción
predeterminado

Lista de archivos @() Lista de todos los archivos empaquetados


Tipo: String[] con este módulo. Al igual que con
ModuleList, FileList es una lista de
inventario y, de lo contrario, no se procesa.
Ejemplo: FileList = @("File1", "File2",
"File3")

PrivateData @{...} Especifica los datos privados que deben


Tipo: Object pasarse al módulo raíz especificado por la
clave RootModule (alias: ModuleToProcess).
PrivateData es una tabla hash que consta de
varios elementos: Tags, LicenseUri,
ProjectURI, IconUri, ReleaseNotes,
Prerelease, RequireLicenseAcceptance y
ExternalModuleDependencies.

Etiquetas @() Las etiquetas ayudan con la detección de


Tipo: String[] módulos en galerías en línea.
Ejemplo: Tags = "PackageManagement",
"PowerShell", "Manifest"

LicenseUri <empty string> Dirección URL de la licencia de este módulo.


Tipo: Uri Ejemplo: LicenseUri =
'https://www.contoso.com/license'

ProjectUri <empty string> Dirección URL del sitio web principal de este
Tipo: Uri proyecto.
Ejemplo: ProjectUri =
'https://www.contoso.com/project'

IconUri <empty string> Dirección URL a un icono que representa


Tipo: Uri este módulo.
Ejemplo: IconUri =
'https://www.contoso.com/icons/icon.png'

Notas de la versión <empty string> Especifica las notas de la versión del


Tipo: String módulo.
Ejemplo: ReleaseNotes = 'The release notes
provide information about the module.

Prelanzamiento <empty string> Este parámetro se agregó en PowerShellGet


Tipo: String 1.6.6. Cadena de versión preliminar que
identifica el módulo como una versión
preliminar en galerías en línea.
Ejemplo: PreRelease = 'This module is a
prerelease version.
Elemento Valor Descripción
predeterminado

RequireLicenseAcceptance $true Este parámetro se agregó en PowerShellGet


Tipo: Boolean 1.5. Marca para indicar si el módulo requiere
la aceptación explícita del usuario para la
instalación, actualización o guardado.
Ejemplo: RequireLicenseAcceptance = $false

ExternalModuleDependencies @() Este parámetro se agregó en PowerShellGet


Tipo: String[] v2. Lista de módulos externos de los que
depende este módulo.
Ejemplo: ExternalModuleDependencies =
@("ExtModule1", "ExtModule2",
"ExtModule3")

HelpInfoURI <empty string> URI de HelpInfo de este módulo.


Tipo: String Ejemplo: HelpInfoURI =
'https://www.contoso.com/help'

DefaultCommandPrefix <empty string> Prefijo predeterminado para los comandos


Tipo: String exportados desde este módulo. Invalide el
prefijo predeterminado mediante Import-
Module -Prefix .
Ejemplo: DefaultCommandPrefix = 'My'

Manifiesto de módulo de ejemplo


El siguiente manifiesto de módulo de ejemplo se New-ModuleManifest creó con en
PowerShell 7 y contiene las claves y los valores predeterminados.

PowerShell

#
# Module manifest for module 'SampleModuleManifest'
#
# Generated by: User01
#
# Generated on: 10/15/2019
#

@{

# Script module or binary module file associated with this manifest.


# RootModule = ''

# Version number of this module.


ModuleVersion = '0.0.1'
# Supported PSEditions
# CompatiblePSEditions = @()

# ID used to uniquely identify this module


GUID = 'b632e90c-df3d-4340-9f6c-3b832646bf87'

# Author of this module


Author = 'User01'

# Company or vendor of this module


CompanyName = 'Unknown'

# Copyright statement for this module


Copyright = '(c) User01. All rights reserved.'

# Description of the functionality provided by this module


# Description = ''

# Minimum version of the PowerShell engine required by this module


# PowerShellVersion = ''

# Name of the PowerShell host required by this module


# PowerShellHostName = ''

# Minimum version of the PowerShell host required by this module


# PowerShellHostVersion = ''

# Minimum version of Microsoft .NET Framework required by this module. This


prerequisite is valid for the PowerShell Desktop edition only.
# DotNetFrameworkVersion = ''

# Minimum version of the common language runtime (CLR) required by this


module. This prerequisite is valid for the PowerShell Desktop edition only.
# CLRVersion = ''

# Processor architecture (None, X86, Amd64) required by this module


# ProcessorArchitecture = ''

# Modules that must be imported into the global environment prior to


importing this module
# RequiredModules = @()

# Assemblies that must be loaded prior to importing this module


# RequiredAssemblies = @()

# Script files (.ps1) that are run in the caller's environment prior to
importing this module.
# ScriptsToProcess = @()

# Type files (.ps1xml) to be loaded when importing this module


# TypesToProcess = @()

# Format files (.ps1xml) to be loaded when importing this module


# FormatsToProcess = @()
# Modules to import as nested modules of the module specified in
RootModule/ModuleToProcess
# NestedModules = @()

# Functions to export from this module, for best performance, do not use
wildcards and do not delete the entry, use an empty array if there are no
functions to export.
FunctionsToExport = @()

# Cmdlets to export from this module, for best performance, do not use
wildcards and do not delete the entry, use an empty array if there are no
cmdlets to export.
CmdletsToExport = @()

# Variables to export from this module


VariablesToExport = '*'

# Aliases to export from this module, for best performance, do not use
wildcards and do not delete the entry, use an empty array if there are no
aliases to export.
AliasesToExport = @()

# DSC resources to export from this module


# DscResourcesToExport = @()

# List of all modules packaged with this module


# ModuleList = @()

# List of all files packaged with this module


# FileList = @()

# Private data to pass to the module specified in


RootModule/ModuleToProcess. This may also contain a PSData hashtable with
additional module metadata used by PowerShell.
PrivateData = @{

PSData = @{

# Tags applied to this module. These help with module discovery in


online galleries.
# Tags = @()

# A URL to the license for this module.


# LicenseUri = ''

# A URL to the main website for this project.


# ProjectUri = ''

# A URL to an icon representing this module.


# IconUri = ''

# ReleaseNotes of this module


# ReleaseNotes = ''

# Prerelease string of this module


# Prerelease = ''

# Flag to indicate whether the module requires explicit user


acceptance for install/update/save
RequireLicenseAcceptance = $true

# External dependent modules of this module


# ExternalModuleDependencies = @()

} # End of PSData hashtable

} # End of PrivateData hashtable

# HelpInfo URI of this module


# HelpInfoURI = ''

# Default prefix for commands exported from this module. Override the
default prefix using Import-Module -Prefix.
# DefaultCommandPrefix = ''

Consulte también
about_Comparison_Operators

about_If

Caché global de ensamblados

Import-Module

New-ModuleManifest

Test-ModuleManifest

Update-ModuleManifest

Escritura de un módulo de Windows PowerShell


Instalación de un módulo de PowerShell
Artículo • 25/09/2021

Una vez creado el módulo de PowerShell, es probable que desee instalarlo en un


sistema, de modo que usted u otras personas puedan usarlo. Por lo general, esto
consiste en copiar los archivos del módulo (por ejemplo, psm1, el ensamblado binario,
el manifiesto del módulo y cualquier otro archivo asociado) en un directorio de ese
equipo. Para un proyecto muy pequeño, esto puede ser tan sencillo como copiar y
pegar los archivos con el Explorador de Windows en un único equipo remoto. Sin
embargo, en el caso de soluciones de mayor tamaño, es posible que desee usar un
proceso de instalación más sofisticado. Independientemente de cómo obtenga el
módulo en el sistema, PowerShell puede usar diferentes técnicas que permitirán a los
usuarios buscar y usar los módulos. Por lo tanto, el problema principal de la instalación
es asegurarse de que PowerShell pueda encontrar el módulo. Para obtener más
información, consulte Importación de un módulo de PowerShell.

Reglas para instalar módulos


La siguiente información pertenece a todos los módulos, incluidos aquellos que crea
para su propio uso, los módulos que obtiene de otras partes y los módulos que
distribuye a otros usuarios.

Instalación de módulos en PSModulePath


Siempre que sea posible, instale todos los módulos en una ruta de acceso que aparece
en la variable de entorno PSModulePath o agregue la ruta de acceso del módulo al
valor de la variable de entorno PSModulePath.

La variable de entorno PSModulePath ( ) contiene las ubicaciones de Windows


PowerShell $Env:PSModulePath módulos. Los cmdlets se basan en el valor de esta
variable de entorno para buscar módulos.

De forma predeterminada, el valor de la variable de entorno PSModulePath contiene los


siguientes directorios del módulo del sistema y del usuario, pero puede realizar más
incorporaciones al valor y editarlo.

$PSHome\Modules ( %Windir%\System32\WindowsPowerShell\v1.0\Modules )

2 Advertencia
Esta ubicación está reservada para los módulos que se distribuyen con
Windows. No instale módulos en esta ubicación.

$Home\Documents\WindowsPowerShell\Modules

( %UserProfile%\Documents\WindowsPowerShell\Modules )

$Env:ProgramFiles\WindowsPowerShell\Modules

( %ProgramFiles%\WindowsPowerShell\Modules )

Para obtener el valor de la variable de entorno PSModulePath, use cualquiera de


los siguientes comandos.

PowerShell

$Env:PSModulePath
[Environment]::GetEnvironmentVariable("PSModulePath")

Para agregar una ruta de acceso de módulo al valor de la variable de entorno


PSModulePath, utilice el siguiente formato de comando. Este formato utiliza el
método SetEnvironmentVariable de la clase System.Environment para hacer un
cambio independiente de la sesión en la variable de entorno PSModulePath.

PowerShell

#Save the current value in the $p variable.


$p = [Environment]::GetEnvironmentVariable("PSModulePath")

#Add the new path to the $p variable. Begin with a semi-colon


separator.
$p += ";C:\Program Files (x86)\MyCompany\Modules\"

#Add the paths in $p to the PSModulePath value.


[Environment]::SetEnvironmentVariable("PSModulePath",$p)

) Importante

Una vez que haya agregado la ruta de acceso a PSModulePath, debe difundir
un mensaje de entorno sobre el cambio. Difundir el cambio permite a otras
aplicaciones, como el Shell, recogerlo. Para difundir el cambio, haga que el
código de instalación del producto envíe un mensaje WM_SETTINGCHANGE
con lParam establecido en la cadena "Environment". Asegúrese de enviar el
mensaje una vez actualizado el código de instalación del módulo
PSModulePath.
Uso del nombre de directorio del módulo correcto
Un módulo bien formado es un módulo que se almacena en un directorio que tiene el
mismo nombre que el nombre base de al menos un archivo en el directorio del módulo.
Si un módulo no está bien formado, Windows PowerShell no lo reconoce como un
módulo.

El "nombre base" de un archivo es el nombre sin la extensión del nombre de archivo. En


un módulo bien formado, el nombre del directorio que contiene los archivos del
módulo debe coincidir con el nombre base de al menos un archivo del módulo.

Por ejemplo, en el módulo Fabrikam de ejemplo, el directorio que contiene los archivos
del módulo se denomina "Fabrikam" y al menos un archivo tiene el nombre base
"Fabrikam". En este caso, tanto Fabrikam.psd1 como Fabrikam.dll tienen el nombre base
"Fabrikam".

C:\Program Files
Fabrikam Technologies
Fabrikam Manager
Modules
Fabrikam
Fabrikam.psd1 (module manifest)
Fabrikam.dll (module assembly)

Efecto de una instalación incorrecta


Si el módulo no está bien formado y su ubicación no se incluye en el valor de la variable
de entorno PSModulePath, las características de detección básicas de Windows
PowerShell, como la siguiente, no funcionan.

La característica de carga automática del módulo no puede importar el módulo


automáticamente.

El parámetro ListAvailable del cmdlet Get-Module no puede encontrar el


módulo.

El cmdlet Import-Module no puede encontrar el módulo. Para importar el módulo,


debe proporcionar la ruta de acceso completa al archivo del módulo raíz o al
archivo de manifiesto del módulo.

Otras características, como las siguientes, no funcionan a menos que el módulo se


importe en la sesión. En los módulos bien formados de la variable de entorno
PSModulePath, estas características funcionan incluso cuando el módulo no se
importa en la sesión.

El cmdlet Get-Command no puede encontrar comandos en el módulo.

Los cmdlets Update-Help y Save-Help no pueden actualizar ni guardar la ayuda del


módulo.

El cmdlet Show-Command no puede encontrar ni mostrar los comandos del


módulo.

Faltan los comandos del módulo en la ventana Show-Command del entorno de


scripting integrado (ISE) de Windows PowerShell.

Ubicación de instalación de los módulos


En esta sección se explica en qué lugar del sistema de archivos se instalan los módulos
de Windows PowerShell. La ubicación depende de cómo se use el módulo.

Instalación de módulos para un usuario específico


Si crea su propio módulo u obtiene un módulo de otra parte, como un sitio web de la
comunidad de Windows PowerShell, y desea que dicho módulo esté disponible solo
para su cuenta de usuario, instálelo en el directorio de módulos específico del usuario.

$home\Documents\WindowsPowerShell\Modules\<Module Folder>\<Module Files>

De forma predeterminada, el directorio de módulos específico del usuario se agrega al


valor de la variable de entorno PSModulePath.

Instalación de módulos para todos los usuarios en


Archivos de programa
Si desea que un módulo esté disponible para todas las cuentas de usuario del equipo,
instálelo en la ubicación Archivos de programa.

$Env:ProgramFiles\WindowsPowerShell\Modules\<Module Folder>\<Module Files>

7 Nota

La ubicación Archivos de programa se agrega al valor de la variable de entorno


PSModulePath de forma predeterminada en Windows PowerShell 4.0 y versiones
posteriores. En el caso de las versiones anteriores de Windows PowerShell, puede
crear manualmente la ubicación Archivos de programa
(%ProgramFiles%\WindowsPowerShell\Modules) y agregar esta ruta de acceso a la
variable de entorno de PSModulePath tal y como se ha descrito anteriormente.

Instalación de módulos en un directorio de producto


Si va a distribuir el módulo a otras partes, use la ubicación predeterminada Archivos de
programa descrita anteriormente, o bien cree su propio subdirectorio específico de la
empresa o específico del producto del directorio %ProgramFiles%.

Por ejemplo, Fabrikam Technologies, una empresa ficticia, envía un módulo de Windows
PowerShell para su producto Fabrikam Manager. Su instalador de módulos crea un
subdirectorio Modules en el subdirectorio del producto Fabrikam Manager.

C:\Program Files
Fabrikam Technologies
Fabrikam Manager
Modules
Fabrikam
Fabrikam.psd1 (module manifest)
Fabrikam.dll (module assembly)

Para habilitar las características de detección de módulos de Windows PowerShell para


encontrar el módulo Fabrikam, el instalador del módulo Fabrikam agrega la ubicación
del módulo al valor de la variable de entorno PSModulePath.

PowerShell

$p = [Environment]::GetEnvironmentVariable("PSModulePath")
$p += ";C:\Program Files\Fabrikam Technologies\Fabrikam Manager\Modules\"
[Environment]::SetEnvironmentVariable("PSModulePath",$p)

Instalación de módulos en el directorio Common Files


Si un módulo se usa en varios componentes de un producto o en varias versiones de un
producto, instale el módulo en un subdirectorio específico del módulo del subdirectorio
%ProgramFiles%\Common Files\Modules.

En el ejemplo siguiente, el módulo Fabrikam se instala en un subdirectorio Fabrikam del


subdirectorio %ProgramFiles%\Common Files\Modules . Tenga en cuenta que cada módulo
reside en su propio subdirectorio en el subdirectorio Modules.

C:\Program Files
Common Files
Modules
Fabrikam
Fabrikam.psd1 (module manifest)
Fabrikam.dll (module assembly)

A continuación, el instalador se asegura de que el valor de la variable de entorno


PSModulePath incluye la ruta de acceso del subdirectorio Modules de Common Files.

PowerShell

$m = $env:ProgramFiles + '\Common Files\Modules'


$p = [Environment]::GetEnvironmentVariable("PSModulePath")
$q = $p -split ';'
if ($q -notContains $m) {
$q += ";$m"
}
$p = $q -join ';'
[Environment]::SetEnvironmentVariable("PSModulePath", $p)

Instalar varias versiones de un módulo


Para instalar varias versiones del mismo módulo, use el procedimiento siguiente.

1. Cree un directorio para cada versión del módulo. Incluya el número de versión en
el nombre del directorio.
2. Cree un manifiesto de módulo para cada versión del módulo. En el valor de la
clave ModuleVersion del manifiesto, escriba el número de versión del módulo.
Guarde el archivo de manifiesto (.psd1) en el directorio específico de la versión del
módulo.
3. Agregue la ruta de acceso de la carpeta raíz del módulo al valor de la variable de
entorno PSModulePath, tal y como se muestra en los ejemplos siguientes.

Para importar una versión determinada del módulo, el usuario final puede usar los
parámetros MinimumVersion o RequiredVersion del cmdlet Import-Module.

Por ejemplo, si el módulo Fabrikam está disponible en las versiones 8.0 y 9.0, la
estructura de directorios del módulo Fabrikam podría ser similar a la siguiente.
C:\Program Files
Fabrikam Manager
Fabrikam8
Fabrikam
Fabrikam.psd1 (module manifest: ModuleVersion = "8.0")
Fabrikam.dll (module assembly)
Fabrikam9
Fabrikam
Fabrikam.psd1 (module manifest: ModuleVersion = "9.0")
Fabrikam.dll (module assembly)

El instalador agrega las dos rutas de acceso del módulo al valor de la variable de
entorno PSModulePath.

PowerShell

$p = [Environment]::GetEnvironmentVariable("PSModulePath")
$p += ";C:\Program Files\Fabrikam\Fabrikam8;C:\Program
Files\Fabrikam\Fabrikam9"
[Environment]::SetEnvironmentVariable("PSModulePath",$p)

Una vez completados estos pasos, el parámetro ListAvailable del cmdlet Get-Module
obtiene ambos módulos Fabrikam. Para importar un módulo determinado, use los
parámetros MinimumVersion o RequiredVersion del cmdlet Import-Module.

Si ambos módulos se importan en la misma sesión y los módulos contienen cmdlets con
los mismos nombres, los cmdlets que se importan en último lugar entran en vigor en la
sesión.

Control de conflictos con los nombres de


comando
Pueden producirse conflictos con los nombres de comando cuando los comandos que
exporta un módulo tienen el mismo nombre que los comandos de la sesión del usuario.

Cuando una sesión contiene dos comandos que tienen el mismo nombre, Windows
PowerShell ejecuta el tipo de comando que tiene prioridad. Cuando una sesión contiene
dos comandos que tienen el mismo nombre y el mismo tipo, Windows PowerShell
ejecuta el comando que se agregó a la sesión más recientemente. Para ejecutar un
comando que no se ejecuta de forma predeterminada, los usuarios pueden completar el
nombre del comando con el nombre del módulo.

Por ejemplo, si la sesión contiene una función Get-Date y el cmdlet Get-Date , Windows
PowerShell ejecuta la función de forma predeterminada. Para ejecutar el cmdlet,
anteponga el nombre del módulo al comando, como por ejemplo:

PowerShell

Microsoft.PowerShell.Utility\Get-Date

Para evitar conflictos de nombres, los autores de módulos pueden usar la clave
DefaultCommandPrefix en el manifiesto del módulo para especificar un prefijo de
nombre para todos los comandos exportados desde el módulo.

Los usuarios pueden usar el parámetro Prefix del cmdlet Import-Module para usar un
prefijo alternativo. El valor del parámetro Prefix tiene prioridad sobre el valor de la clave
DefaultCommandPrefix.

Compatibilidad de rutas de acceso en sistemas


que no Windows acceso
Las plataformas Windows usan el carácter de dos puntos ( ) como separador de ruta de
acceso y un carácter de barra diagonal : / () como separador de directorio. La
[System.IO.Path] clase tiene miembros estáticos que se pueden usar para que el

código funcione en cualquier plataforma:

[System.IO.Path]::PathSeparator : devuelve el carácter utilizado para separar las

rutas de acceso en una variable de entorno PATH para la plataforma host.


[System.IO.Path]::DirectorySeparatorChar : devuelve el carácter utilizado para
separar los nombres de directorio con una ruta de acceso para la plataforma host.

Use estas propiedades estáticas en en lugar de los caracteres ; \ y al construir cadenas


de ruta de acceso.

Consulte también
about_Command_Precedence

Escritura de un módulo de Windows PowerShell


Registro de cmdlets
Artículo • 25/09/2021

En los temas de esta sección se describen los módulos y complementos, y cómo usar
módulos y complementos para que los cmdlets estén disponibles en una Windows
PowerShell sesión.

En esta sección
Módulos y complementos Describe las diferencias entre el registro de cmdlets a través
de módulos y mediante complementos.

Cómo registrar cmdlets mediante módulos Describe cómo registrar cmdlets mediante
módulos.

Cómo crear un complemento Windows PowerShell de datos Describe cómo registrar


cmdlets mediante complementos.

Vea también
Escribir un cmdlet de Windows PowerShell
Módulos y complementos
Artículo • 25/09/2021

Los cmdlets se pueden agregar a una sesión mediante módulos (introducidos por
Windows PowerShell 2.0) o complementos. Una vez que el cmdlet se agrega a la sesión,
una aplicación host puede ejecutarlo mediante programación o de forma interactiva en
la línea de comandos.

Se recomienda usar módulos como método de entrega para agregar cmdlets a una
sesión por los siguientes motivos:

Los módulos permiten agregar cmdlets cargando el ensamblado donde se define


el cmdlet. No es necesario implementar una clase de complemento.

Los módulos permiten agregar otros recursos, como variables, funciones, scripts,
tipos y archivos de formato, etc.

Los complementos solo se pueden usar para agregar cmdlets y proveedores a la


sesión.

Consulte también
Escritura de un módulo de Windows PowerShell

Escribir un cmdlet de Windows PowerShell


Cómo importar cmdlets mediante
módulos
Artículo • 25/09/2021

En este artículo se describe cómo importar cmdlets a una sesión de PowerShell


mediante un módulo binario.

7 Nota

Los miembros de los módulos pueden incluir cmdlets, proveedores, funciones,


variables, alias y mucho más. Los complementos solo pueden contener cmdlets y
proveedores.

Carga de cmdlets mediante un módulo


1. Cree una carpeta de módulo que tenga el mismo nombre que el archivo de
ensamblado en el que se implementan los cmdlets. En este procedimiento, la
carpeta del módulo se crea en Windows system32 carpeta.

%SystemRoot%\system32\WindowsPowerShell\v1.0\Modules\mymodule

2. Asegúrese de que la PSModulePath variable de entorno incluye la ruta de acceso a


la nueva carpeta del módulo. De forma predeterminada, la carpeta del sistema ya
se ha agregado a la PSModulePath variable de entorno. Para ver PSModulePath ,
escriba: $env:PSModulePath .

3. Copie el ensamblado del cmdlet en la carpeta del módulo.

4. Agregue un archivo de manifiesto de módulo ( .psd1 ) en la carpeta raíz del


módulo. PowerShell usa el manifiesto del módulo para importar el módulo. Para
obtener más información, vea How to Write a PowerShell Module Manifest.

5. Ejecute el siguiente comando para agregar los cmdlets a la sesión:

Import-Module [Module_Name]

Este procedimiento se puede usar para probar los cmdlets. Agrega todos los
cmdlets del ensamblado a la sesión. Para obtener más información sobre los
módulos, vea Escribir un Windows PowerShell módulo.
Consulte también
Cómo escribir un manifiesto de módulo de PowerShell

Importación de un módulo de PowerShell

Import-Module

Instalación de módulos

acerca de_about_PSModulePath

Escribir un cmdlet de Windows PowerShell


Cómo crear un complemento de
Windows PowerShell
Artículo • 24/09/2021

Un Windows PowerShell complemento proporciona un mecanismo para registrar


conjuntos de cmdlets y otro proveedor de Windows PowerShell con el shell, lo que
amplía la funcionalidad del shell. Un Windows PowerShell complemento puede registrar
todos los cmdlets y proveedores en un único ensamblado, o puede registrar una lista
específica de cmdlets y proveedores.

Los ensamblados de complemento deben instalarse en un directorio protegido, tal


como lo harían con otros sistemas operativos. De lo contrario, los usuarios
malintencionados pueden reemplazar un ensamblado por código no seguro.

Windows PowerShell Clases de complemento


Todas Windows PowerShell complemento derivan de las clases
System.Management.Automation.PSSnapIn o
System.Management.Automation.Custompssnapin.

Ejemplos
Escribir un Windows PowerShell complemento:en este ejemplo se muestra cómo crear
un complemento que se usa para registrar todos los cmdlets y proveedores en un
ensamblado.

Escribir uncomplemento Windows PowerShell personalizado: en este ejemplo se


muestra cómo crear un complemento personalizado que se usa para registrar un
conjunto específico de cmdlets y proveedores que podrían existir o no en un único
ensamblado.

Consulte también
System.Management.Automation.PSSnapIn

System.Management.Automation.Custompssnapin

Registro de cmdlets

SDK del shell de Windows PowerShell


Escritura de un complemento de
Windows PowerShell
Artículo • 25/09/2021

En este ejemplo se muestra cómo escribir un complemento Windows PowerShell que se


puede usar para registrar todos los cmdlets y proveedores de Windows PowerShell en
un ensamblado.

Con este tipo de complemento, no se seleccionan los cmdlets y proveedores que desea
registrar. Para escribir un complemento que le permita seleccionar lo que está
registrado, vea Escribir un complemento Windows PowerShell personalizado.

Escritura de un complemento de Windows PowerShell


1. Agregue el atributo RunInstallerAttribute.

2. Cree una clase pública que derive de la clase


System.Management.Automation.PSSnapIn.

En este ejemplo, el nombre de clase es "GetProcPSSnapIn01".

3. Agregue una propiedad pública para el nombre del complemento (obligatorio). Al


asignar nombres a complementos, no use ninguno de los caracteres siguientes: # ,
,,, . , ( ) { } [ ,,, ] ,,, & , - / \ $ ; , : " ' < > | ? @ ` , *

En este ejemplo, el nombre del complemento es "GetProcPSSnapIn01".

4. Agregue una propiedad pública para el proveedor del complemento (obligatorio).

En este ejemplo, el proveedor es "Microsoft".

5. Agregue una propiedad pública para el recurso de proveedor del complemento


(opcional).

En este ejemplo, el recurso del proveedor es "GetProcPSSnapIn01,Microsoft".

6. Agregue una propiedad pública para la descripción del complemento (obligatorio).

En este ejemplo, la descripción es "This is a Windows PowerShell snap-in that


registers the get-proc cmdlet".

7. Agregue una propiedad pública para el recurso de descripción del complemento


(opcional).
En este ejemplo, el recurso del proveedor es "GetProcPSSnapIn01, se trata de un
complemento Windows PowerShell que registra el cmdlet get-proc".

Ejemplo
En este ejemplo se muestra cómo escribir Windows PowerShell complemento que se
puede usar para registrar el cmdlet Get-Proc en el shell de Windows PowerShell. Tenga
en cuenta que en este ejemplo, el ensamblado completo solo contendrá la clase de
complemento GetProcPSSnapIn01 y la Get-Proc clase de cmdlet.

C#

[RunInstaller(true)]
public class GetProcPSSnapIn01 : PSSnapIn
{
/// <summary>
/// Create an instance of the GetProcPSSnapIn01 class.
/// </summary>
public GetProcPSSnapIn01()
: base()
{
}

/// <summary>
/// Specify the name of the PowerShell snap-in.
/// </summary>
public override string Name
{
get
{
return "GetProcPSSnapIn01";
}
}

/// <summary>
/// Specify the vendor for the PowerShell snap-in.
/// </summary>
public override string Vendor
{
get
{
return "Microsoft";
}
}

/// <summary>
/// Specify the localization resource information for the vendor.
/// Use the format: resourceBaseName,VendorName.
/// </summary>
public override string VendorResource
{
get
{
return "GetProcPSSnapIn01,Microsoft";
}
}

/// <summary>
/// Specify a description of the PowerShell snap-in.
/// </summary>
public override string Description
{
get
{
return "This is a PowerShell snap-in that includes the get-proc
cmdlet.";
}
}

/// <summary>
/// Specify the localization resource information for the description.
/// Use the format: resourceBaseName,Description.
/// </summary>
public override string DescriptionResource
{
get
{
return "GetProcPSSnapIn01,This is a PowerShell snap-in that includes
the get-proc cmdlet.";
}
}
}

Consulte también
Cómo registrar cmdlets, proveedores y aplicaciones host

SDK del shell de Windows PowerShell


Escritura de un complemento de
Windows PowerShell personalizado
Artículo • 25/09/2021

En este ejemplo se muestra cómo escribir Windows PowerShell complemento que


registra cmdlets específicos.

Con este tipo de complemento, se especifican los cmdlets, proveedores, tipos o


formatos que se registrarán. Para obtener más información sobre cómo escribir un
complemento que registre todos los cmdlets y proveedores en un ensamblado, vea
Escribir un Windows PowerShell complemento.

Para escribir un Windows PowerShell


complemento que registra cmdlets específicos.
1. Agregue el atributo RunInstallerAttribute.

2. Cree una clase pública que derive de la clase


System.Management.Automation.Custompssnapin.

En este ejemplo, el nombre de clase es "CustomPSSnapinTest".

3. Agregue una propiedad pública para el nombre del complemento (obligatorio). Al


asignar nombres a complementos, no use ninguno de los caracteres siguientes: # ,
,,, . , ( ) { } [ ,,, ] ,,, & , - / \ $ ; , : " ' < > | ? @ ` , *

En este ejemplo, el nombre del complemento es "CustomPSSnapInTest".

4. Agregue una propiedad pública para el proveedor del complemento (obligatorio).

En este ejemplo, el proveedor es "Microsoft".

5. Agregue una propiedad pública para el recurso de proveedor del complemento


(opcional).

En este ejemplo, el recurso del proveedor es "CustomPSSnapInTest,Microsoft".

6. Agregue una propiedad pública para la descripción del complemento (obligatorio).

En este ejemplo, la descripción es: "Se trata de un complemento Windows


PowerShell personalizado que incluye los Test-HelloWorld Test-CustomSnapinTest
cmdlets y ".
7. Agregue una propiedad pública para el recurso de descripción del complemento
(opcional).

En este ejemplo, el recurso del proveedor es:

CustomPSSnapInTest, se trata de un complemento Windows PowerShell que


incluye los cmdlets Test-HelloWorld y Test-CustomSnapinTest personalizados".

8. Especifique los cmdlets que pertenecen al complemento personalizado (opcional)


mediante la clase
System.Management.Automation.Runspaces.Cmdletconfigurationentry. La
información que se agrega aquí incluye el nombre del cmdlet, su tipo de .NET y el
nombre de archivo de ayuda del cmdlet (el formato del nombre del archivo de
ayuda del cmdlet debe ser name.dll-help.xml ).

En este ejemplo se agregan los cmdlets Test-HelloWorld y TestCustomSnapinTest.

9. Especifique los proveedores que pertenecen al complemento personalizado


(opcional).

En este ejemplo no se especifica ningún proveedor.

10. Especifique los tipos que pertenecen al complemento personalizado (opcional).

En este ejemplo no se especifica ningún tipo.

11. Especifique los formatos que pertenecen al complemento personalizado


(opcional).

En este ejemplo no se especifica ningún formato.

Ejemplo
En este ejemplo se muestra cómo escribir un complemento Windows PowerShell
personalizado que se puede usar para registrar los Test-HelloWorld Test-
CustomSnapinTest cmdlets y . Tenga en cuenta que, en este ejemplo, el ensamblado
completo podría contener otros cmdlets y proveedores que este complemento no
registraría.

C#

[RunInstaller(true)]
public class CustomPSSnapinTest : CustomPSSnapIn
{
/// <summary>
/// Creates an instance of CustomPSSnapInTest class.
/// </summary>
public CustomPSSnapinTest()
: base()
{
}

/// <summary>
/// Specify the name of the custom PowerShell snap-in.
/// </summary>
public override string Name
{
get
{
return "CustomPSSnapInTest";
}
}

/// <summary>
/// Specify the vendor for the custom PowerShell snap-in.
/// </summary>
public override string Vendor
{
get
{
return "Microsoft";
}
}

/// <summary>
/// Specify the localization resource information for the vendor.
/// Use the format: resourceBaseName,resourceName.
/// </summary>
public override string VendorResource
{
get
{
return "CustomPSSnapInTest,Microsoft";
}
}

/// <summary>
/// Specify a description of the custom PowerShell snap-in.
/// </summary>
public override string Description
{
get
{
return "This is a custom PowerShell snap-in that includes the Test-
HelloWorld and Test-CustomSnapinTest cmdlets.";
}
}

/// <summary>
/// Specify the localization resource information for the description.
/// Use the format: resourceBaseName,Description.
/// </summary>
public override string DescriptionResource
{
get
{
return "CustomPSSnapInTest,This is a custom PowerShell snap-in that
includes the Test-HelloWorld and Test-CustomSnapinTest cmdlets.";
}
}

/// <summary>
/// Specify the cmdlets that belong to this custom PowerShell snap-in.
/// </summary>
private Collection<CmdletConfigurationEntry> _cmdlets;
public override Collection<CmdletConfigurationEntry> Cmdlets
{
get
{
if (_cmdlets == null)
{
_cmdlets = new Collection<CmdletConfigurationEntry>();
_cmdlets.Add(new CmdletConfigurationEntry("test-customsnapintest",
typeof(TestCustomSnapinTest), "TestCmdletHelp.dll-help.xml"));
_cmdlets.Add(new CmdletConfigurationEntry("test-helloworld",
typeof(TestHelloWorld), "HelloWorldHelp.dll-help.xml"));
}

return _cmdlets;
}
}

/// <summary>
/// Specify the providers that belong to this custom PowerShell snap-in.
/// </summary>
private Collection<ProviderConfigurationEntry> _providers;
public override Collection<ProviderConfigurationEntry> Providers
{
get
{
if (_providers == null)
{
_providers = new Collection<ProviderConfigurationEntry>();
}

return _providers;
}
}

/// <summary>
/// Specify the types that belong to this custom PowerShell snap-in.
/// </summary>
private Collection<TypeConfigurationEntry> _types;
public override Collection<TypeConfigurationEntry> Types
{
get
{
if (_types == null)
{
_types = new Collection<TypeConfigurationEntry>();
}

return _types;
}
}

/// <summary>
/// Specify the formats that belong to this custom PowerShell snap-in.
/// </summary>
private Collection<FormatConfigurationEntry> _formats;
public override Collection<FormatConfigurationEntry> Formats
{
get
{
if (_formats == null)
{
_formats = new Collection<FormatConfigurationEntry>();
}

return _formats;
}
}
}

Para obtener más información sobre el registro de complementos, vea How to Register
Cmdlets, Providers, and Host Applications (Cómo registrar cmdlets, proveedores y
aplicaciones host) en Windows PowerShell Programmer's Guide (Guía del programador).

Consulte también
Cómo registrar cmdlets, proveedores y aplicaciones host

SDK del shell de Windows PowerShell


Importación de un módulo de
PowerShell
Artículo • 25/09/2021

Una vez que haya instalado un módulo en un sistema, es probable que quiera importar
el módulo. La importación es el proceso que carga el módulo en la memoria activa, para
que un usuario pueda acceder a ese módulo en su sesión de PowerShell. En PowerShell
2.0, puede importar un módulo de PowerShell recién instalado con una llamada al
cmdlet Import-Module. En PowerShell 3.0, PowerShell puede importar implícitamente un
módulo cuando un usuario llama a una de las funciones o cmdlets del módulo. Tenga en
cuenta que ambas versiones suponen que instala el módulo en una ubicación donde
PowerShell pueda encontrarlo. Para obtener más información, vea Instalación de un
módulo de PowerShell. Puede usar un manifiesto de módulo para restringir qué partes
del módulo se exportan y puede usar parámetros de la llamada para restringir qué
partes Import-Module se importan.

Importar un Snap-In (PowerShell 1.0)


Los módulos no existían en PowerShell 1.0: en su lugar, tenía que registrar y usar
complementos. Sin embargo, no se recomienda usar esta tecnología en este momento,
ya que los módulos suelen ser más fáciles de instalar e importar. Para obtener más
información, vea How to Create a Windows PowerShell Snap-in.

Importar un módulo con Import-Module


(PowerShell 2.0)
PowerShell 2.0 usa el cmdlet Import-Module con el nombre adecuado para importar
módulos. Cuando se ejecuta este cmdlet, Windows PowerShell busca el módulo
especificado dentro de los directorios especificados en la PSModulePath variable .
Cuando se encuentra el directorio especificado, Windows PowerShell busca archivos en
el orden siguiente: archivos de manifiesto de módulo (.psd1), archivos de módulo de
script (.psm1), archivos de módulo binarios (.dll). Para obtener más información sobre
cómo agregar directorios a la búsqueda, vea about_PSModulePath. En el código
siguiente se describe cómo importar un módulo:

PowerShell

Import-Module myModule
Suponiendo que myModule se encuentra en PSModulePath , PowerShell cargaría
myModule en la memoria activa. Si myModule no se encuentra en una ruta de acceso,
todavía podría decir explícitamente a PSModulePath PowerShell dónde encontrarlo:

PowerShell

Import-Module -Name C:\myRandomDirectory\myModule -Verbose

También puede usar el parámetro para identificar lo que se exporta fuera del módulo y
lo -Verbose que se importa en la memoria activa. Tanto las exportaciones como las
importaciones restringen lo que se expone al usuario: la diferencia es quién controla la
visibilidad. Básicamente, las exportaciones se controlan mediante código dentro del
módulo. Por el contrario, las importaciones se controlan mediante la Import-Module
llamada a . Para obtener más información, vea Restringir los miembros que se
importan a continuación.

Importar implícitamente un módulo


(PowerShell 3.0)
A partir de Windows PowerShell 3.0, los módulos se importan automáticamente cuando
se usa cualquier cmdlet o función del módulo en un comando. Esta característica
funciona en cualquier módulo de un directorio incluido en el valor de la variable de
entorno PSModulePath. Sin embargo, si no guarda el módulo en una ruta de acceso
válida, todavía puede cargarlo mediante la opción Import-Module explícita, descrita
anteriormente.

Las siguientes acciones desencadenan la importación automática de un módulo,


también conocido como "carga automática del módulo".

Uso de un cmdlet en un comando. Por ejemplo, al Get-ExecutionPolicy escribir se


importa el módulo Microsoft.PowerShell.Security que contiene el cmdlet Get-
ExecutionPolicy .

Uso del cmdlet Get-Command para obtener el comando. Por ejemplo, al Get-
Command Get-JobTrigger escribir se importa el módulo PSScheduledJob que

contiene el Get-JobTrigger cmdlet . Un Get-Command comando que incluye


caracteres comodín se considera detección y no desencadena la importación de un
módulo.

Uso del cmdlet Get-Help para obtener ayuda para un cmdlet. Por ejemplo, al Get-
Help Get-WinEvent escribir se importa el módulo Microsoft.PowerShell.Diagnostics
que contiene el cmdlet Get-WinEvent .

Para admitir la importación automática de módulos, el cmdlet obtiene todos los cmdlets
y funciones de todos los módulos instalados, incluso si el módulo no se Get-Command
importa en la sesión. Para obtener más información, vea el tema de ayuda del cmdlet
Get-Command.

El proceso de importación
Cuando se importa un módulo, se crea un nuevo estado de sesión para el módulo y se
crea un objeto System.Management.Automation.PSModuleInfo en memoria. Se crea un
estado de sesión para cada módulo que se importa (esto incluye el módulo raíz y los
módulos anidados). Los miembros que se exportan desde el módulo raíz, incluidos los
miembros exportados al módulo raíz por cualquier módulo anidado, se importan a
continuación en el estado de sesión del autor de la llamada.

Los metadatos de los miembros que se exportan desde un módulo tienen una
propiedad ModuleName. Esta propiedad se rellena con el nombre del módulo que las
exportó.

2 Advertencia

Si el nombre de un miembro exportado usa un verbo no aprobado o si el nombre


del miembro usa caracteres restringidos, se muestra una advertencia cuando se
ejecuta el cmdlet Import-Module.

De forma predeterminada, el cmdlet Import-Module no devuelve ningún objeto a la


canalización. Sin embargo, el cmdlet admite un parámetro PassThru que se puede usar
para devolver un objeto System.Management.Automation.PSModuleInfo para cada
módulo que se importa. Para enviar la salida al host, los usuarios deben ejecutar el
cmdlet Write-Host.

Restringir los miembros que se importan


Cuando se importa un módulo mediante el cmdlet Import-Module, de forma
predeterminada, todos los miembros del módulo exportados se importan en la sesión,
incluidos los comandos exportados al módulo por un módulo anidado. De forma
predeterminada, las variables y alias no se exportan. Para restringir los miembros que se
exportan, use un manifiesto de módulo. Para restringir los miembros que se importan,
use los parámetros siguientes del Import-Module cmdlet .
Función: este parámetro restringe las funciones que se exportan. (Si usa un
manifiesto de módulo, vea la clave FunctionsToExport).

`Cmdlet: este parámetro restringe los cmdlets que se exportan (si usa un
manifiesto de módulo, vea la clave CmdletsToExport).

Variable: este parámetro restringe las variables que se exportan (si usa un
manifiesto de módulo, vea la clave VariablesToExport).

Alias: este parámetro restringe los alias que se exportan (si usa un manifiesto de
módulo, vea la clave AliasesToExport).

Consulte también
Escritura de un módulo de Windows PowerShell
Inicio rápido de Proveedor de Windows
PowerShell
Artículo • 24/09/2021

En este tema se explica cómo crear un Windows PowerShell que tenga la funcionalidad
básica de crear una nueva unidad. Para obtener información general sobre los
proveedores, vea Windows PowerShell Provider Overview. Para obtener ejemplos de
proveedores con una funcionalidad más completa, vea Ejemplos de proveedores.

Escritura de un proveedor básico


La funcionalidad más básica de un proveedor Windows PowerShell es crear y quitar
unidades. En este ejemplo, implementamos los métodos
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* y
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* de la
clase System.Management.Automation.Provider.Drivecmdletprovider. También verá
cómo declarar una clase de proveedor.

Al escribir un proveedor, puede especificar unidades de disco predeterminadas que se


crean automáticamente cuando el proveedor está disponible. También se define un
método para crear nuevas unidades que usan ese proveedor.

Los ejemplos proporcionados en este tema se basan en el ejemplo


AccessDBProviderSample02, que forma parte de un ejemplo mayor que representa una
base de datos de Access como una Windows PowerShell de datos.

Configuración del proyecto


En Visual Studio, cree un proyecto de biblioteca de clases denominado
AccessDBProviderSample. Complete los pasos siguientes para configurar el proyecto de
modo que Windows PowerShell se inicie y el proveedor se cargará en la sesión, al
compilar e iniciar el proyecto.

Configuración del proyecto de proveedor

1. Agregue el ensamblado System.Management.Automation como referencia al


proyecto.

2. Haga clic Project > en Propiedades de AccessDBProviderSample > Depurar. En


Proyecto de inicio , haga clic en Iniciar programa externo y vaya al archivo
ejecutable de Windows PowerShell (normalmente
c:\Windows\System32\WindowsPowerShell\v1.0 \ .powershell.exe).

3. En Opciones de inicio, escriba lo siguiente en el cuadro Argumentos de la línea de


comandos: -noexit -command "
[reflection.assembly]::loadFrom(AccessDBProviderSample.dll' ) | import-module"

Declarar la clase de proveedor


Nuestro proveedor deriva de la clase
System.Management.Automation.Provider.Drivecmdletprovider. La mayoría de los
proveedores que proporcionan funcionalidad real (acceso y manipulación de elementos,
navegar por el almacén de datos y obtener y establecer contenido de elementos)
derivan de la clase System.Management.Automation.Provider.Navigationcmdletprovider.

Además de especificar que la clase deriva de


System.Management.Automation.Provider.Drivecmdletprovider,debe decorarla con
System.Management.Automation.Provider.Cmdletproviderattribute como se muestra en
el ejemplo.

C#

namespace Microsoft.Samples.PowerShell.Providers
{
using System;
using System.Data;
using System.Data.Odbc;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Provider;

#region AccessDBProvider

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : DriveCmdletProvider
{

}
}

Implementación de NewDrive
El motor de Windows PowerShell llama al método
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* cuando un
usuario llama al cmdlet Microsoft.PowerShell.Commands.NewPSDriveCommand
especificando el nombre del proveedor. El motor de Windows PowerShell pasa el
parámetro PSDriveInfo y el método devuelve la nueva unidad al Windows PowerShell
motor. Este método debe declararse dentro de la clase creada anteriormente.

El método comprueba primero si existe el objeto de unidad y la raíz de la unidad que se


pasaron, devolviendo si null alguno de ellos no lo hace. A continuación, usa un
constructor de la clase interna AccessDBPSDriveInfo para crear una nueva unidad y una
conexión a la base de datos de Access que representa la unidad.

C#

protected override PSDriveInfo NewDrive(PSDriveInfo drive)


{
// Check if the drive object is null.
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null));

return null;
}

// Check if the drive root is not null or empty


// and if it is an existing file.
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root) ==
false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive));

return null;
}

// Create a new drive and create an ODBC connection to the new drive.
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);
OdbcConnectionStringBuilder builder = new
OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new OdbcConnection(builder.ConnectionString);


conn.Open();
accessDBPSDriveInfo.Connection = conn;
return accessDBPSDriveInfo;
}

A continuación se muestra la clase interna AccessDBPSDriveInfo que incluye el


constructor usado para crear una nueva unidad y contiene la información de estado de
la unidad.

C#

internal class AccessDBPSDriveInfo : PSDriveInfo


{
/// <summary>
/// A reference to the connection to the database.
/// </summary>
private OdbcConnection connection;

/// <summary>
/// Initializes a new instance of the AccessDBPSDriveInfo class.
/// The constructor takes a single argument.
/// </summary>
/// <param name="driveInfo">Drive defined by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{
}

/// <summary>
/// Gets or sets the ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return this.connection; }
set { this.connection = value; }
}
}

Implementación de RemoveDrive
El motor de Windows PowerShell llama al método
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* cuando
un usuario llama al cmdlet Microsoft.PowerShell.Commands.RemovePSDriveCommand.
El método de este proveedor cierra la conexión a la base de datos de Access.

C#

protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)


{
// Check if drive object is null.
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive));

return null;
}

// Close the ODBC connection to the drive.


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}

accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
}
Información general sobre Proveedor de
Windows PowerShell
Artículo • 27/09/2021

Un Windows PowerShell de datos permite que cualquier almacén de datos se exponga


como un sistema de archivos como si fuera una unidad montada. Por ejemplo, el
proveedor del Registro integrado le permite navegar por el registro como si navegara
por la c unidad del equipo. Un proveedor también puede invalidar Item los cmdlets
(por ejemplo, Get-Item , , etc.) para que los datos del almacén de datos se puedan tratar
como archivos y directorios que se tratan al navegar por un sistema de Set-Item
archivos. Para obtener más información sobre los proveedores y las unidades, y los
proveedores integrados en Windows PowerShell, vea about_Providers.

Proveedores y unidades
Un proveedor define la lógica que se usa para acceder, navegar y editar un almacén de
datos, mientras que una unidad especifica un punto de entrada específico a un almacén
de datos (o una parte de un almacén de datos) que es del tipo definido por el
proveedor. Por ejemplo, el proveedor del Registro permite acceder a los subárboles y las
claves de un registro, y las unidades HKLM y HKCU especifican los subárboles
correspondientes dentro del registro. Las unidades HKLM y HKCU usan el proveedor del
Registro.

Al escribir un proveedor, puede especificar unidades-unidades predeterminadas que se


crean automáticamente cuando el proveedor está disponible. También se define un
método para crear nuevas unidades que usan ese proveedor.

Tipo de proveedores
Hay varios tipos de proveedores, cada uno de los cuales proporciona un nivel de
funcionalidad diferente. Un proveedor se implementa como una clase que deriva de uno
de los descendientes de la clase CmdletProvider
System.Management.Automation.SessionStateCategory. Para obtener información sobre
los distintos tipos de proveedores, vea Tipos de proveedor.

Cmdlets de proveedor
Los proveedores pueden implementar métodos que se corresponden con cmdlets,
creando comportamientos personalizados para esos cmdlets cuando se usan en una
unidad para ese proveedor. En función del tipo de proveedor, hay disponibles diferentes
conjuntos de cmdlets. Para obtener una lista completa de los cmdlets disponibles para
la personalización en proveedores, vea Cmdlets de proveedor.

Rutas de acceso del proveedor


Los usuarios navegan por unidades de proveedor como sistemas de archivos. Por este
problema, esperan que la sintaxis de las rutas de acceso se corresponda con las rutas de
acceso usadas en la navegación del sistema de archivos. Cuando un usuario ejecuta un
cmdlet de proveedor, especifica una ruta de acceso al elemento al que se va a acceder.
La ruta de acceso especificada se puede interpretar de varias maneras. Un proveedor
debe admitir uno o varios de los siguientes tipos de ruta de acceso.

Rutas de acceso calificadas por unidad


Una ruta de acceso calificada por unidad es una combinación del nombre del elemento,
el contenedor y los subcontenedores en los que se encuentra el elemento y la unidad
Windows PowerShell a través de la que se accede al elemento. (Las unidades las define
el proveedor que se usa para acceder al almacén de datos. Esta ruta de acceso comienza
con el nombre de unidad seguido de dos puntos (:). Por ejemplo: get-childitem C:

Rutas de acceso calificadas por el proveedor


Para permitir que Windows PowerShell motor inicialice y desinicialice el proveedor, el
proveedor debe admitir una ruta de acceso calificada por el proveedor. Por ejemplo, el
usuario puede inicializar y desinicializar el proveedor FileSystem porque define la
siguiente ruta de acceso calificada por el proveedor: FileSystem::\\uncshare\abc\bar .

Rutas de acceso directas del proveedor


Para permitir el acceso remoto al proveedor de Windows PowerShell, debe admitir una
ruta de acceso directa del proveedor para pasar directamente al proveedor de Windows
PowerShell para la ubicación actual. Por ejemplo, el proveedor Windows PowerShell
registro puede usar \\server\regkeypath como ruta de acceso directa del proveedor.

Rutas de acceso internas del proveedor


Para permitir que el cmdlet del proveedor acceda a los datos mediante interfaces de
programación de aplicaciones (API) que no son de Windows PowerShell, el proveedor
de Windows PowerShell debe admitir una ruta de acceso interna del proveedor. Esta
ruta de acceso se indica después de "::" en la ruta de acceso completa del proveedor.
Por ejemplo, la ruta de acceso interna del proveedor para el sistema de Windows
PowerShell es \\uncshare\abc\bar .

Invalidación de parámetros de cmdlet


Un proveedor puede invalidar el comportamiento de algunos cmdlets específicos del
proveedor. Para obtener una lista de parámetros que se pueden invalidar y cómo
invalidarlos en la clase de proveedor, consulte Provider cmdlet parameters (Parámetros
del cmdlet Provider).

Parámetros dinámicos
Los proveedores pueden definir parámetros dinámicos que se agregan a un cmdlet de
proveedor cuando el usuario especifica un valor determinado para uno de los
parámetros estáticos del cmdlet. Para ello, un proveedor implementa uno o varios
métodos de parámetros dinámicos. Para obtener una lista de parámetros de cmdlet que
se pueden usar para agregar parámetros dinámicos y los métodos usados para
implementarlos, vea Provider cmdlet dynamic parameters.

Funcionalidades del proveedor


La enumeración System.Management.Automation.Provider.Providercapabilities define
una serie de funcionalidades que los proveedores pueden admitir. Entre ellas se incluye
la capacidad de usar caracteres comodín, filtrar elementos y admitir transacciones. Para
especificar las funcionalidades de un proveedor, agregue una lista de valores de la
enumeración System.Management.Automation.Provider.Providercapabilities, combinada
con una operación lógica, como la propiedad OR
System.Management.Automation.Provider.Cmdletproviderattribute.Providercapabilities*
(el segundo parámetro del atributo) del atributo
System.Management.Automation.Provider.Cmdletproviderattribute para la clase de
proveedor. Por ejemplo, el atributo siguiente especifica que el proveedor admite las
funcionalidades System.Management.Automation.Provider.Providercapabilities
ShouldProcess y System.Management.Automation.Provider.ProviderCapabilities
Transactions.

C#
[CmdletProvider(RegistryProvider.ProviderName,
ProviderCapabilities.ShouldProcess | ProviderCapabilities.Transactions)]

Ayuda del cmdlet del proveedor


Al escribir un proveedor, puede implementar su propia Ayuda para los cmdlets de
proveedor que admite. Esto incluye un único tema de ayuda para cada cmdlet de
proveedor o varias versiones de un tema de ayuda para los casos en los que el cmdlet
del proveedor actúa de forma diferente en función del uso de parámetros dinámicos.
Para admitir ayuda específica del cmdlet del proveedor, el proveedor debe implementar
la interfaz System.Management.Automation.Provider.Icmdletprovidersupportshelp.

El motor Windows PowerShell llama al método


System.Management.Automation.Provider.Icmdletprovidersupportshelp.Gethelpmaml*
para mostrar el tema de Ayuda de los cmdlets del proveedor. El motor proporciona el
nombre del cmdlet que el usuario especificó al ejecutar el cmdlet y la Get-Help ruta de
acceso actual del usuario. La ruta de acceso actual es necesaria si el proveedor
implementa versiones diferentes del mismo cmdlet de proveedor para distintas
unidades. El método debe devolver una cadena que contenga el XML de la Ayuda del
cmdlet.

El contenido del archivo de Ayuda se escribe mediante PSMAML XML. Se trata del
mismo esquema XML que se usa para escribir contenido de Ayuda para cmdlets
independientes. Agregue el contenido de la Ayuda del cmdlet personalizado al archivo
de Ayuda del proveedor en el CmdletHelpPaths elemento . En el ejemplo siguiente se
muestra el elemento para un cmdlet de proveedor único y se muestra cómo especificar
el nombre del cmdlet de command proveedor que el proveedor. Soporta

XML

<CmdletHelpPaths>
<command:command>
<command:details>
<command:name>ProviderCmdletName</command:name>
<command:verb>Verb</command:verb>
<command:noun>Noun</command:noun>
<command:details>
</command:command>
<CmdletHelpPath>
Consulte también
Windows PowerShell Funcionalidad del proveedor

Cmdlets de proveedor

Escritura de un proveedor de Windows PowerShell


Tipos de proveedor
Artículo • 04/11/2021

Los proveedores definen su funcionalidad básica cambiando el modo en que los


cmdlets del proveedor, proporcionados por PowerShell, realizan sus acciones. Por
ejemplo, los proveedores pueden usar la funcionalidad predeterminada del cmdlet o
pueden cambiar cómo funciona ese cmdlet al recuperar elementos Get-Item del
almacén de datos. La funcionalidad del proveedor descrita en este documento incluye la
funcionalidad definida por la sobrescritura de métodos de interfaces y clases base de
proveedor específicas.

7 Nota

Para ver las características de proveedor predefinidas por PowerShell, consulte


Funcionalidades del proveedor.

Proveedores habilitados para unidades


Los proveedores habilitados para unidades especifican las unidades predeterminadas
disponibles para el usuario y permiten al usuario agregar o quitar unidades. En la
mayoría de los casos, los proveedores son proveedores habilitados para unidades
porque requieren alguna unidad predeterminada para acceder al almacén de datos. Sin
embargo, al escribir su propio proveedor, es posible que desee o no permitir que el
usuario cree y quite unidades.

Para crear un proveedor habilitado para unidad, la clase de proveedor debe derivar de la
clase System.Management.Automation.Provider.DriveCmdletProvider u otra clase que se
derive de esa clase. La clase DriveCmdletProvider define los métodos siguientes para
implementar las unidades predeterminadas del proveedor y admitir los New-PSDrive
Remove-PSDrive cmdlets y . En la mayoría de los casos, para admitir un cmdlet de

proveedor, debe sobrescribir el método al que llama el motor de PowerShell para


invocar el cmdlet, como el método del cmdlet y, opcionalmente, puede sobrescribir un
segundo método, como , para agregar parámetros dinámicos al NewDrive New-PSDrive
NewDriveDynamicParameters cmdlet.

El método InitializeDefaultDrives define las unidades predeterminadas que están


disponibles para el usuario cada vez que se usa el proveedor.
Los métodos NewDrive y NewDriveDynamicParameters definen cómo el proveedor
admite el New-PSDrive cmdlet del proveedor. Este cmdlet permite al usuario crear
unidades para acceder al almacén de datos.

El método RemoveDrive define cómo el proveedor admite el Remove-PSDrive


cmdlet del proveedor. Este cmdlet permite al usuario quitar unidades del almacén
de datos.

Proveedores habilitados para elementos


Los proveedores habilitados para elementos permiten al usuario obtener, establecer o
borrar los elementos del almacén de datos. Un "elemento" es un elemento del almacén
de datos al que el usuario puede acceder o administrar de forma independiente. Para
crear un proveedor habilitado para elementos, la clase de proveedor debe derivar de la
clase System.Management.Automation.Provider.ItemCmdletProvider u otra clase que se
derive de esa clase.

La clase ItemCmdletProvider define los métodos siguientes para implementar cmdlets


de proveedor específicos. En la mayoría de los casos, para admitir un cmdlet de
proveedor, debe sobrescribir el método al que llama el motor de PowerShell para
invocar el cmdlet, como el método del cmdlet y, opcionalmente, puede sobrescribir un
segundo método, como , para agregar parámetros dinámicos al ClearItem Clear-Item
ClearItemDynamicParameters cmdlet.

Los métodos ClearItem y ClearItemDynamicParameters definen cómo el proveedor


admite el Clear-Item cmdlet del proveedor. Este cmdlet permite al usuario quitar
el valor de un elemento en el almacén de datos.

Los métodos GetItem y GetItemDynamicParameters definen cómo el proveedor


admite el Get-Item cmdlet del proveedor. Este cmdlet permite al usuario recuperar
datos del almacén de datos.

Los métodos SetItem y SetItemDynamicParameters definen cómo el proveedor


admite el Set-Item cmdlet del proveedor. Este cmdlet permite al usuario actualizar
los valores de los elementos del almacén de datos.

Los métodos InvokeDefaultAction e InvokeDefaultActionDynamicParameters


definen cómo el proveedor admite el Invoke-Item cmdlet del proveedor. Este
cmdlet permite al usuario realizar la acción predeterminada especificada por el
elemento.
Los métodos ItemExists y ItemExistsDynamicParameters definen cómo el
proveedor admite el Test-Path cmdlet del proveedor. Este cmdlet permite al
usuario determinar si existen todos los elementos de una ruta de acceso.

Además de los métodos usados para implementar cmdlets de proveedor, la clase


ItemCmdletProvider también define los métodos siguientes:

El método ExpandPath permite al usuario usar caracteres comodín al especificar la


ruta de acceso del proveedor.

IsValidPath se usa para determinar si una ruta de acceso es sintáctica y


semánticamente válida para el proveedor.

Proveedores habilitados para contenedores


Los proveedores habilitados para contenedores permiten al usuario administrar
elementos que son contenedores. Un contenedor es un grupo de elementos
secundarios con un elemento primario común. Para crear un proveedor habilitado para
contenedor, la clase de proveedor debe derivar de la clase
System.Management.Automation.Provider.ContainerCmdletProvider u otra clase que se
derive de esa clase.

) Importante

Los proveedores habilitados para contenedores no pueden acceder a los almacenes


de datos que contienen contenedores anidados. Si un elemento secundario de un
contenedor es otro contenedor, debe implementar un proveedor habilitado para la
navegación.

La clase ContainerCmdletProvider define los métodos siguientes para implementar


cmdlets de proveedor específicos. En la mayoría de los casos, para admitir un cmdlet de
proveedor, debe sobrescribir el método al que llama el motor de PowerShell para
invocar el cmdlet, como el método del cmdlet y, opcionalmente, puede sobrescribir un
segundo método, como , para agregar parámetros dinámicos al CopyItem Copy-Item
CopyItemDynamicParameters cmdlet.

Los métodos CopyItem y CopyItemDynamicParameters definen cómo el proveedor


admite el Copy-Item cmdlet del proveedor. Este cmdlet permite al usuario copiar
un elemento de una ubicación a otra.
Los métodos GetChildItems y GetChildItemsDynamicParameters definen cómo el
proveedor admite el Get-ChildItem cmdlet del proveedor. Este cmdlet permite al
usuario recuperar los elementos secundarios del elemento primario.

Los métodos GetChildNames y GetChildNamesDynamicParameters definen cómo


el proveedor admite el cmdlet provider si se especifica Get-ChildItem su
parámetro Name .

Los métodos NewItem y NewItemDynamicParameters definen cómo el proveedor


admite el New-Item cmdlet del proveedor. Este cmdlet permite al usuario crear
nuevos elementos en el almacén de datos.

Los métodos RemoveItem y RemoveItemDynamicParameters definen cómo el


proveedor admite el Remove-Item cmdlet del proveedor. Este cmdlet permite al
usuario quitar elementos del almacén de datos.

Los métodos RenameItem y RenameItemDynamicParameters definen cómo el


proveedor admite el Rename-Item cmdlet del proveedor. Este cmdlet permite al
usuario cambiar el nombre de los elementos del almacén de datos.

Además de los métodos usados para implementar cmdlets de proveedor, la clase


ContainerCmdletProvider también define los métodos siguientes:

La clase de proveedor puede usar el método HasChildItems para determinar si un


elemento tiene elementos secundarios.

La clase de proveedor puede usar el método ConvertPath para crear una nueva
ruta de acceso específica del proveedor a partir de una ruta de acceso
especificada.

Proveedores habilitados para navegación


Los proveedores habilitados para la navegación permiten al usuario mover elementos
en el almacén de datos. Para crear un proveedor habilitado para la navegación, la clase
de proveedor debe derivar de la clase
System.Management.Automation.Provider.NavigationCmdletProvider.

La clase NavigationCmdletProvider define los métodos siguientes para implementar


cmdlets de proveedor específicos. En la mayoría de los casos, para admitir un cmdlet de
proveedor, debe sobrescribir el método al que llama el motor de PowerShell para
invocar el cmdlet, como el método del cmdlet y, opcionalmente, puede sobrescribir un
segundo método, como , para agregar parámetros dinámicos al MoveItem Move-Item
MoveItemDynamicParameters cmdlet.
Los métodos MoveItem y MoveItemDynamicParameters definen cómo el
proveedor admite el Move-Item cmdlet del proveedor. Este cmdlet permite al
usuario mover un elemento de una ubicación del almacén a otra.

El método MakePath define cómo el proveedor admite el Join-Path cmdlet


provider. Este cmdlet permite al usuario combinar un segmento de ruta de acceso
principal y secundario para crear una ruta de acceso interna del proveedor.

Además de los métodos usados para implementar cmdlets de proveedor, la clase


NavigationCmdletProvider también define los métodos siguientes:

El método GetChildName extrae el nombre del nodo secundario de una ruta de


acceso.

El método GetParentPath extrae la parte primaria de una ruta de acceso.

El método IsItemContainer determina si el elemento es un elemento contenedor.


En este contexto, un contenedor es un grupo de elementos secundarios en un
elemento primario común.

El método NormalizeRelativePath devuelve una ruta de acceso a un elemento


relativo a una ruta de acceso base especificada.

Proveedores habilitados para contenido


Los proveedores habilitados para contenido permiten al usuario borrar, obtener o
establecer el contenido de los elementos de un almacén de datos. Por ejemplo, el
proveedor FileSystem permite borrar, obtener y establecer el contenido de los archivos
en el sistema de archivos. Para crear un proveedor habilitado para contenido, la clase de
proveedor debe implementar los métodos de la interfaz
System.Management.Automation.Provider.IContentCmdletProvider.

La interfaz IContentCmdletProvider define los métodos siguientes para implementar


cmdlets de proveedor específicos. En la mayoría de los casos, para admitir un cmdlet de
proveedor, debe sobrescribir el método al que llama el motor de PowerShell para
invocar el cmdlet, como el método del cmdlet y, opcionalmente, puede sobrescribir un
segundo método, como , para agregar parámetros dinámicos al ClearContent Clear-
Content ClearContentDynamicParameters cmdlet.

Los métodos ClearContent y ClearContentDynamicParameters definen cómo el


proveedor admite el Clear-Content cmdlet del proveedor. Este cmdlet permite al
usuario eliminar el contenido de un elemento sin eliminarlo.
Los métodos GetContentReader y GetContentReaderDynamicParameters definen
cómo el proveedor admite el Get-Content cmdlet del proveedor. Este cmdlet
permite al usuario recuperar el contenido de un elemento. El GetContentReader
método devuelve una interfaz
System.Management.Automation.Provider.IContentReader que define los métodos
usados para leer el contenido.

Los métodos GetContentWriter y GetContentWriterDynamicParameters definen


cómo el proveedor admite el Set-Content cmdlet del proveedor. Este cmdlet
permite al usuario actualizar el contenido de un elemento. El GetContentWriter
método devuelve una interfaz
System.Management.Automation.Provider.IContentWriter que define los métodos
usados para escribir el contenido.

Proveedores habilitados para propiedades


Los proveedores habilitados para propiedades permiten al usuario administrar las
propiedades de los elementos del almacén de datos. Para crear un proveedor habilitado
para propiedades, la clase de proveedor debe implementar los métodos de las
interfaces System.Management.Automation.Provider.IPropertyCmdletProvider y
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider. En la
mayoría de los casos, para admitir un cmdlet de proveedor, debe sobrescribir el método
al que llama el motor de PowerShell para invocar el cmdlet, como el método para el
cmdlet Clear-Property y, opcionalmente, puede sobrescribir un segundo método, como ,
para agregar parámetros dinámicos al ClearProperty ClearPropertyDynamicParameters
cmdlet.

La interfaz IPropertyCmdletProvider define los métodos siguientes para implementar


cmdlets de proveedor específicos:

Los métodos ClearProperty y ClearPropertyDynamicParameters definen cómo el


proveedor admite el Clear-ItemProperty cmdlet del proveedor. Este cmdlet
permite al usuario eliminar el valor de una propiedad.

Los métodos GetProperty y GetPropertyDynamicParameters definen cómo el


proveedor admite el Get-ItemProperty cmdlet del proveedor. Este cmdlet permite
al usuario recuperar la propiedad de un elemento.

Los métodos SetProperty y SetPropertyDynamicParameters definen cómo el


proveedor admite el Set-ItemProperty cmdlet del proveedor. Este cmdlet permite
al usuario actualizar las propiedades de un elemento.
La interfaz IDynamicPropertyCmdletProvider define los métodos siguientes para
implementar cmdlets de proveedor específicos:

Los métodos CopyProperty y CopyPropertyDynamicParameters definen cómo el


proveedor admite el Copy-ItemProperty cmdlet del proveedor. Este cmdlet permite
al usuario copiar una propiedad y su valor de una ubicación a otra.

Los métodos MoveProperty y MovePropertyDynamicParameters definen cómo el


proveedor admite el Move-ItemProperty cmdlet del proveedor. Este cmdlet permite
al usuario mover una propiedad y su valor de una ubicación a otra.

Los métodos NewProperty y NewPropertyDynamicParameters definen cómo el


proveedor admite el New-ItemProperty cmdlet del proveedor. Este cmdlet permite
al usuario crear una nueva propiedad y establecer su valor.

Los métodos RemoveProperty y RemovePropertyDynamicParameters definen


cómo el proveedor admite el Remove-ItemProperty cmdlet . Este cmdlet permite al
usuario eliminar una propiedad y su valor.

Los métodos RenameProperty y RenamePropertyDynamicParameters definen


cómo el proveedor admite el Rename-ItemProperty cmdlet . Este cmdlet permite al
usuario cambiar el nombre de una propiedad.

Consulte también
about_Providers

Escritura de un proveedor de Windows PowerShell


Cmdlets de proveedor
Artículo • 24/11/2021

Los cmdlets que el usuario puede ejecutar para administrar un almacén de datos se
conocen como cmdlets de proveedor. Para admitir estos cmdlets, debe sobrescribir
algunos de los métodos definidos por las clases e interfaces del proveedor base.

Estos son los cmdlets de proveedor que puede ejecutar el usuario:

Cmdlets de PSDrive

Get-PSDrive

Este cmdlet devuelve las unidades de PowerShell de la sesión actual. No es necesario


sobrescribir ningún método para admitir este cmdlet.

New-PSDrive

Este cmdlet permite al usuario crear unidades de PowerShell para acceder al almacén de
datos. Para admitir este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.DriveCmdletProvider:

Newdrive
NewDriveDynamicParameters

Remove-PSDrive

Este cmdlet permite al usuario quitar las unidades de PowerShell que acceden al
almacén de datos. Para admitir este cmdlet, sobrescriba el método
System.Management.Automation.Provider.DriveCmdletProvider.Removedrive.

Cmdlets de elemento

Clear-Item

Este cmdlet permite al usuario quitar el valor de un elemento en el almacén de datos.


Para admitir este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ItemCmdletProvider:
Clearitem
ClearItemDynamicParameters

Copy-Item

Este cmdlet permite al usuario copiar un elemento de una ubicación a otra. Para admitir
este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ContainerCmdletProvider:

Copyitem
CopyItemDynamicParameters

Get-Item

Este cmdlet permite al usuario recuperar datos del almacén de datos. Para admitir este
cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ItemCmdletProvider:

Getitem
GetItemDynamicParameters

Get-ChildItem

Este cmdlet permite al usuario recuperar los elementos secundarios del elemento
primario. Para admitir este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ContainerCmdletProvider:

GetChildItems
GetChildItemsDynamicParameters
GetChildNames
GetChildNamesDynamicParameters

Invoke-Item

Este cmdlet permite al usuario realizar la acción predeterminada especificada por el


elemento . Para admitir este cmdlet, sobrescriba el método
System.Management.Automation.Provider.ItemCmdletProvider.InvokeDefaultAction.

Move-Item
Este cmdlet permite al usuario mover un elemento de una ubicación a otra. Para admitir
este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.Navigationcmdletprovider:

MoveItem
MoveItemDynamicParameters

New-ItemProperty

Este cmdlet permite al usuario crear un nuevo elemento en el almacén de datos.

Remove-Item

Este cmdlet permite al usuario quitar elementos del almacén de datos. Para admitir este
cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ContainerCmdletProvider:

RemoveItem
RemoveItemDynamicParameters

Rename-Item

Este cmdlet permite al usuario cambiar el nombre de los elementos del almacén de
datos. Para admitir este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ContainerCmdletProvider:

RenameItem
RenameItemDynamicParameters

Set-Item

Este cmdlet permite al usuario actualizar los valores de los elementos del almacén de
datos. Para admitir este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ItemCmdletProvider:

SetItem
SetItemDynamicParameters

Cmdlets de contenido de elementos


Add-Content

Este cmdlet permite al usuario agregar contenido a un elemento.

Clear-Content

Este cmdlet permite al usuario eliminar contenido de un elemento sin eliminar el


elemento. Para admitir este cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IContentCmdletProvider:

ClearContent
ClearContentDynamicParameters

Get-Content

Este cmdlet permite al usuario recuperar el contenido de un elemento. Para admitir este
cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IContentCmdletProvider:

GetContentReader
GetContentReaderDynamicParameters

El método GetContentReader devuelve una interfaz


System.Management.Automation.Provider.IContentReader que define los métodos
usados para leer el contenido.

Set-Content

Este cmdlet permite al usuario actualizar el contenido de un elemento. Para admitir este
cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IContentCmdletProvider:

GetContentWriter
GetContentWriterDynamicParameters

El método GetContentWriter devuelve una interfaz


System.Management.Automation.Provider.IContentWriter que define los métodos
usados para escribir el contenido.

Cmdlets de propiedad item


Clear-ItemProperty

Este cmdlet permite al usuario eliminar el valor de una propiedad. Para admitir este
cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IPropertyCmdletProvider:

ClearProperty
ClearPropertyDynamicParameters

Copy-ItemProperty

Este cmdlet permite al usuario copiar una propiedad y su valor de una ubicación a otra.
Para admitir este cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider:

CopyProperty
CopyPropertyDynamicParameters

Get-ItemProperty

Este cmdlet recupera las propiedades de un elemento. Para admitir este cmdlet,
sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IPropertyCmdletProvider:

Getproperty
GetPropertyDynamicParameters

Move-ItemProperty

Este cmdlet permite al usuario mover una propiedad y su valor de una ubicación a otra.
Para admitir este cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider:

MoveProperty
MovePropertyDynamicParameters

New-ItemProperty

Este cmdlet permite al usuario crear una nueva propiedad y establecer su valor. Para
admitir este cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider:
NewProperty
NewPropertyDynamicParameters

Remove-ItemProperty

Este cmdlet permite al usuario eliminar una propiedad y su valor. Para admitir este
cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider:

RemoveProperty
RemovePropertyDynamicParameters

Rename-ItemProperty

Este cmdlet permite al usuario cambiar el nombre de una propiedad. Para admitir este
cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IDynamicPropertyCmdletProvider:

RenameProperty
RenamePropertyDynamicParameters

Set-ItemProperty

Este cmdlet permite al usuario actualizar las propiedades de un elemento. Para admitir
este cmdlet, sobrescriba los métodos siguientes de la interfaz
System.Management.Automation.Provider.IPropertyCmdletProvider:

SetProperty
SetPropertyDynamicParameters

Cmdlets de ubicación

Get-Location

Recupera información sobre la ubicación de trabajo actual. No es necesario sobrescribir


ningún método para admitir este cmdlet.

Pop-Location
Este cmdlet cambia la ubicación actual a la ubicación que se ha inserido más
recientemente en la pila. No es necesario sobrescribir ningún método para admitir este
cmdlet.

Push-Location

Este cmdlet agrega la ubicación actual a la parte superior de una lista de ubicaciones
(una "pila"). No es necesario sobrescribir ningún método para admitir este cmdlet.

Set-Location

Este cmdlet establece la ubicación de trabajo actual en una ubicación especificada. No


es necesario sobrescribir ningún método para admitir este cmdlet.

Cmdlets de ruta de acceso

Join-Path

Este cmdlet permite al usuario combinar un segmento de ruta de acceso principal y


secundario para crear una ruta de acceso interna del proveedor. Para admitir este
cmdlet, sobrescriba el método
System.Management.Automation.Provider.NavigationCmdletProvider.MakePath.

Convert-Path

Este cmdlet convierte una ruta de acceso de una ruta de acceso de PowerShell en una
ruta de acceso del proveedor de PowerShell.

Split-Path

Devuelve la parte especificada de una ruta de acceso.

Resolve-Path

Resuelve los caracteres comodín en una ruta de acceso y muestra el contenido de la


ruta de acceso.

Test-Path
Este cmdlet determina si existen todos los elementos de una ruta de acceso. Para
admitir este cmdlet, sobrescriba los métodos siguientes de la clase
System.Management.Automation.Provider.ItemCmdletProvider:

ItemExists
ItemExistsDynamicParameters

Cmdlets de PSProvider

Get-PSProvider

Este cmdlet devuelve información sobre los proveedores disponibles en la sesión. No es


necesario sobrescribir ningún método para admitir este cmdlet.
Parámetros del cmdlet de proveedor
Artículo • 27/09/2021

Los cmdlets de proveedor incluyen un conjunto de parámetros estáticos que están


disponibles para todos los proveedores que admiten el cmdlet, así como parámetros
dinámicos que se agregan cuando el usuario especifica un valor determinado para
determinados parámetros estáticos del cmdlet del proveedor.

Parámetros estáticos del cmdlet provider


Los parámetros estáticos se definen mediante Windows PowerShell. Un gran conjunto
de estos parámetros se implementa mediante Windows PowerShell proporcionar
coherencia entre todos los proveedores y proporcionar una experiencia de desarrollo
más sencilla. Algunos ejemplos de estos parámetros son literalPath los parámetros , y
del cmdlet exclude include Get-Item . Se puede sobrescribir un conjunto más pequeño
de estos parámetros para proporcionar acciones específicas para el proveedor. Algunos
ejemplos de estos parámetros son Path el parámetro y del cmdlet Value Set-Item .
Esta es una lista de los parámetros que se pueden sobrescribir para los cmdlets del
proveedor.

Clear-Content Cmdlet Puede definir cómo el proveedor usará los valores pasados al

parámetro del cmdlet implementando el método Path Clear-Content


System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*.

Clear-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados al
parámetro del cmdlet implementando el método Path Clear-Item
System.Management.Automation.Provider.Itemcmdletprovider.Clearitem*.

Clear-ItemProperty Cmdlet Puede definir cómo el proveedor usará los valores pasados a

los parámetros y del cmdlet implementando el método Path Name Clear-ItemProperty


System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*.

Copy-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados a los

parámetros , y del cmdlet implementando el método Path Destination Recurse Copy-


Item System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem.

Get-ChildItems cmdlet Puede definir cómo el proveedor usará los valores pasados a los
parámetros y del cmdlet mediante la implementación de los métodos Path Recurse
Get-ChildItem
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems* y
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames*.

Get-Content Cmdlet Puede definir cómo el proveedor usará los valores pasados al

parámetro del cmdlet implementando el método Path Get-Content


System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader*.

Get-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados al

parámetro del cmdlet implementando el método Path Get-Item


System.Management.Automation.Provider.Itemcmdletprovider.Getitem*.

Get-ItemProperty Cmdlet Puede definir cómo el proveedor usará los valores pasados a
los parámetros y del cmdlet implementando el método Path Name Get-ItemProperty
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty*.

Invoke-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados al
parámetro del cmdlet implementando el método Path Invoke-Item
System.Management.Automation.Provider.Itemcmdletprovider.Invokedefaultaction*.

Move-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados a los

parámetros y del cmdlet implementando el método Path Destination Move-Item


System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*.

New-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados a los

parámetros , y del cmdlet implementando el método Path ItemType Value New-Item


System.Management.Automation.Provider.Containercmdletprovider.Newitem*.

New-ItemProperty Cmdlet Puede definir cómo el proveedor usará los valores pasados a
los parámetros , , y del cmdlet implementando el método Path Name PropertyType
Value New-ItemProperty

Microsoft.PowerShell.Commands.Registryprovider.Newproperty*.

Remove-Item Puede definir cómo el proveedor usará los valores pasados a los

parámetros y del cmdlet implementando el método Path Recurse Remove-Item


System.Management.Automation.Provider.Containercmdletprovider.Removeitem*.

Remove-ItemProperty Puede definir cómo el proveedor usará los valores pasados a los

parámetros y del cmdlet implementando el método Path Name Remove-ItemProperty


System.Management.Automation.Provider.Idynamicpropertycmdletprovider.Removepro
perty*.

Rename-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados a los

parámetros y del cmdlet implementando el método Path NewName Rename-Item


System.Management.Automation.Provider.Containercmdletprovider.Renameitem*.

Rename-ItemProperty Puede definir cómo el proveedor usará los valores pasados a los
parámetros , y del cmdlet implementando el método Path NewName Name Rename-
ItemProperty
System.Management.Automation.Provider.Idynamicpropertycmdletprovider.Renamepro
perty*.

Set-Content Cmdlet Puede definir cómo el proveedor usará los valores pasados al
parámetro del cmdlet implementando el método Path Set-Content
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*.

Set-Item Cmdlet Puede definir cómo el proveedor usará los valores pasados a los

parámetros y del cmdlet implementando el método Path Value Set-Item


System.Management.Automation.Provider.Itemcmdletprovider.Setitem*.

Set-ItemProperty Cmdlet Puede definir cómo el proveedor usará los valores pasados a

los parámetros y del cmdlet implementando el método Path Value Set-Item


System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*.

Test-Path Cmdlet Puede definir cómo el proveedor usará los valores pasados al

parámetro del cmdlet implementando el método Path Test-Path


System.Management.Automation.Provider.Itemcmdletprovider.Invokedefaultaction*.

Además, no puede especificar las características de estos parámetros, como si son


opcionales o obligatorios, ni puede dar un alias a estos parámetros ni especificar
ninguno de los atributos de validación. Por el contrario, puede especificar características
de parámetro en cmdlets independientes mediante atributos como el Parameters
atributo .

Parámetros dinámicos del cmdlet provider


Los parámetros dinámicos para los proveedores de cmdlets son similares a los
proveedores dinámicos para cmdlets independientes. En ambos casos, los parámetros
se agregan al cmdlet cuando el usuario especifica un valor determinado para uno de los
parámetros predeterminados, como el path parámetro . Sin embargo, no todos los
parámetros estáticos se pueden usar para desencadenar la adición de parámetros
dinámicos. Para obtener más información sobre los parámetros dinámicos, vea Provider
Cmdlet Dynamic Parameters.

Consulte también
Parámetros dinámicos del cmdlet provider

Escritura de un proveedor de Windows PowerShell


Parámetros dinámicos del cmdlet de
proveedor
Artículo • 24/09/2021

Los proveedores pueden definir parámetros dinámicos que se agregan a un cmdlet de


proveedor cuando el usuario especifica un valor determinado para uno de los
parámetros estáticos del cmdlet. Por ejemplo, un proveedor puede agregar parámetros
dinámicos diferentes en función de la ruta de acceso que el usuario especifica cuando
llama a los Get-Item Set-Item cmdlets del proveedor o .

Métodos de parámetros dinámicos


Los parámetros dinámicos se definen mediante la implementación de uno de los
métodos de parámetros dinámicos, como los métodos
System.Management.Automation.Provider.Itemcmdletprovider.Getitemdynamicparamet
ers* y
System.Management.Automation.Provider.Itemcmdletprovider.Setitemdynamicparamete
rs*. Estos métodos devuelven un objeto que tiene propiedades públicas que se decoran
con atributos similares a los de los cmdlets independientes. Este es un ejemplo de una
implementación del método
System.Management.Automation.Provider.Itemcmdletprovider.Getitemdynamicparamet
ers* tomado del proveedor de certificados:

C#

protected override object GetItemDynamicParameters(string path)


{
return new CertificateProviderDynamicParameters();
}

A diferencia de los parámetros estáticos de los cmdlets de proveedor, puede especificar


las características de estos parámetros de la misma manera que los parámetros se
definen en cmdlets independientes. Este es un ejemplo de una clase de parámetro
dinámico tomada del proveedor de certificados:

C#

internal sealed class CertificateProviderDynamicParameters


{
/// <summary>
/// Dynamic parameter the controls whether we only return
/// code signing certs.
/// </summary>
[Parameter()]
public SwitchParameter CodeSigningCert
{
get
{
{
return codeSigningCert;
}
}

set
{
{
codeSigningCert = value;
}
}
}

private SwitchParameter codeSigningCert = new SwitchParameter();


}

Parámetros dinámicos
Esta es una lista de los parámetros estáticos que se pueden usar para agregar
parámetros dinámicos.

Clear-Content Cmdlet Puede definir parámetros dinámicos desencadenados por el

parámetro del cmdlet Clear-Clear implementando el método Path


System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontentdynamic
parameters*.

Clear-Item Cmdlet Puede definir parámetros dinámicos desencadenados por el


parámetro del cmdlet implementando el método Path Clear-Item
System.Management.Automation.Provider.Itemcmdletprovider.Clearitemdynamicparame
ters*.

Clear-ItemProperty Cmdlet Puede definir parámetros dinámicos desencadenados por el

parámetro del cmdlet implementando el método Path Clear-ItemProperty


System.Management.Automation.Provider.Ipropertycmdletprovider.Clearpropertydynam
icparameters*.

Copy-Item Cmdlet Puede definir parámetros dinámicos desencadenados por los

parámetros , y del cmdlet implementando el método Path Destination Recurse Copy-


Item
System.Management.Automation.Provider.Containercmdletprovider.Copyitemdynamicp
arameters*.

Get-ChildItems cmdlet Puede definir parámetros dinámicos desencadenados por los


parámetros y del cmdlet implementando los métodos Path Recurse Get-ChildItem
System.Management.Automation.Provider.Containercmdletprovider.Getchilditemsdyna
micparameters* y
System.Management.Automation.Provider.Containercmdletprovider.Getchildnamesdyna
micparameters*.

Get-Content Cmdlet Puede definir parámetros dinámicos desencadenados por el


parámetro del cmdlet implementando el método Path Get-Content
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreaderdyn
amicparameters*.

Get-Item Cmdlet Puede definir parámetros dinámicos desencadenados por el parámetro

del cmdlet implementando el método Path Get-Item


System.Management.Automation.Provider.Itemcmdletprovider.Getitemdynamicparamet
ers*.

Get-ItemProperty Cmdlet Puede definir parámetros dinámicos que desencadenan los


parámetros y del cmdlet implementando el método Path Name Get-ItemProperty
System.Management.Automation.Provider.Ipropertycmdletprovider.Getpropertydynamic
parameters*.

Invoke-Item Cmdlet Puede definir parámetros dinámicos desencadenados por el


parámetro del cmdlet implementando el método Path Invoke-Item
System.Management.Automation.Provider.Itemcmdletprovider.Invokedefaultactiondyna
micparameters*.

Move-Item Cmdlet Puede definir parámetros dinámicos que desencadenan los

parámetros y del cmdlet implementando el método Path Destination Move-Item


System.Management.Automation.Provider.Navigationcmdletprovider.Moveitemdynamic
parameters*.

New-Item Cmdlet Puede definir parámetros dinámicos desencadenados por los


parámetros , y del cmdlet implementando el método Path ItemType Value New-Item
System.Management.Automation.Provider.Containercmdletprovider.Newitemdynamicpa
rameters*.

New-ItemProperty Cmdlet Puede definir parámetros dinámicos desencadenados por los

parámetros , , y del cmdlet implementando el método Path Name PropertyType Value


New-ItemProperty

System.Management.Automation.Provider.Idynamicpropertycmdletprovider.Newpropert
ydynamicparameters*.

New-PSDrive Cmdlet Puede definir parámetros dinámicos desencadenados por el objeto


System.Management.Automation.PSDriveinfo devuelto por el cmdlet implementando el
método New-PSDrive
System.Management.Automation.Provider.Drivecmdletprovider.Newdrivedynamicparam
eters*.

Remove-Item Puede definir parámetros dinámicos desencadenados por los parámetros y


del cmdlet implementando el método Path Recurse Remove-Item
System.Management.Automation.Provider.Containercmdletprovider.Removeitemdynami
cparameters*.

Remove-ItemProperty Puede definir parámetros dinámicos desencadenados por los

parámetros y del cmdlet implementando el método Path Name Remove-ItemProperty


System.Management.Automation.Provider.Idynamicpropertycmdletprovider.Removepro
pertydynamicparameters*.

Rename-Item Cmdlet Puede definir parámetros dinámicos que desencadenan los


parámetros y del cmdlet implementando el método Path NewName Rename-Item
System.Management.Automation.Provider.Containercmdletprovider.Renameitemdynami
cparameters*.

Rename-ItemProperty Puede definir parámetros dinámicos desencadenados por los


parámetros , y del cmdlet implementando el método Path Name NewName Rename-
ItemProperty

System.Management.Automation.Provider.Idynamicpropertycmdletprovider.Renamepro
pertydynamicparameters*.

Set-Content Cmdlet Puede definir parámetros dinámicos desencadenados por el


parámetro del cmdlet implementando el método Path Set-Content
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriterdyna
micparameters*.

Set-Item Cmdlet Puede definir parámetros dinámicos que desencadenan los parámetros

y del cmdlet implementando el método Path Value Set-Item


System.Management.Automation.Provider.Itemcmdletprovider.Setitemdynamicparamete
rs*.
Set-ItemProperty Cmdlet Puede definir parámetros dinámicos que desencadenan los

parámetros y del cmdlet implementando el método Path Value Set-Item


System.Management.Automation.Provider.Ipropertycmdletprovider.Setpropertydynamic
parameters*.

Test-Path Cmdlet Puede definir parámetros dinámicos desencadenados por el

parámetro del cmdlet implementando el método Path Test-Path


System.Management.Automation.Provider.Itemcmdletprovider.Invokedefaultactiondyna
micparameters*.

Consulte también
Escritura de un proveedor de Windows PowerShell
Escritura de un proveedor de elementos
Artículo • 27/09/2021

En este tema se describe cómo implementar los métodos de un proveedor de Windows


PowerShell que acceden y manipulan elementos del almacén de datos. Para poder
acceder a los elementos, un proveedor debe derivar de la clase
System.Management.Automation.Provider.Itemcmdletprovider.

El proveedor de los ejemplos de este tema usa una base de datos de Access como su
almacén de datos. Hay varios métodos auxiliares y clases que se usan para interactuar
con la base de datos. Para obtener el ejemplo completo que incluye los métodos
auxiliares, vea AccessDBProviderSample03.

Para obtener más información sobre los Windows PowerShell, vea Información general
Windows PowerShell proveedores de servicios.

Implementación de métodos de elemento


La clase System.Management.Automation.Provider.Itemcmdletprovider expone varios
métodos que se pueden usar para tener acceso a los elementos de un almacén de datos
y manipularlos. Para obtener una lista completa de estos métodos, vea Métodos
ItemCmdletProvider. En este ejemplo, implementaremos cuatro de estos métodos.
System.Management.Automation.Provider.Itemcmdletprovider.Getitem* obtiene un
elemento en una ruta de acceso especificada.
System.Management.Automation.Provider.Itemcmdletprovider.Setitem* establece el
valor del elemento especificado.
System.Management.Automation.Provider.Itemcmdletprovider.Itemexists* comprueba si
existe un elemento en la ruta de acceso especificada.
System.Management.Automation.Provider.Itemcmdletprovider.Isvalidpath* comprueba
una ruta de acceso para ver si se asigna a una ubicación del almacén de datos.

7 Nota

Este tema se basa en la información de inicio rápido Windows PowerShell


proveedor de aplicaciones. En este tema no se cubren los conceptos básicos de
cómo configurar un proyecto de proveedor ni cómo implementar los métodos
heredados de la clase
System.Management.Automation.Provider.Drivecmdletprovider que crean y
quitan unidades.
Declaración de la clase de proveedor
Declare el proveedor para derivar de la clase
System.Management.Automation.Provider.Itemcmdletprovider y decorelo con el
atributo System.Management.Automation.Provider.Cmdletprovider .

C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]

public class AccessDBProvider : ItemCmdletProvider


{

Implementación de GetItem
El motor de PowerShell llama a
System.Management.Automation.Provider.Itemcmdletprovider.Getitem* cuando un
usuario llama al cmdlet Microsoft.PowerShell.Commands.GetItemCommand del
proveedor. El método devuelve el elemento en la ruta de acceso especificada. En el
ejemplo de base de datos de Access, el método comprueba si el elemento es la propia
unidad, una tabla de la base de datos o una fila de la base de datos. El método envía el
elemento al motor de PowerShell llamando al método
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject*.

C#

protected override void GetItem(string path)


{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

Implementación de SetItem
El motor de PowerShell llama al método
System.Management.Automation.Provider.Itemcmdletprovider.Setitem* cuando un
usuario llama al cmdlet Microsoft.PowerShell.Commands.SetItemCommand. Establece el
valor del elemento en la ruta de acceso especificada.

En el ejemplo de base de datos de Access, tiene sentido establecer el valor de un


elemento solo si ese elemento es una fila, por lo que el método produce
NotSupportedException cuando el elemento no es una fila.

C#

protected override void SetItem(string path, object values)


{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}

// Get in-memory representation of table


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

Implementar ItemExists
El motor de PowerShell llama al método
System.Management.Automation.Provider.Itemcmdletprovider.Itemexists* cuando un
usuario llama al cmdlet Microsoft.PowerShell.Commands.TestPathCommand. El método
determina si hay un elemento en la ruta de acceso especificada. Si el elemento existe, el
método lo devuelve al motor de PowerShell llamando a
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject*.

C#

protected override bool ItemExists(string path)


{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

Implementación de IsValidPath
El método System.Management.Automation.Provider.Itemcmdletprovider.Isvalidpath*
comprueba si la ruta de acceso especificada es válida sintácticamente para el proveedor
actual. No comprueba si existe un elemento en la ruta de acceso.

C#

protected override bool IsValidPath(string path)


{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
}

Pasos siguientes
Un proveedor típico del mundo real es capaz de admitir elementos que contienen otros
elementos y de mover elementos de una ruta de acceso a otra dentro de la unidad. Para
obtener un ejemplo de un proveedor que admite contenedores, vea Escribir un
proveedor de contenedores. Para obtener un ejemplo de un proveedor que admite el
movimiento de elementos, vea Escribir un proveedor de navegación.

Consulte también
Escritura de un proveedor de contenedores

Escritura de un proveedor de navegación

Información general sobre Proveedor de Windows PowerShell


Escritura de un proveedor de
contenedores
Artículo • 27/09/2021

En este tema se describe cómo implementar los métodos de un proveedor de Windows


PowerShell que admiten elementos que contienen otros elementos, como carpetas en el
proveedor del sistema de archivos. Para poder admitir contenedores, un proveedor
debe derivar de la clase
System.Management.Automation.Provider.Containercmdletprovider.

El proveedor de los ejemplos de este tema usa una base de datos de Access como su
almacén de datos. Hay varios métodos auxiliares y clases que se usan para interactuar
con la base de datos. Para obtener el ejemplo completo que incluye los métodos
auxiliares, vea AccessDBProviderSample04.

Para obtener más información sobre los Windows PowerShell, vea Información general
Windows PowerShell proveedores de servicios.

Implementación de métodos de contenedor


La clase System.Management.Automation.Provider.Containercmdletprovider
implementa métodos que admiten contenedores y crean, copian y quitan elementos.
Para obtener una lista completa de estos métodos, vea
System.Management.Automation.Provider.ContainerCmdletProvider.

7 Nota

Este tema se basa en la información de inicio rápido Windows PowerShell


proveedor de aplicaciones. En este tema no se cubren los conceptos básicos de
cómo configurar un proyecto de proveedor ni cómo implementar los métodos
heredados de la clase
System.Management.Automation.Provider.Drivecmdletprovider que crean y
quitan unidades. En este tema tampoco se explica cómo implementar métodos
expuestos por la clase
System.Management.Automation.Provider.Itemcmdletprovider. Para obtener un
ejemplo en el que se muestra cómo implementar cmdlets de elementos, vea
Escribir un proveedor de elementos.
Declaración de la clase de proveedor
Declare el proveedor para derivar de la clase
System.Management.Automation.Provider.Containercmdletprovider y decore con el
atributo System.Management.Automation.Provider.Cmdletprovider .

C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : ContainerCmdletProvider
{

Implementación de GetChildItems
El motor de PowerShell llama al método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
cuando un usuario llama al cmdlet
Microsoft.PowerShell.Commands.GetChildItemCommand. Este método obtiene los
elementos que son los elementos secundarios del elemento en la ruta de acceso
especificada.

En el ejemplo de base de datos de Access, el comportamiento del método


System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
depende del tipo del elemento especificado. Si el elemento es la unidad, los elementos
secundarios son tablas y el método devuelve el conjunto de tablas de la base de datos.
Si el elemento especificado es una tabla, los elementos secundarios son las filas de esa
tabla. Si el elemento es una fila, no tiene elementos secundarios y el método devuelve
solo esa fila. Todos los elementos secundarios se devuelven al motor de PowerShell
mediante el método
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject*.

C#

protected override void GetChildItems(string path, bool recurse)


{
// If path represented is a drive then the children in the path
are
// tables. Hence all tables in the drive represented will have to
be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set


then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name,
recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
}

Implementación de GetChildNames
El método
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames* es
similar al método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*,
salvo que devuelve solo la propiedad name de los elementos y no los propios
elementos.

C#

protected override void GetChildNames(string path,


ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);

WriteItemObject(row.RowNumber, path, false);


}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
}

Implementación de NewItem
El método
System.Management.Automation.Provider.Containercmdletprovider.Newitem* crea un
nuevo elemento del tipo especificado en la ruta de acceso especificada. El motor de
PowerShell llama a este método cuando un usuario llama al cmdlet
Microsoft.PowerShell.Commands.NewItemCommand.

En este ejemplo, el método implementa lógica para determinar que la ruta de acceso y
el tipo coinciden. Es decir, solo se puede crear una tabla directamente en la unidad (la
base de datos) y solo se puede crear una fila debajo de una tabla. Si la ruta de acceso y
el tipo de elemento especificados no coinciden de esta manera, el método produce una
excepción.

C#

protected override void NewItem(string path, string type,


object newItemValue)
{
string tableName;
int rowNumber;

PathType pt = GetNamesFromPath(path, out tableName, out


rowNumber);

if (pt == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

// Check if type is either "table" or "row", if not throw an


// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
&& !String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
WriteError(new ErrorRecord
(new ArgumentException("Type must be either
a table or row"),
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
)
);
throw new ArgumentException("This provider can only create
items of type \"table\" or \"row\"");
}

// Path type is the type of path of the container. So if a drive


// is specified, then a table can be created under it and if a
table
// is specified, then a row can be created under it. For the sake
of
// completeness, if a row is specified, then if the row specified
by
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
// on the number of rows

if (PathIsDrive(path))
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
// Execute command using ODBC connection to create a
table
try
{
// create the table using an sql statement
string newTableName = newItemValue.ToString();

if (!TableNameIsValid(newTableName))
{
return;
}
string sql = "create table " + newTableName
+ " (ID INT)";

// Create the table using the Odbc connection from


the
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

if (ShouldProcess(newTableName, "create"))
{
OdbcCommand cmd = new OdbcCommand(sql,
connection);
cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
}
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
throw new
ArgumentException("A row cannot be created under a
database, specify a path that represents a Table");
}
}// if (PathIsDrive...
else
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
if (rowNumber < 0)
{
throw new
ArgumentException("A table cannot be created
within another table, specify a path that represents a database");
}
else
{
throw new
ArgumentException("A table cannot be created
inside a row, specify a path that represents a database");
}
} //if (String.Equals....
// if path specified is a row, create a new row
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
// The user is required to specify the values to be
inserted
// into the table in a single string separated by commas
string value = newItemValue as string;

if (String.IsNullOrEmpty(value))
{
throw new
ArgumentException("Value argument must have comma
separated values of each column in a row");
}
string[] rowValues = value.Split(',');

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

if (rowValues.Length != table.Columns.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The table has {0} columns and
the value specified must have so many comma separated values",
table.Columns.Count);

throw new ArgumentException(message);


}

if (!Force && (rowNumber >=0 && rowNumber <


table.Rows.Count))
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The row {0} already
exists. To create a new row specify row number as {1}, or specify path to a
table, or use the -Force parameter",
rowNumber,
table.Rows.Count);

throw new ArgumentException(message);


}

if (rowNumber > table.Rows.Count)


{
string message =
String.Format(CultureInfo.CurrentCulture,
"To create a new row specify row
number as {0}, or specify path to a table",
table.Rows.Count);

throw new ArgumentException(message);


}

// Create a new row and update the row with the input
// provided by the user
DataRow row = table.NewRow();
for (int i = 0; i < rowValues.Length; i++)
{
row[i] = rowValues[i];
}
table.Rows.Add(row);

if (ShouldProcess(tableName, "update rows"))


{
// Update the table from memory back to the data
source
da.Update(ds, tableName);
}

}// else if (String...


}// else ...

Implementación de CopyItem
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem copia el
elemento especificado en la ruta de acceso especificada. El motor de PowerShell llama a
este método cuando un usuario llama al cmdlet
Microsoft.PowerShell.Commands.CopyItemCommand. Este método también puede ser
recursivo, copiando todos los elementos secundarios además del propio elemento.

De forma similar al método


System.Management.Automation.Provider.Containercmdletprovider.Newitem*, este
método realiza lógica para asegurarse de que el elemento especificado es del tipo
correcto para la ruta de acceso a la que se copia. Por ejemplo, si la ruta de acceso de
destino es una tabla, el elemento que se va a copiar debe ser una fila.

C#

protected override void CopyItem(string path, string copyPath, bool recurse)


{
string tableName, copyTableName;
int rowNumber, copyRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
PathType copyType = GetNamesFromPath(copyPath, out copyTableName,
out copyRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(copyPath);
}

// Get the table and the table to copy to


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter cda = GetAdapterForTable(copyTableName);


if (cda == null)
{
return;
}

DataSet cds = GetDataSetForTable(cda, copyTableName);


DataTable copyTable = GetDataTable(cds, copyTableName);

// if source represents a table


if (type == PathType.Table)
{
// if copyPath does not represent a table
if (copyType != PathType.Table)
{
ArgumentException e = new ArgumentException("Table can
only be copied on to another table location");

WriteError(new ErrorRecord(e, "PathNotValid",


ErrorCategory.InvalidArgument, copyPath));

throw e;
}

// if table already exists then force parameter should be set


// to force a copy
if (!Force && GetTable(copyTableName) != null)
{
throw new ArgumentException("Specified path already
exists");
}

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];
DataRow copyRow = copyTable.NewRow();

copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
}
} // if (type == ...
// if source represents a row
else
{
if (copyType == PathType.Row)
{
if (!Force && (copyRowNumber < copyTable.Rows.Count))
{
throw new ArgumentException("Specified path already
exists.");
}

DataRow row = table.Rows[rowNumber];


DataRow copyRow = null;

if (copyRowNumber < copyTable.Rows.Count)


{
// copy to an existing row
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
}
else if (copyRowNumber == copyTable.Rows.Count)
{
// copy to the next row in the table that will
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
else
{
// attempting to copy to a nonexistent row or a row
// that cannot be created now - throw an exception
string message =
String.Format(CultureInfo.CurrentCulture,
"The item cannot be specified
to the copied row. Specify row number as {0}, or specify a path to the
table.",
table.Rows.Count);

throw new ArgumentException(message);


}
}
else
{
// destination path specified represents a table,
// create a new row and copy the item
DataRow copyRow = copyTable.NewRow();
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
}

if (ShouldProcess(copyTableName, "CopyItems"))
{
cda.Update(cds, copyTableName);
}

} //CopyItem
Implementación de RemoveItem
El método
System.Management.Automation.Provider.Containercmdletprovider.Removeitem* quita
el elemento en la ruta de acceso especificada. El motor de PowerShell llama a este
método cuando un usuario llama al cmdlet
Microsoft.PowerShell.Commands.RemoveItemCommand.

C#

protected override void RemoveItem(string path, bool recurse)


{
string tableName;
int rowNumber = 0;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// if recurse flag has been specified, delete all the rows as
well
if (recurse)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

for (int i = 0; i < table.Rows.Count; i++)


{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
RemoveTable(tableName);
}
}//if (recurse...
else
{
// Remove the table
if (ShouldProcess(path, "RemoveItem"))
{
RemoveTable(tableName);
}
}
}
else if (type == PathType.Row)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

table.Rows[rowNumber].Delete();

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
}
}
else
{
ThrowTerminatingInvalidPathException(path);
}

Pasos siguientes
Un proveedor típico del mundo real es capaz de mover elementos de una ruta de
acceso a otra dentro de la unidad. Para obtener un ejemplo de un proveedor que
admite el movimiento de elementos, vea Escribir un proveedor de navegación.

Consulte también
Escritura de un proveedor de navegación

Información general sobre Proveedor de Windows PowerShell


Escritura de un proveedor de
navegación
Artículo • 24/09/2021

En este tema se describe cómo implementar los métodos de un proveedor de Windows


PowerShell que admite contenedores anidados (almacenes de datos de varios niveles),
mover elementos y rutas de acceso relativas. Un proveedor de navegación debe derivar
de la clase System.Management.Automation.Provider.Navigationcmdletprovider.

El proveedor de los ejemplos de este tema usa una base de datos de Access como su
almacén de datos. Hay varios métodos auxiliares y clases que se usan para interactuar
con la base de datos. Para obtener el ejemplo completo que incluye los métodos
auxiliares, vea AccessDBProviderSample05.

Para obtener más información sobre los Windows PowerShell, vea Información general
Windows PowerShell proveedores de servicios.

Implementación de métodos de navegación


La clase System.Management.Automation.Provider.Navigationcmdletprovider
implementa métodos que admiten contenedores anidados, rutas de acceso relativas y
elementos móviles. Para obtener una lista completa de estos métodos, vea Métodos
NavigationCmdletProvider.

7 Nota

Este tema se basa en la información de inicio rápido Windows PowerShell


proveedor de aplicaciones. En este tema no se cubren los conceptos básicos de
cómo configurar un proyecto de proveedor ni cómo implementar los métodos
heredados de la clase
System.Management.Automation.Provider.Drivecmdletprovider que crean y
quitan unidades. En este tema tampoco se explica cómo implementar métodos
expuestos por las clases
System.Management.Automation.Provider.Itemcmdletprovider o
System.Management.Automation.Provider.Containercmdletprovider. Para obtener
un ejemplo en el que se muestra cómo implementar cmdlets de elementos, vea
Escribir un proveedor de elementos. Para obtener un ejemplo en el que se
muestra cómo implementar cmdlets de contenedor, consulte Escritura de un
proveedor de contenedores.
Declaración de la clase de proveedor
Declare el proveedor para derivar de la clase
System.Management.Automation.Provider.Navigationcmdletprovider y decorelo con el
atributo System.Management.Automation.Provider.Cmdletproviderattribute.

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider
{

Implementación de IsItemContainer
El método
System.Management.Automation.Provider.Navigationcmdletprovider.Isitemcontainer*
comprueba si el elemento de la ruta de acceso especificada es un contenedor.

C#

protected override bool IsItemContainer(string path)


{
if (PathIsDrive(path))
{
return true;
}

string[] pathChunks = ChunkPath(path);


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...
return false;
}

Implementación de GetChildName
El método
System.Management.Automation.Provider.Navigationcmdletprovider.Getchildname*
obtiene la propiedad name del elemento secundario en la ruta de acceso especificada.
Si el elemento de la ruta de acceso especificada no es un elemento secundario de un
contenedor, este método debe devolver la ruta de acceso.

C#

protected override string GetChildName(string path)


{
if (PathIsDrive(path))
{
return path;
}

string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
return tableName;
}
else if (type == PathType.Row)
{
return rowNumber.ToString(CultureInfo.CurrentCulture);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

return null;
}

Implementación de GetParentPath
El método
System.Management.Automation.Provider.Navigationcmdletprovider.Getparentpath*
obtiene la ruta de acceso del elemento primario del elemento en la ruta de acceso
especificada. Si el elemento de la ruta de acceso especificada es la raíz del almacén de
datos (por lo que no tiene ningún elemento primario), este método debe devolver la
ruta de acceso raíz.

C#

protected override string GetParentPath(string path, string root)


{
// If root is specified then the path has to contain
// the root. If not nothing should be returned
if (!String.IsNullOrEmpty(root))
{
if (!path.Contains(root))
{
return null;
}
}

return path.Substring(0, path.LastIndexOf(pathSeparator,


StringComparison.OrdinalIgnoreCase));
}

Implementación de MakePath
El método
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath* une
una ruta de acceso primaria especificada y una ruta de acceso secundaria especificada
para crear una ruta de acceso interna del proveedor (para obtener información sobre los
tipos de ruta de acceso que los proveedores pueden admitir, vea información general
del proveedor de Windows PowerShell. El motor de PowerShell llama a este método
cuando un usuario llama al cmdlet Microsoft.PowerShell.Commands.JoinPathCommand.

C#

protected override string MakePath(string parent, string child)


{
string result;

string normalParent = NormalizePath(parent);


normalParent = RemoveDriveFromPath(normalParent);
string normalChild = NormalizePath(child);
normalChild = RemoveDriveFromPath(normalChild);

if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
result = String.Empty;
}
else if (String.IsNullOrEmpty(normalParent) &&
!String.IsNullOrEmpty(normalChild))
{
result = normalChild;
}
else if (!String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent;
}
else
{
result = normalParent + pathSeparator;
}
} // else if (!String...
else
{
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent + pathSeparator;
}
else
{
result = normalParent;
}

if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result += normalChild.Substring(1);
}
else
{
result += normalChild;
}
} // else

return result;
}

Implementación de NormalizeRelativePath
El método
System.Management.Automation.Provider.Navigationcmdletprovider.Normalizerelativep
ath* toma los parámetros y , y devuelve una ruta de acceso normalizada equivalente al
parámetro y relativa al path basepath parámetro path basepath .
C#

protected override string NormalizeRelativePath(string path,


string basepath)
{
// Normalize the paths first
string normalPath = NormalizePath(path);
normalPath = RemoveDriveFromPath(normalPath);
string normalBasePath = NormalizePath(basepath);
normalBasePath = RemoveDriveFromPath(normalBasePath);

if (String.IsNullOrEmpty(normalBasePath))
{
return normalPath;
}
else
{
if (!normalPath.Contains(normalBasePath))
{
return null;
}

return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
}
}

Implementación de MoveItem
El método
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem* mueve
un elemento de la ruta de acceso especificada a la ruta de acceso de destino
especificada. El motor de PowerShell llama a este método cuando un usuario llama al
cmdlet Microsoft.PowerShell.Commands.MoveItemCommand.

C#

protected override void MoveItem(string path, string destination)


{
// Get type, table name and rowNumber from the path
string tableName, destTableName;
int rowNumber, destRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

PathType destType = GetNamesFromPath(destination, out


destTableName,
out destRowNumber);
if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (destType == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(destination);
}

if (type == PathType.Table)
{
ArgumentException e = new ArgumentException("Move not
supported for tables");

WriteError(new ErrorRecord(e, "MoveNotSupported",


ErrorCategory.InvalidArgument, path));

throw e;
}
else
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter dda = GetAdapterForTable(destTableName);


if (dda == null)
{
return;
}

DataSet dds = GetDataSetForTable(dda, destTableName);


DataTable destTable = GetDataTable(dds, destTableName);
DataRow row = table.Rows[rowNumber];

if (destType == PathType.Table)
{
DataRow destRow = destTable.NewRow();

destRow.ItemArray = row.ItemArray;
}
else
{
DataRow destRow = destTable.Rows[destRowNumber];

destRow.ItemArray = row.ItemArray;
}

// Update the changes


if (ShouldProcess(path, "MoveItem"))
{
WriteItemObject(row, path, false);
dda.Update(dds, destTableName);
}
}
}

Consulte también
Escritura de un proveedor de contenedores

Información general sobre Proveedor de Windows PowerShell


Ejemplos de proveedor
Artículo • 27/09/2021

En esta sección se incluyen ejemplos de proveedores que acceden a una base de datos
de Microsoft Access. Estos ejemplos incluyen clases de proveedor que derivan de todas
las clases de proveedor base.

En esta sección
Esta sección contiene los siguientes temas:

Ejemplo AccessDBProviderSample01 En este ejemplo se muestra cómo declarar la clase


de proveedor que se deriva directamente de la clase
System.Management.Automation.Provider.Cmdletprovider. Se incluye aquí solo por
cuestiones de integridad.

AccessDBProviderSample02 En este ejemplo se muestra cómo sobrescribir los métodos


System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* y
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* para
admitir llamadas a New-PSDrive los Remove-PSDrive cmdlets y . La clase de proveedor de
este ejemplo se deriva de la clase
System.Management.Automation.Provider.Drivecmdletprovider.

AccessDBProviderSample03 En este ejemplo se muestra cómo sobrescribir los métodos


System.Management.Automation.Provider.Itemcmdletprovider.Getitem* y
System.Management.Automation.Provider.Itemcmdletprovider.Setitem* para admitir
llamadas a Get-Item los Set-Item cmdlets y . La clase de proveedor de este ejemplo se
deriva de la clase System.Management.Automation.Provider.Itemcmdletprovider.

AccessDBProviderSample04 En este ejemplo se muestra cómo sobrescribir métodos de


contenedor para admitir llamadas a los Copy-Item Get-ChildItem New-Item cmdlets , ,
Remove-Item y . Estos métodos deberían implementarse cuando el almacén de datos
contengan elementos que son contenedores. Un contenedor es un grupo de elementos
secundarios con un elemento primario común. La clase de proveedor de este ejemplo se
deriva de la clase System.Management.Automation.Provider.Containercmdletprovider.

AccessDBProviderSample05 En este ejemplo se muestra cómo sobrescribir métodos de


contenedor para admitir llamadas a los Move-Item Join-Path cmdlets y . Estos métodos
deberían implementarse cuando el usuario necesite mover elementos dentro de un
contenedor y si el almacén de datos tiene contenedores anidados. La clase de
proveedor de este ejemplo se deriva de la clase
System.Management.Automation.Provider.Navigationcmdletprovider.

AccessDBProviderSample06 En este ejemplo se muestra cómo sobrescribir métodos de


contenido para admitir llamadas a los Clear-Content Get-Content cmdlets , Set-Content
y . Estos métodos deberían implementarse cuando el usuario necesite administrar el
contenido de los elementos en el almacén de datos. La clase de proveedor de este
ejemplo se deriva de la clase
System.Management.Automation.Provider.Navigationcmdletprovider e implementa la
interfaz System.Management.Automation.Provider.Icontentcmdletprovider.

Consulte también
Escritura de un proveedor de Windows PowerShell
AccessDBProviderSample01
Artículo • 24/09/2021

En este ejemplo se muestra cómo declarar una clase de proveedor que se deriva
directamente de la clase System.Management.Automation.Provider.Cmdletprovider. Se
incluye aquí solo por cuestiones de integridad.

Muestra

) Importante

Lo más probable es que la clase de proveedor derive de una de las siguientes


clases y posiblemente implemente otras interfaces de proveedor:

Clase System.Management.Automation.Provider.Itemcmdletprovider. Vea


AccessDBProviderSample03.
Clase System.Management.Automation.Provider.Containercmdletprovider.
Vea AccessDBProviderSample04.
Clase System.Management.Automation.Provider.Navigationcmdletprovider.
Vea AccessDBProviderSample05.

Para obtener más información sobre cómo elegir de qué clase de proveedor derivar
en función de las características del proveedor, vea Designing Your Windows
PowerShell Provider.

En este ejemplo se muestra lo siguiente:

Declarar el CmdletProvider atributo.

Definición de una clase de proveedor que se deriva directamente de la clase


System.Management.Automation.Provider.Cmdletprovider.

Ejemplo
En este ejemplo se muestra cómo definir una clase de proveedor y cómo declarar el
CmdletProvider atributo.

C#
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// Simple provider.
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : CmdletProvider
{

#endregion AccessDBProvider
}

Consulte también
System.Management.Automation.Provider.Itemcmdletprovider

System.Management.Automation.Provider.Containercmdletprovider

System.Management.Automation.Provider.Navigationcmdletprovider

Diseño del proveedor de Windows PowerShell


AccessDBProviderSample02
Artículo • 27/09/2021

En este ejemplo se muestra cómo sobrescribir los métodos


System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* y
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* para
admitir llamadas a New-PSDrive los Remove-PSDrive cmdlets y . La clase de proveedor de
este ejemplo se deriva de la clase
System.Management.Automation.Provider.Drivecmdletprovider.

Muestra

) Importante

Lo más probable es que la clase de proveedor derive de una de las siguientes


clases y posiblemente implemente otras interfaces de proveedor:

Clase System.Management.Automation.Provider.Itemcmdletprovider. Vea


AccessDBProviderSample03.
Clase System.Management.Automation.Provider.Containercmdletprovider.
Vea AccessDBProviderSample04.
Clase System.Management.Automation.Provider.Navigationcmdletprovider.
Vea AccessDBProviderSample05.

Para obtener más información sobre cómo elegir de qué clase de proveedor derivar
en función de las características del proveedor, vea Designing Your Windows
PowerShell Provider.

En este ejemplo se muestra lo siguiente:

Declarar el CmdletProvider atributo.

Definir una clase de proveedor que unidades de la clase


System.Management.Automation.Provider.Drivecmdletprovider.

Sobrescriba el método
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* para
admitir la creación de nuevas unidades. (En este ejemplo no se muestra cómo
agregar parámetros dinámicos al New-PSDrive cmdlet).
Sobrescriba el método
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* para
admitir la eliminación de unidades existentes.

Ejemplo
En este ejemplo se muestra cómo sobrescribir los métodos
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* y
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive*. Para este
proveedor de ejemplo, cuando se crea una unidad, la información de conexión se
almacena en un AccessDBPsDriveInfo objeto .

C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// A PowerShell Provider which acts upon a access data store.
/// </summary>
/// <remarks>
/// This example only demonstrates the drive overrides
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : DriveCmdletProvider
{
#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

} // AccessDBProvider

#endregion AccessDBProvider

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo
}

Consulte también
System.Management.Automation.Provider.Itemcmdletprovider

System.Management.Automation.Provider.Containercmdletprovider

System.Management.Automation.Provider.Navigationcmdletprovider

Diseño del proveedor de Windows PowerShell


AccessDBProviderSample03
Artículo • 24/09/2021

En este ejemplo se muestra cómo sobrescribir los métodos


System.Management.Automation.Provider.Itemcmdletprovider.Getitem* y
System.Management.Automation.Provider.Itemcmdletprovider.Setitem* para admitir
llamadas a Get-Item los Set-Item cmdlets y . La clase de proveedor de este ejemplo se
deriva de la clase System.Management.Automation.Provider.Itemcmdletprovider.

Muestra

) Importante

Lo más probable es que la clase de proveedor derive de una de las siguientes


clases y posiblemente implemente otras interfaces de proveedor:

Clase System.Management.Automation.Provider.Itemcmdletprovider.
Clase System.Management.Automation.Provider.Containercmdletprovider.
Vea AccessDBProviderSample04.
Clase System.Management.Automation.Provider.Navigationcmdletprovider.
Vea AccessDBProviderSample05.

Para obtener más información sobre cómo elegir de qué clase de proveedor derivar
en función de las características del proveedor, vea Designing Your Windows
PowerShell Provider.

En este ejemplo se muestra lo siguiente:

Declarar el CmdletProvider atributo.


Definir una clase de proveedor que deriva de la clase
System.Management.Automation.Provider.Itemcmdletprovider.
Sobrescribir el método
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* para
cambiar el comportamiento del cmdlet, lo que permite al usuario crear nuevas
New-PSDrive unidades. (En este ejemplo no se muestra cómo agregar parámetros
dinámicos al New-PSDrive cmdlet).
Sobrescriba el método
System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* para
admitir la eliminación de unidades existentes.
Sobrescribir el método
System.Management.Automation.Provider.Itemcmdletprovider.Getitem* para
cambiar el comportamiento del cmdlet, lo que permite al usuario recuperar
elementos del almacén Get-Item de datos. (En este ejemplo no se muestra cómo
agregar parámetros dinámicos al Get-Item cmdlet).
Sobrescribir el método
System.Management.Automation.Provider.Itemcmdletprovider.Setitem* para
cambiar el comportamiento del cmdlet, lo que permite al usuario actualizar los
elementos del almacén de Set-Item datos. (En este ejemplo no se muestra cómo
agregar parámetros dinámicos al Get-Item cmdlet).
Sobrescribir el método
System.Management.Automation.Provider.Itemcmdletprovider.Itemexists* para
cambiar el comportamiento del Test-Path cmdlet. (En este ejemplo no se muestra
cómo agregar parámetros dinámicos al Test-Path cmdlet).
Sobrescriba el método
System.Management.Automation.Provider.Itemcmdletprovider.Isvalidpath* para
determinar si la ruta de acceso proporcionada es válida.

Ejemplo
En este ejemplo se muestra cómo sobrescribir los métodos necesarios para obtener y
establecer elementos en una base de datos de Microsoft Access.

C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Collections.ObjectModel;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// A PowerShell Provider which acts upon a access database.
/// </summary>
/// <remarks>
/// This example implements the item overloads.
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]

public class AccessDBProvider : ItemCmdletProvider


{
#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();
builder.Driver = "Microsoft Access Driver (*.mdb)";
builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}
// Get in-memory representation of table
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads

#region Helper Methods

/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");

return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath

/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;

if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the path</param>
/// <returns>what the path represents</returns>
private PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;

default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath

/// <summary>
/// Throws an argument exception stating that the specified path does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object representing
/// information about one database table
/// </returns>
private Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;

// iterate through all rows in the schema and create


DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName + "\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count, columns);
results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables

/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
private Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;

} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
private OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName) ||


!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create sql


// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
private DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);

// Create a dataset object which will provide an in-memory


// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
private DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // SafeConvertRowNumber

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

#endregion Helper Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

private enum PathType { Database, Table, Row, Invalid };

#endregion Private Properties


}

#endregion AccessDBProvider

#region Helper Classes

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#endregion Helper Classes


}

Consulte también
System.Management.Automation.Provider.Itemcmdletprovider

System.Management.Automation.Provider.Containercmdletprovider

System.Management.Automation.Provider.Navigationcmdletprovider
Diseño del proveedor de Windows PowerShell
AccessDBProviderSample04
Artículo • 27/09/2021

En este ejemplo se muestra cómo sobrescribir métodos de contenedor para admitir


llamadas a los Copy-Item Get-ChildItem New-Item cmdlets , , Remove-Item y . Estos
métodos deberían implementarse cuando el almacén de datos contengan elementos
que son contenedores. Un contenedor es un grupo de elementos secundarios con un
elemento primario común. La clase de proveedor de este ejemplo se deriva de la clase
System.Management.Automation.Provider.Containercmdletprovider.

Muestra

) Importante

Lo más probable es que la clase de proveedor derive de


System.Management.Automation.Provider.Navigationcmdletprovider.

En este ejemplo se muestra lo siguiente:

Declarar el CmdletProvider atributo.


Definir una clase de proveedor que deriva de la clase
System.Management.Automation.Provider.Containercmdletprovider.
Sobrescriba el método
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
para cambiar el comportamiento del cmdlet que permite al usuario copiar
elementos de una ubicación a Copy-Item otra. (En este ejemplo no se muestra
cómo agregar parámetros dinámicos al Copy-Item cmdlet).
Sobrescribir el método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
para cambiar el comportamiento del cmdlet Get-ChildItems, que permite al
usuario recuperar los elementos secundarios del elemento primario. (En este
ejemplo no se muestra cómo agregar parámetros dinámicos al cmdlet Get-
ChildItems).
Sobrescribir el método
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames
* para cambiar el comportamiento del cmdlet Get-ChildItems cuando se especifica
el parámetro del Name cmdlet .
Sobrescribir el método
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
para cambiar el comportamiento del cmdlet, lo que permite al usuario agregar
elementos al almacén New-Item de datos. (En este ejemplo no se muestra cómo
agregar parámetros dinámicos al New-Item cmdlet).
Sobrescribir el método
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
para cambiar el comportamiento del Remove-Item cmdlet. (En este ejemplo no se
muestra cómo agregar parámetros dinámicos al Remove-Item cmdlet).

Ejemplo
En este ejemplo se muestra cómo sobrescribir los métodos necesarios para copiar, crear
y quitar elementos, así como métodos para obtener los elementos secundarios de un
elemento primario.

C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// A PowerShell Provider which acts upon an Access database
/// </summary>
/// <remarks>
/// This example implements the container overloads</remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : ContainerCmdletProvider
{

#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive
/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out
rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}

// Get in-memory representation of table


OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);
if (rowNumber >= table.Rows.Count)
{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads

#region Container Overloads


/// <summary>
/// Return either the tables in the database or the datarows
/// </summary>
/// <param name="path">The path to the parent</param>
/// <param name="recurse">True to return all child items recursively.
/// </param>
protected override void GetChildItems(string path, bool recurse)
{
// If path represented is a drive then the children in the path
are
// tables. Hence all tables in the drive represented will have to
be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set


then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name,
recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildItems

/// <summary>
/// Return the names of all child items.
/// </summary>
/// <param name="path">The root path.</param>
/// <param name="returnContainers">Not used.</param>
protected override void GetChildNames(string path,
ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);

WriteItemObject(row.RowNumber, path, false);


}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildNames

/// <summary>
/// Determines if the specified path has child items.
/// </summary>
/// <param name="path">The path to examine.</param>
/// <returns>
/// True if the specified path has child items.
/// </returns>
protected override bool HasChildItems(string path)
{
if (PathIsDrive(path))
{
return true;
}

return (ChunkPath(path).Length == 1);


} // HasChildItems

/// <summary>
/// Creates a new item at the specified path.
/// </summary>
///
/// <param name="path">
/// The path to the new item.
/// </param>
///
/// <param name="type">
/// Type for the object to create. "Table" for creating a new table
and
/// "Row" for creating a new row in a table.
/// </param>
///
/// <param name="newItemValue">
/// Object for creating new instance of a type at the specified path.
For
/// creating a "Table" the object parameter is ignored and for
creating
/// a "Row" the object must be of type string which will contain
comma
/// separated values of the rows to insert.
/// </param>
protected override void NewItem(string path, string type,
object newItemValue)
{
string tableName;
int rowNumber;

PathType pt = GetNamesFromPath(path, out tableName, out


rowNumber);

if (pt == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

// Check if type is either "table" or "row", if not throw an


// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
&& !String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
WriteError(new ErrorRecord
(new ArgumentException("Type must be either
a table or row"),
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
)
);

throw new ArgumentException("This provider can only create


items of type \"table\" or \"row\"");
}

// Path type is the type of path of the container. So if a drive


// is specified, then a table can be created under it and if a
table
// is specified, then a row can be created under it. For the sake
of
// completeness, if a row is specified, then if the row specified
by
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
// on the number of rows

if (PathIsDrive(path))
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
// Execute command using ODBC connection to create a
table
try
{
// create the table using an sql statement
string newTableName = newItemValue.ToString();

if (!TableNameIsValid(newTableName))
{
return;
}
string sql = "create table " + newTableName
+ " (ID INT)";

// Create the table using the Odbc connection from


the
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

if (ShouldProcess(newTableName, "create"))
{
OdbcCommand cmd = new OdbcCommand(sql,
connection);
cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
}
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
throw new
ArgumentException("A row cannot be created under a
database, specify a path that represents a Table");
}
}// if (PathIsDrive...
else
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
if (rowNumber < 0)
{
throw new
ArgumentException("A table cannot be created
within another table, specify a path that represents a database");
}
else
{
throw new
ArgumentException("A table cannot be created
inside a row, specify a path that represents a database");
}
} //if (String.Equals....
// if path specified is a row, create a new row
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
// The user is required to specify the values to be
inserted
// into the table in a single string separated by commas
string value = newItemValue as string;

if (String.IsNullOrEmpty(value))
{
throw new
ArgumentException("Value argument must have comma
separated values of each column in a row");
}
string[] rowValues = value.Split(',');

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

if (rowValues.Length != table.Columns.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The table has {0} columns and
the value specified must have so many comma separated values",
table.Columns.Count);

throw new ArgumentException(message);


}

if (!Force && (rowNumber >=0 && rowNumber <


table.Rows.Count))
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The row {0} already
exists. To create a new row specify row number as {1}, or specify path to a
table, or use the -Force parameter",
rowNumber,
table.Rows.Count);

throw new ArgumentException(message);


}

if (rowNumber > table.Rows.Count)


{
string message =
String.Format(CultureInfo.CurrentCulture,
"To create a new row specify row
number as {0}, or specify path to a table",
table.Rows.Count);

throw new ArgumentException(message);


}

// Create a new row and update the row with the input
// provided by the user
DataRow row = table.NewRow();
for (int i = 0; i < rowValues.Length; i++)
{
row[i] = rowValues[i];
}
table.Rows.Add(row);

if (ShouldProcess(tableName, "update rows"))


{
// Update the table from memory back to the data
source
da.Update(ds, tableName);
}

}// else if (String...


}// else ...

} // NewItem

/// <summary>
/// Copies an item at the specified path to the location specified
/// </summary>
///
/// <param name="path">
/// Path of the item to copy
/// </param>
///
/// <param name="copyPath">
/// Path of the item to copy to
/// </param>
///
/// <param name="recurse">
/// Tells the provider to recurse subcontainers when copying
/// </param>
///
protected override void CopyItem(string path, string copyPath, bool
recurse)
{
string tableName, copyTableName;
int rowNumber, copyRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
PathType copyType = GetNamesFromPath(copyPath, out copyTableName,
out copyRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(copyPath);
}

// Get the table and the table to copy to


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter cda = GetAdapterForTable(copyTableName);


if (cda == null)
{
return;
}

DataSet cds = GetDataSetForTable(cda, copyTableName);


DataTable copyTable = GetDataTable(cds, copyTableName);

// if source represents a table


if (type == PathType.Table)
{
// if copyPath does not represent a table
if (copyType != PathType.Table)
{
ArgumentException e = new ArgumentException("Table can
only be copied on to another table location");

WriteError(new ErrorRecord(e, "PathNotValid",


ErrorCategory.InvalidArgument, copyPath));

throw e;
}

// if table already exists then force parameter should be set


// to force a copy
if (!Force && GetTable(copyTableName) != null)
{
throw new ArgumentException("Specified path already
exists");
}
for (int i = 0; i < table.Rows.Count; i++)
{
DataRow row = table.Rows[i];
DataRow copyRow = copyTable.NewRow();

copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
}
} // if (type == ...
// if source represents a row
else
{
if (copyType == PathType.Row)
{
if (!Force && (copyRowNumber < copyTable.Rows.Count))
{
throw new ArgumentException("Specified path already
exists.");
}

DataRow row = table.Rows[rowNumber];


DataRow copyRow = null;

if (copyRowNumber < copyTable.Rows.Count)


{
// copy to an existing row
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
}
else if (copyRowNumber == copyTable.Rows.Count)
{
// copy to the next row in the table that will
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
else
{
// attempting to copy to a nonexistent row or a row
// that cannot be created now - throw an exception
string message =
String.Format(CultureInfo.CurrentCulture,
"The item cannot be specified
to the copied row. Specify row number as {0}, or specify a path to the
table.",
table.Rows.Count);

throw new ArgumentException(message);


}
}
else
{
// destination path specified represents a table,
// create a new row and copy the item
DataRow copyRow = copyTable.NewRow();
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
}

if (ShouldProcess(copyTableName, "CopyItems"))
{
cda.Update(cds, copyTableName);
}

} //CopyItem

/// <summary>
/// Removes (deletes) the item at the specified path
/// </summary>
///
/// <param name="path">
/// The path to the item to remove.
/// </param>
///
/// <param name="recurse">
/// True if all children in a subtree should be removed, false if
only
/// the item at the specified path should be removed. Is applicable
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
protected override void RemoveItem(string path, bool recurse)
{
string tableName;
int rowNumber = 0;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// if recurse flag has been specified, delete all the rows as
well
if (recurse)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

for (int i = 0; i < table.Rows.Count; i++)


{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
RemoveTable(tableName);
}
}//if (recurse...
else
{
// Remove the table
if (ShouldProcess(path, "RemoveItem"))
{
RemoveTable(tableName);
}
}
}
else if (type == PathType.Row)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

table.Rows[rowNumber].Delete();

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
}
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // RemoveItem

#endregion Container Overloads

#region Helper Methods


/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");

return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath

/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;

if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the path</param>
/// <returns>what the path represents</returns>
private PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;

default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath

/// <summary>
/// Throws an argument exception stating that the specified path does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object representing
/// information about one database table
/// </returns>
private Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;

// iterate through all rows in the schema and create


DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName +
"\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count, columns);

results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables

/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
private Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;

} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Removes the specified table from the database
/// </summary>
/// <param name="tableName">Name of the table to remove</param>
private void RemoveTable(string tableName)
{
// validate if tablename is valid and if table is present
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
{
return;
}

// Execute command using ODBC connection to remove a table


try
{
// delete the table using an sql statement
string sql = "drop table " + tableName;

AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

OdbcCommand cmd = new OdbcCommand(sql, connection);


cmd.ExecuteScalar();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "CannotRemoveSpecifiedTable",
ErrorCategory.InvalidOperation, null)
);
}

} // RemoveTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
private OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName)


||!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create sql


// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Set the delete cmd for the table here


sql = "Delete from " + tableName + " where ID = ?";
da.DeleteCommand = new OdbcCommand(sql, connection);

// Specify a DeleteCommand parameter based on the "ID"


// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";

// Create an InsertCommand based on the sql string


// Insert into "tablename" values (?,?,?)" where
// ? represents a column in the table. Note that
// the number of ? will be equal to the number of
// columnds
DataSet ds = new DataSet();

da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;

sql = "Insert into " + tableName + " values ( ";


for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
sql += "?, ";
}
sql = sql.Substring(0, sql.Length - 2);
sql += ")";
da.InsertCommand = new OdbcCommand(sql, connection);

// Create parameters for the InsertCommand based on the


// captions of each column
for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
private DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);

// Create a dataset object which will provide an in-memory


// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
private DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;

return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // SafeConvertRowNumber

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

/// <summary>
/// Gets the next available ID in the table
/// </summary>
/// <param name="table">DataTable object representing the table to
/// search for ID</param>
/// <returns>next available id</returns>
private int GetNextID(DataTable table)
{
int big = 0;
int id = 0;

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];

object o = row["ID"];

if (o.GetType().Name.Equals("Int16"))
{
id = (int)(short)o;
}
else
{
id = (int)o;
}
if (big < id)
{
big = id;
}
}

big++;
return big;
}

#endregion Helper Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

private enum PathType { Database, Table, Row, Invalid };

#endregion Private Properties


}

#endregion AccessDBProvider

#region Helper Classes

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo
#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#endregion Helper Classes


}

Consulte también
System.Management.Automation.Provider.Itemcmdletprovider

System.Management.Automation.Provider.Containercmdletprovider

System.Management.Automation.Provider.Navigationcmdletprovider

Diseño del proveedor de Windows PowerShell


AccessDBProviderSample05
Artículo • 24/09/2021

En este ejemplo se muestra cómo sobrescribir métodos de contenedor para admitir


llamadas a Move-Item Join-Path los cmdlets y . Estos métodos deberían implementarse
cuando el usuario necesite mover elementos dentro de un contenedor y si el almacén
de datos tiene contenedores anidados. La clase de proveedor de este ejemplo se deriva
de la clase System.Management.Automation.Provider.Navigationcmdletprovider.

Muestra

) Importante

Lo más probable es que la clase de proveedor derive de una de las siguientes


clases y posiblemente implemente otras interfaces de proveedor:

Clase System.Management.Automation.Provider.Itemcmdletprovider. Vea


AccessDBProviderSample03.
Clase System.Management.Automation.Provider.Containercmdletprovider.
Vea AccessDBProviderSample04.
Clase System.Management.Automation.Provider.Navigationcmdletprovider.

Para obtener más información sobre cómo elegir de qué clase de proveedor derivar
en función de las características del proveedor, vea Designing Your Windows
PowerShell Provider.

En este ejemplo se muestra lo siguiente:

Declarar el CmdletProvider atributo.

Definir una clase de proveedor que deriva de la clase


System.Management.Automation.Provider.Navigationcmdletprovider.

Sobrescribir el método
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*
para cambiar el comportamiento del cmdlet, lo que permite al usuario mover
elementos de una ubicación a Move-Item otra. (En este ejemplo no se muestra
cómo agregar parámetros dinámicos al Move-Item cmdlet).
Sobrescribir el método
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*
para cambiar el comportamiento del Join-Path cmdlet.

Sobrescriba el método
System.Management.Automation.Provider.Navigationcmdletprovider.Isitemcontain
er*.

Sobrescriba el método
System.Management.Automation.Provider.Navigationcmdletprovider.Getchildnam
e*.

Sobrescriba el método
System.Management.Automation.Provider.Navigationcmdletprovider.Getparentpat
h*.

Sobrescriba el método
System.Management.Automation.Provider.Navigationcmdletprovider.Normalizerel
ativepath*.

Ejemplo
En este ejemplo se muestra cómo sobrescribir los métodos necesarios para mover
elementos en una base de datos de Microsoft Access.

C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// This example implements the navigation methods.
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider
{

#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}
// Get in-memory representation of table
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads

#region Container Overloads

/// <summary>
/// Return either the tables in the database or the datarows
/// </summary>
/// <param name="path">The path to the parent</param>
/// <param name="recurse">True to return all child items recursively.
/// </param>
protected override void GetChildItems(string path, bool recurse)
{
// If path represented is a drive then the children in the path
are
// tables. Hence all tables in the drive represented will have to
be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set


then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name,
recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildItems

/// <summary>
/// Return the names of all child items.
/// </summary>
/// <param name="path">The root path.</param>
/// <param name="returnContainers">Not used.</param>
protected override void GetChildNames(string path,
ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);

WriteItemObject(row.RowNumber, path, false);


}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildNames

/// <summary>
/// Determines if the specified path has child items.
/// </summary>
/// <param name="path">The path to examine.</param>
/// <returns>
/// True if the specified path has child items.
/// </returns>
protected override bool HasChildItems(string path)
{
if (PathIsDrive(path))
{
return true;
}

return (ChunkPath(path).Length == 1);


} // HasChildItems

/// <summary>
/// Creates a new item at the specified path.
/// </summary>
///
/// <param name="path">
/// The path to the new item.
/// </param>
///
/// <param name="type">
/// Type for the object to create. "Table" for creating a new table
and
/// "Row" for creating a new row in a table.
/// </param>
///
/// <param name="newItemValue">
/// Object for creating new instance of a type at the specified path.
For
/// creating a "Table" the object parameter is ignored and for
creating
/// a "Row" the object must be of type string which will contain
comma
/// separated values of the rows to insert.
/// </param>
protected override void NewItem(string path, string type,
object newItemValue)
{
string tableName;
int rowNumber;

PathType pt = GetNamesFromPath(path, out tableName, out


rowNumber);

if (pt == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

// Check if type is either "table" or "row", if not throw an


// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
&& !String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
WriteError(new ErrorRecord
(new ArgumentException("Type must be either
a table or row"),
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
)
);

throw new ArgumentException("This provider can only create


items of type \"table\" or \"row\"");
}

// Path type is the type of path of the container. So if a drive


// is specified, then a table can be created under it and if a
table
// is specified, then a row can be created under it. For the sake
of
// completeness, if a row is specified, then if the row specified
by
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
// on the number of rows

if (PathIsDrive(path))
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
// Execute command using ODBC connection to create a
table
try
{
// create the table using an sql statement
string newTableName = newItemValue.ToString();
string sql = "create table " + newTableName
+ " (ID INT)";

// Create the table using the Odbc connection from


the
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

if (ShouldProcess(newTableName, "create"))
{
OdbcCommand cmd = new OdbcCommand(sql,
connection);
cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
}
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
throw new
ArgumentException("A row cannot be created under a
database, specify a path that represents a Table");
}
}// if (PathIsDrive...
else
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
if (rowNumber < 0)
{
throw new
ArgumentException("A table cannot be created
within another table, specify a path that represents a database");
}
else
{
throw new
ArgumentException("A table cannot be created
inside a row, specify a path that represents a database");
}
} //if (String.Equals....
// if path specified is a row, create a new row
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
// The user is required to specify the values to be
inserted
// into the table in a single string separated by commas
string value = newItemValue as string;

if (String.IsNullOrEmpty(value))
{
throw new
ArgumentException("Value argument must have comma
separated values of each column in a row");
}
string[] rowValues = value.Split(',');

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

if (rowValues.Length != table.Columns.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The table has {0} columns and
the value specified must have so many comma separated values",
table.Columns.Count);

throw new ArgumentException(message);


}

if (!Force && (rowNumber >= 0 && rowNumber <


table.Rows.Count))
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The row {0} already exists. To
create a new row specify row number as {1}, or specify path to a table, or
use the -Force parameter",
rowNumber,
table.Rows.Count);
throw new ArgumentException(message);
}

if (rowNumber > table.Rows.Count)


{
string message =
String.Format(CultureInfo.CurrentCulture,
"To create a new row specify row
number as {0}, or specify path to a table",
table.Rows.Count);

throw new ArgumentException(message);


}

// Create a new row and update the row with the input
// provided by the user
DataRow row = table.NewRow();
for (int i = 0; i < rowValues.Length; i++)
{
row[i] = rowValues[i];
}
table.Rows.Add(row);

if (ShouldProcess(tableName, "update rows"))


{
// Update the table from memory back to the data
source
da.Update(ds, tableName);
}

}// else if (String...


}// else ...

} // NewItem

/// <summary>
/// Copies an item at the specified path to the location specified
/// </summary>
///
/// <param name="path">
/// Path of the item to copy
/// </param>
///
/// <param name="copyPath">
/// Path of the item to copy to
/// </param>
///
/// <param name="recurse">
/// Tells the provider to recurse subcontainers when copying
/// </param>
///
protected override void CopyItem(string path, string copyPath, bool
recurse)
{
string tableName, copyTableName;
int rowNumber, copyRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
PathType copyType = GetNamesFromPath(copyPath, out copyTableName,
out copyRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(copyPath);
}

// Get the table and the table to copy to


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter cda = GetAdapterForTable(copyTableName);


if (cda == null)
{
return;
}

DataSet cds = GetDataSetForTable(cda, copyTableName);


DataTable copyTable = GetDataTable(cds, copyTableName);

// if source represents a table


if (type == PathType.Table)
{
// if copyPath does not represent a table
if (copyType != PathType.Table)
{
ArgumentException e = new ArgumentException("Table can
only be copied on to another table location");

WriteError(new ErrorRecord(e, "PathNotValid",


ErrorCategory.InvalidArgument, copyPath));

throw e;
}

// if table already exists then force parameter should be set


// to force a copy
if (!Force && GetTable(copyTableName) != null)
{
throw new ArgumentException("Specified path already
exists");
}

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];
DataRow copyRow = copyTable.NewRow();

copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
}
} // if (type == ...
// if source represents a row
else
{
if (copyType == PathType.Row)
{
if (!Force && (copyRowNumber < copyTable.Rows.Count))
{
throw new ArgumentException("Specified path already
exists.");
}

DataRow row = table.Rows[rowNumber];


DataRow copyRow = null;

if (copyRowNumber < copyTable.Rows.Count)


{
// copy to an existing row
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
}
else if (copyRowNumber == copyTable.Rows.Count)
{
// copy to the next row in the table that will
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
else
{
// attempting to copy to a nonexistent row or a row
// that cannot be created now - throw an exception
string message =
String.Format(CultureInfo.CurrentCulture,
"The item cannot be specified to
the copied row. Specify row number as {0}, or specify a path to the table.",
table.Rows.Count);

throw new ArgumentException(message);


}
}
else
{
// destination path specified represents a table,
// create a new row and copy the item
DataRow copyRow = copyTable.NewRow();
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
}

if (ShouldProcess(copyTableName, "CopyItems"))
{
cda.Update(cds, copyTableName);
}

} //CopyItem

/// <summary>
/// Removes (deletes) the item at the specified path
/// </summary>
///
/// <param name="path">
/// The path to the item to remove.
/// </param>
///
/// <param name="recurse">
/// True if all children in a subtree should be removed, false if
only
/// the item at the specified path should be removed. Is applicable
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
protected override void RemoveItem(string path, bool recurse)
{
string tableName;
int rowNumber = 0;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// if recurse flag has been specified, delete all the rows as
well
if (recurse)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

for (int i = 0; i < table.Rows.Count; i++)


{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
RemoveTable(tableName);
}
}//if (recurse...
else
{
// Remove the table
if (ShouldProcess(path, "RemoveItem"))
{
RemoveTable(tableName);
}
}
}
else if (type == PathType.Row)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

table.Rows[rowNumber].Delete();

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
}
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // RemoveItem
#endregion Container Overloads

#region Navigation

/// <summary>
/// Determine if the path specified is that of a container.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>True if the path specifies a container.</returns>
protected override bool IsItemContainer(string path)
{
if (PathIsDrive(path))
{
return true;
}

string[] pathChunks = ChunkPath(path);


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...

return false;
} // IsItemContainer

/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// <param name="path">
/// The full or partial provider specific path
/// </param>
///
/// <returns>
/// The leaf element in the path
/// </returns>
protected override string GetChildName(string path)
{
if (PathIsDrive(path))
{
return path;
}

string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
return tableName;
}
else if (type == PathType.Row)
{
return rowNumber.ToString(CultureInfo.CurrentCulture);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

return null;
}

/// <summary>
/// Removes the child segment of the path and returns the remaining
/// parent portion
/// </summary>
///
/// <param name="path">
/// A full or partial provider specific path. The path may be to an
/// item that may or may not exist.
/// </param>
///
/// <param name="root">
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// operation. If this parameter is not null or empty the result
/// of the method should not be a path to a container that is a
/// parent or in a different tree than the root.
/// </param>
///
/// <returns></returns>

protected override string GetParentPath(string path, string root)


{
// If root is specified then the path has to contain
// the root. If not nothing should be returned
if (!String.IsNullOrEmpty(root))
{
if (!path.Contains(root))
{
return null;
}
}
return path.Substring(0, path.LastIndexOf(pathSeparator,
StringComparison.OrdinalIgnoreCase));
}

/// <summary>
/// Joins two strings with a provider specific path separator.
/// </summary>
///
/// <param name="parent">
/// The parent segment of a path to be joined with the child.
/// </param>
///
/// <param name="child">
/// The child segment of a path to be joined with the parent.
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// joined by a path separator.
/// </returns>

protected override string MakePath(string parent, string child)


{
string result;

string normalParent = NormalizePath(parent);


normalParent = RemoveDriveFromPath(normalParent);
string normalChild = NormalizePath(child);
normalChild = RemoveDriveFromPath(normalChild);

if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
result = String.Empty;
}
else if (String.IsNullOrEmpty(normalParent) &&
!String.IsNullOrEmpty(normalChild))
{
result = normalChild;
}
else if (!String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent;
}
else
{
result = normalParent + pathSeparator;
}
} // else if (!String...
else
{
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent + pathSeparator;
}
else
{
result = normalParent;
}

if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result += normalChild.Substring(1);
}
else
{
result += normalChild;
}
} // else

return result;
} // MakePath

/// <summary>
/// Normalizes the path that was passed in and returns the normalized
/// path as a relative path to the basePath that was passed.
/// </summary>
///
/// <param name="path">
/// A fully qualified provider specific path to an item. The item
/// should exist or the provider should write out an error.
/// </param>
///
/// <param name="basepath">
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// A normalized path that is relative to the basePath that was
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>

protected override string NormalizeRelativePath(string path,


string basepath)
{
// Normalize the paths first
string normalPath = NormalizePath(path);
normalPath = RemoveDriveFromPath(normalPath);
string normalBasePath = NormalizePath(basepath);
normalBasePath = RemoveDriveFromPath(normalBasePath);

if (String.IsNullOrEmpty(normalBasePath))
{
return normalPath;
}
else
{
if (!normalPath.Contains(normalBasePath))
{
return null;
}

return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
}
}

/// <summary>
/// Moves the item specified by the path to the specified destination
/// </summary>
///
/// <param name="path">
/// The path to the item to be moved
/// </param>
///
/// <param name="destination">
/// The path of the destination container
/// </param>

protected override void MoveItem(string path, string destination)


{
// Get type, table name and rowNumber from the path
string tableName, destTableName;
int rowNumber, destRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

PathType destType = GetNamesFromPath(destination, out


destTableName,
out destRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (destType == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(destination);
}

if (type == PathType.Table)
{
ArgumentException e = new ArgumentException("Move not
supported for tables");

WriteError(new ErrorRecord(e, "MoveNotSupported",


ErrorCategory.InvalidArgument, path));

throw e;
}
else
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter dda = GetAdapterForTable(destTableName);


if (dda == null)
{
return;
}

DataSet dds = GetDataSetForTable(dda, destTableName);


DataTable destTable = GetDataTable(dds, destTableName);
DataRow row = table.Rows[rowNumber];

if (destType == PathType.Table)
{
DataRow destRow = destTable.NewRow();

destRow.ItemArray = row.ItemArray;
}
else
{
DataRow destRow = destTable.Rows[destRowNumber];

destRow.ItemArray = row.ItemArray;
}

// Update the changes


if (ShouldProcess(path, "MoveItem"))
{
WriteItemObject(row, path, false);
dda.Update(dds, destTableName);
}
}
}

#endregion Navigation

#region Helper Methods


/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");

return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath

/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;
if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
/// <param name="path">Path from which drive needs to be
removed</param>
/// <returns>Path with drive information removed</returns>
private string RemoveDriveFromPath(string path)
{
string result = path;
string root;

if (this.PSDriveInfo == null)
{
root = String.Empty;
}
else
{
root = this.PSDriveInfo.Root;
}

if (result == null)
{
result = String.Empty;
}

if (result.Contains(root))
{
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
}

return result;
}

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the path</param>
/// <returns>what the path represents</returns>
private PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;
default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath

/// <summary>
/// Throws an argument exception stating that the specified path does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object representing
/// information about one database table
/// </returns>
private Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;
// iterate through all rows in the schema and create
DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName + "\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count, columns);

results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables

/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
private Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);
int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;

} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Removes the specified table from the database
/// </summary>
/// <param name="tableName">Name of the table to remove</param>
private void RemoveTable(string tableName)
{
// validate if tablename is valid and if table is present
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
{
return;
}

// Execute command using ODBC connection to remove a table


try
{
// delete the table using an sql statement
string sql = "drop table " + tableName;

AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

OdbcCommand cmd = new OdbcCommand(sql, connection);


cmd.ExecuteScalar();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "CannotRemoveSpecifiedTable",
ErrorCategory.InvalidOperation, null)
);
}

} // RemoveTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
private OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName) ||


!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create sql


// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Set the delete cmd for the table here


sql = "Delete from " + tableName + " where ID = ?";
da.DeleteCommand = new OdbcCommand(sql, connection);

// Specify a DeleteCommand parameter based on the "ID"


// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";

// Create an InsertCommand based on the sql string


// Insert into "tablename" values (?,?,?)" where
// ? represents a column in the table. Note that
// the number of ? will be equal to the number of
// columnds
DataSet ds = new DataSet();

da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;

sql = "Insert into " + tableName + " values ( ";


for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
sql += "?, ";
}
sql = sql.Substring(0, sql.Length - 2);
sql += ")";
da.InsertCommand = new OdbcCommand(sql, connection);

// Create parameters for the InsertCommand based on the


// captions of each column
for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
private DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);

// Create a dataset object which will provide an in-memory


// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
private DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;

return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // SafeConvertRowNumber

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

/// <summary>
/// Gets the next available ID in the table
/// </summary>
/// <param name="table">DataTable object representing the table to
/// search for ID</param>
/// <returns>next available id</returns>
private int GetNextID(DataTable table)
{
int big = 0;

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];

int id = (int)row["ID"];

if (big < id)


{
big = id;
}
}

big++;
return big;
}

#endregion Helper Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

private enum PathType { Database, Table, Row, Invalid };

#endregion Private Properties

} // AccessDBProvider

#endregion AccessDBProvider

#region Helper Classes

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#endregion Helper Classes


}

Consulte también
System.Management.Automation.Provider.Itemcmdletprovider

System.Management.Automation.Provider.Containercmdletprovider

System.Management.Automation.Provider.Navigationcmdletprovider

Diseño del proveedor de Windows PowerShell


AccessDBProviderSample06
Artículo • 27/09/2021

En este ejemplo se muestra cómo sobrescribir métodos de contenido para admitir


llamadas a los Clear-Content Get-Content cmdlets , Set-Content y . Estos métodos
deberían implementarse cuando el usuario necesite administrar el contenido de los
elementos en el almacén de datos. La clase de proveedor de este ejemplo deriva de la
clase System.Management.Automation.Provider.Navigationcmdletprovider e
implementa la interfaz
System.Management.Automation.Provider.Icontentcmdletprovider.

Muestra

) Importante

Lo más probable es que la clase de proveedor derive de una de las siguientes


clases y posiblemente implemente otras interfaces de proveedor:

Clase System.Management.Automation.Provider.Itemcmdletprovider. Vea


AccessDBProviderSample03.
Clase System.Management.Automation.Provider.Containercmdletprovider.
Vea AccessDBProviderSample04.
Clase System.Management.Automation.Provider.Navigationcmdletprovider.

Para obtener más información sobre cómo elegir de qué clase de proveedor derivar
en función de las características del proveedor, vea Designing Your Windows
PowerShell Provider.

En este ejemplo se muestra lo siguiente:

Declarar el CmdletProvider atributo.


Definir una clase de proveedor que deriva de la clase
System.Management.Automation.Provider.Navigationcmdletprovider y que declara
la interfaz System.Management.Automation.Provider.Icontentcmdletprovider.
Sobrescribir el método
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*
para cambiar el comportamiento del cmdlet, lo que permite al usuario quitar el
contenido de Clear-Content un elemento. (En este ejemplo no se muestra cómo
agregar parámetros dinámicos al Clear-Content cmdlet).
Sobrescribir el método
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentread
er* para cambiar el comportamiento del cmdlet, lo que permite al usuario
recuperar el contenido de Get-Content un elemento. (En este ejemplo no se
muestra cómo agregar parámetros dinámicos al Get-Content cmdlet ).
Sobrescribir el método
Microsoft.PowerShell.Commands.Filesystemprovider.Getcontentwriter* para
cambiar el comportamiento del cmdlet, lo que permite al usuario actualizar el
contenido de Set-Content un elemento. (En este ejemplo no se muestra cómo
agregar parámetros dinámicos al Set-Content cmdlet).

Ejemplo
En este ejemplo se muestra cómo sobrescribir los métodos necesarios para borrar,
obtener y establecer el contenido de los elementos de una base de datos de Microsoft
Access.

C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.Text;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// This example implements the content methods.
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider,
IContentCmdletProvider
{

#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file
and set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}

// Get in-memory representation of table


OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads


#region Container Overloads

/// <summary>
/// Return either the tables in the database or the datarows
/// </summary>
/// <param name="path">The path to the parent</param>
/// <param name="recurse">True to return all child items
recursively.
/// </param>
protected override void GetChildItems(string path, bool recurse)
{
// If path represented is a drive then the children in the path
are
// tables. Hence all tables in the drive represented will have
to be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set


then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name,
recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildItems

/// <summary>
/// Return the names of all child items.
/// </summary>
/// <param name="path">The root path.</param>
/// <param name="returnContainers">Not used.</param>
protected override void GetChildNames(string path,
ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);

WriteItemObject(row.RowNumber, path, false);


}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildNames

/// <summary>
/// Determines if the specified path has child items.
/// </summary>
/// <param name="path">The path to examine.</param>
/// <returns>
/// True if the specified path has child items.
/// </returns>
protected override bool HasChildItems(string path)
{
if (PathIsDrive(path))
{
return true;
}

return (ChunkPath(path).Length == 1);


} // HasChildItems

/// <summary>
/// Creates a new item at the specified path.
/// </summary>
///
/// <param name="path">
/// The path to the new item.
/// </param>
///
/// <param name="type">
/// Type for the object to create. "Table" for creating a new table
and
/// "Row" for creating a new row in a table.
/// </param>
///
/// <param name="newItemValue">
/// Object for creating new instance of a type at the specified
path. For
/// creating a "Table" the object parameter is ignored and for
creating
/// a "Row" the object must be of type string which will contain
comma
/// separated values of the rows to insert.
/// </param>
protected override void NewItem(string path, string type,
object newItemValue)
{
string tableName;
int rowNumber;

PathType pt = GetNamesFromPath(path, out tableName, out


rowNumber);

if (pt == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

// Check if type is either "table" or "row", if not throw an


// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
&& !String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
WriteError(new ErrorRecord
(new ArgumentException("Type must be
either a table or row"),
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
)
);

throw new ArgumentException("This provider can only create


items of type \"table\" or \"row\"");
}

// Path type is the type of path of the container. So if a drive


// is specified, then a table can be created under it and if a
table
// is specified, then a row can be created under it. For the
sake of
// completeness, if a row is specified, then if the row
specified by
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
// on the number of rows

if (PathIsDrive(path))
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
// Execute command using ODBC connection to create a
table
try
{
// create the table using an sql statement
string newTableName = newItemValue.ToString();
string sql = "create table " + newTableName
+ " (ID INT)";

// Create the table using the Odbc connection from


the
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

if (ShouldProcess(newTableName, "create"))
{
OdbcCommand cmd = new OdbcCommand(sql,
connection);
cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
}
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
throw new
ArgumentException("A row cannot be created under a
database, specify a path that represents a Table");
}
}// if (PathIsDrive...
else
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
if (rowNumber < 0)
{
throw new
ArgumentException("A table cannot be created
within another table, specify a path that represents a database");
}
else
{
throw new
ArgumentException("A table cannot be created
inside a row, specify a path that represents a database");
}
} //if (String.Equals....
// if path specified is a row, create a new row
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
// The user is required to specify the values to be
inserted
// into the table in a single string separated by commas
string value = newItemValue as string;

if (String.IsNullOrEmpty(value))
{
throw new
ArgumentException("Value argument must have
comma separated values of each column in a row");
}
string[] rowValues = value.Split(',');

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

if (rowValues.Length != table.Columns.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The table has {0} columns and
the value specified must have so many comma separated values",
table.Columns.Count);

throw new ArgumentException(message);


}

if (!Force && (rowNumber >= 0 && rowNumber <


table.Rows.Count))
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The row {0} already exists. To
create a new row specify row number as {1}, or specify path to a table, or
use the -Force parameter",
rowNumber,
table.Rows.Count);

throw new ArgumentException(message);


}

if (rowNumber > table.Rows.Count)


{
string message =
String.Format(CultureInfo.CurrentCulture,
"To create a new row specify row
number as {0}, or specify path to a table",
table.Rows.Count);

throw new ArgumentException(message);


}

// Create a new row and update the row with the input
// provided by the user
DataRow row = table.NewRow();
for (int i = 0; i < rowValues.Length; i++)
{
row[i] = rowValues[i];
}
table.Rows.Add(row);

if (ShouldProcess(tableName, "update rows"))


{
// Update the table from memory back to the data
source
da.Update(ds, tableName);
}

}// else if (String...


}// else ...

} // NewItem

/// <summary>
/// Copies an item at the specified path to the location specified
/// </summary>
///
/// <param name="path">
/// Path of the item to copy
/// </param>
///
/// <param name="copyPath">
/// Path of the item to copy to
/// </param>
///
/// <param name="recurse">
/// Tells the provider to recurse subcontainers when copying
/// </param>
///
protected override void CopyItem(string path, string copyPath, bool
recurse)
{
string tableName, copyTableName;
int rowNumber, copyRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
PathType copyType = GetNamesFromPath(copyPath, out
copyTableName, out copyRowNumber);
if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(copyPath);
}

// Get the table and the table to copy to


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter cda = GetAdapterForTable(copyTableName);


if (cda == null)
{
return;
}

DataSet cds = GetDataSetForTable(cda, copyTableName);


DataTable copyTable = GetDataTable(cds, copyTableName);

// if source represents a table


if (type == PathType.Table)
{
// if copyPath does not represent a table
if (copyType != PathType.Table)
{
ArgumentException e = new ArgumentException("Table can
only be copied on to another table location");

WriteError(new ErrorRecord(e, "PathNotValid",


ErrorCategory.InvalidArgument, copyPath));

throw e;
}

// if table already exists then force parameter should be


set
// to force a copy
if (!Force && GetTable(copyTableName) != null)
{
throw new ArgumentException("Specified path already
exists");
}

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];
DataRow copyRow = copyTable.NewRow();

copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
}
} // if (type == ...
// if source represents a row
else
{
if (copyType == PathType.Row)
{
if (!Force && (copyRowNumber < copyTable.Rows.Count))
{
throw new ArgumentException("Specified path already
exists.");
}

DataRow row = table.Rows[rowNumber];


DataRow copyRow = null;

if (copyRowNumber < copyTable.Rows.Count)


{
// copy to an existing row
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
}
else if (copyRowNumber == copyTable.Rows.Count)
{
// copy to the next row in the table that will
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
else
{
// attempting to copy to a nonexistent row or a row
// that cannot be created now - throw an exception
string message =
String.Format(CultureInfo.CurrentCulture,
"The item cannot be specified to
the copied row. Specify row number as {0}, or specify a path to the table.",
table.Rows.Count);

throw new ArgumentException(message);


}
}
else
{
// destination path specified represents a table,
// create a new row and copy the item
DataRow copyRow = copyTable.NewRow();
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
}

if (ShouldProcess(copyTableName, "CopyItems"))
{
cda.Update(cds, copyTableName);
}

} //CopyItem

/// <summary>
/// Removes (deletes) the item at the specified path
/// </summary>
///
/// <param name="path">
/// The path to the item to remove.
/// </param>
///
/// <param name="recurse">
/// True if all children in a subtree should be removed, false if
only
/// the item at the specified path should be removed. Is applicable
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
protected override void RemoveItem(string path, bool recurse)
{
string tableName;
int rowNumber = 0;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// if recurse flag has been specified, delete all the rows
as well
if (recurse)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

for (int i = 0; i < table.Rows.Count; i++)


{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
RemoveTable(tableName);
}
}//if (recurse...
else
{
// Remove the table
if (ShouldProcess(path, "RemoveItem"))
{
RemoveTable(tableName);
}
}
}
else if (type == PathType.Row)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

table.Rows[rowNumber].Delete();

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
}
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // RemoveItem

#endregion Container Overloads

#region Navigation

/// <summary>
/// Determine if the path specified is that of a container.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>True if the path specifies a container.</returns>
protected override bool IsItemContainer(string path)
{
if (PathIsDrive(path))
{
return true;
}

string[] pathChunks = ChunkPath(path);


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...

return false;
} // IsItemContainer

/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// <param name="path">
/// The full or partial provider specific path
/// </param>
///
/// <returns>
/// The leaf element in the path
/// </returns>
protected override string GetChildName(string path)
{
if (PathIsDrive(path))
{
return path;
}

string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
return tableName;
}
else if (type == PathType.Row)
{
return rowNumber.ToString(CultureInfo.CurrentCulture);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

return null;
}

/// <summary>
/// Removes the child segment of the path and returns the remaining
/// parent portion
/// </summary>
///
/// <param name="path">
/// A full or partial provider specific path. The path may be to an
/// item that may or may not exist.
/// </param>
///
/// <param name="root">
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// operation. If this parameter is not null or empty the result
/// of the method should not be a path to a container that is a
/// parent or in a different tree than the root.
/// </param>
///
/// <returns></returns>

protected override string GetParentPath(string path, string root)


{
// If root is specified then the path has to contain
// the root. If not nothing should be returned
if (!String.IsNullOrEmpty(root))
{
if (!path.Contains(root))
{
return null;
}
}

return path.Substring(0, path.LastIndexOf(pathSeparator,


StringComparison.OrdinalIgnoreCase));
}

/// <summary>
/// Joins two strings with a provider specific path separator.
/// </summary>
///
/// <param name="parent">
/// The parent segment of a path to be joined with the child.
/// </param>
///
/// <param name="child">
/// The child segment of a path to be joined with the parent.
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// joined by a path separator.
/// </returns>

protected override string MakePath(string parent, string child)


{
string result;

string normalParent = NormalizePath(parent);


normalParent = RemoveDriveFromPath(normalParent);
string normalChild = NormalizePath(child);
normalChild = RemoveDriveFromPath(normalChild);

if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
result = String.Empty;
}
else if (String.IsNullOrEmpty(normalParent) &&
!String.IsNullOrEmpty(normalChild))
{
result = normalChild;
}
else if (!String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent;
}
else
{
result = normalParent + pathSeparator;
}
} // else if (!String...
else
{
if (!normalParent.Equals(String.Empty,
StringComparison.OrdinalIgnoreCase) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent + pathSeparator;
}
else
{
result = normalParent;
}

if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result += normalChild.Substring(1);
}
else
{
result += normalChild;
}
} // else

return result;
} // MakePath

/// <summary>
/// Normalizes the path that was passed in and returns the
normalized
/// path as a relative path to the basePath that was passed.
/// </summary>
///
/// <param name="path">
/// A fully qualified provider specific path to an item. The item
/// should exist or the provider should write out an error.
/// </param>
///
/// <param name="basepath">
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// A normalized path that is relative to the basePath that was
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>

protected override string NormalizeRelativePath(string path,


string
basepath)
{
// Normalize the paths first
string normalPath = NormalizePath(path);
normalPath = RemoveDriveFromPath(normalPath);
string normalBasePath = NormalizePath(basepath);
normalBasePath = RemoveDriveFromPath(normalBasePath);

if (String.IsNullOrEmpty(normalBasePath))
{
return normalPath;
}
else
{
if (!normalPath.Contains(normalBasePath))
{
return null;
}

return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
}
}

/// <summary>
/// Moves the item specified by the path to the specified
destination
/// </summary>
///
/// <param name="path">
/// The path to the item to be moved
/// </param>
///
/// <param name="destination">
/// The path of the destination container
/// </param>

protected override void MoveItem(string path, string destination)


{
// Get type, table name and rowNumber from the path
string tableName, destTableName;
int rowNumber, destRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

PathType destType = GetNamesFromPath(destination, out


destTableName,
out destRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (destType == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(destination);
}

if (type == PathType.Table)
{
ArgumentException e = new ArgumentException("Move not
supported for tables");
WriteError(new ErrorRecord(e, "MoveNotSupported",
ErrorCategory.InvalidArgument, path));

throw e;
}
else
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter dda = GetAdapterForTable(destTableName);


if (dda == null)
{
return;
}

DataSet dds = GetDataSetForTable(dda, destTableName);


DataTable destTable = GetDataTable(dds, destTableName);
DataRow row = table.Rows[rowNumber];

if (destType == PathType.Table)
{
DataRow destRow = destTable.NewRow();

destRow.ItemArray = row.ItemArray;
}
else
{
DataRow destRow = destTable.Rows[destRowNumber];

destRow.ItemArray = row.ItemArray;
}

// Update the changes


if (ShouldProcess(path, "MoveItem"))
{
WriteItemObject(row, path, false);
dda.Update(dds, destTableName);
}
}
}

#endregion Navigation

#region Helper Methods

/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");

return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath

/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;

if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
/// <param name="path">Path from which drive needs to be
removed</param>
/// <returns>Path with drive information removed</returns>
private string RemoveDriveFromPath(string path)
{
string result = path;
string root;

if (this.PSDriveInfo == null)
{
root = String.Empty;
}
else
{
root = this.PSDriveInfo.Root;
}

if (result == null)
{
result = String.Empty;
}

if (result.Contains(root))
{
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
}

return result;
}

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the
path</param>
/// <returns>what the path represents</returns>
public PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;
default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath

/// <summary>
/// Throws an argument exception stating that the specified path
does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object
representing
/// information about one database table
/// </returns>
internal Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;

// iterate through all rows in the schema and create


DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName +
"\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count,
columns);

results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables

/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
public Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;

} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Removes the specified table from the database
/// </summary>
/// <param name="tableName">Name of the table to remove</param>
private void RemoveTable(string tableName)
{
// validate if tablename is valid and if table is present
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
{
return;
}
// Execute command using ODBC connection to remove a table
try
{
// delete the table using an sql statement
string sql = "drop table " + tableName;

AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

OdbcCommand cmd = new OdbcCommand(sql, connection);


cmd.ExecuteScalar();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "CannotRemoveSpecifiedTable",
ErrorCategory.InvalidOperation, null)
);
}

} // RemoveTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
internal OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName) ||


!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update
the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create


sql
// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Set the delete cmd for the table here


sql = "Delete from " + tableName + " where ID = ?";
da.DeleteCommand = new OdbcCommand(sql, connection);

// Specify a DeleteCommand parameter based on the "ID"


// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";

// Create an InsertCommand based on the sql string


// Insert into "tablename" values (?,?,?)" where
// ? represents a column in the table. Note that
// the number of ? will be equal to the number of
// columnds
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;

da.FillSchema(ds, SchemaType.Source);

sql = "Insert into " + tableName + " values ( ";


for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
sql += "?, ";
}
sql = sql.Substring(0, sql.Length - 2);
sql += ")";
da.InsertCommand = new OdbcCommand(sql, connection);

// Create parameters for the InsertCommand based on the


// captions of each column
for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
internal DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);

// Create a dataset object which will provide an in-memory


// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
internal DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;
return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // 1

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

/// <summary>
/// Gets the next available ID in the table
/// </summary>
/// <param name="table">DataTable object representing the table to
/// search for ID</param>
/// <returns>next available id</returns>
private int GetNextID(DataTable table)
{
int big = 0;

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];

int id = (int)row["ID"];

if (big < id)


{
big = id;
}
}

big++;
return big;
}
#endregion Helper Methods

#region Content Methods

/// <summary>
/// Clear the contents at the specified location. In this case,
clearing
/// the item amounts to clearing a row
/// </summary>
/// <param name="path">The path to the content to clear.</param>
public void ClearContent(string path)
{
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out
rowNumber);

if (type != PathType.Table)
{
WriteError(new ErrorRecord(
new InvalidOperationException("Operation not supported.
Content can be cleared only for table"),
"NotValidRow", ErrorCategory.InvalidArgument,
path));
return;
}

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

// Clear contents at the specified location


for (int i = 0; i < table.Rows.Count; i++)
{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "ClearContent"))
{
da.Update(ds, tableName);
}

} // ClearContent

/// <summary>
/// Not implemented.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public object ClearContentDynamicParameters(string path)
{
return null;
}

/// <summary>
/// Get a reader at the path specified.
/// </summary>
/// <param name="path">The path from which to read.</param>
/// <returns>A content reader used to read the data.</returns>
public IContentReader GetContentReader(string path)
{
string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out
rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be obtained
only for tables");
}

return new AccessDBContentReader(path, this);


} // GetContentReader

/// <summary>
/// Not implemented.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public object GetContentReaderDynamicParameters(string path)
{
return null;
}

/// <summary>
/// Get an object used to write content.
/// </summary>
/// <param name="path">The root path at which to write.</param>
/// <returns>A content writer for writing.</returns>
public IContentWriter GetContentWriter(string path)
{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be added
only to tables");
}

return new AccessDBContentWriter(path, this);


}

/// <summary>
/// Not implemented.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public object GetContentWriterDynamicParameters(string path)
{
return null;
}

#endregion Content Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

#endregion Private Properties

} // AccessDBProvider

#endregion AccessDBProvider

#region Helper Classes

#region Public Enumerations

/// <summary>
/// Type of item represented by the path
/// </summary>
public enum PathType
{
/// <summary>
/// Represents a database
/// </summary>
Database,
/// <summary>
/// Represents a table
/// </summary>
Table,
/// <summary>
/// Represents a row
/// </summary>
Row,
/// <summary>
/// Represents an invalid path
/// </summary>
Invalid
};

#endregion Public Enumerations

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#region AccessDBContentReader

/// <summary>
/// Content reader used to retrieve data from this provider.
/// </summary>
public class AccessDBContentReader : IContentReader
{
// A provider instance is required so as to get "content"
private AccessDBProvider provider;
private string path;
private long currentOffset;

internal AccessDBContentReader(string path, AccessDBProvider


provider)
{
this.path = path;
this.provider = provider;
}

/// <summary>
/// Read the specified number of rows from the source.
/// </summary>
/// <param name="readCount">The number of items to
/// return.</param>
/// <returns>An array of elements read.</returns>
public IList Read(long readCount)
{
// Read the number of rows specified by readCount and increment
// offset
string tableName;
int rowNumber;
PathType type = provider.GetNamesFromPath(path, out tableName,
out rowNumber);

Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
Collection<DataRow> results = new Collection<DataRow>();

if (currentOffset < 0 || currentOffset >= rows.Count)


{
return null;
}

int rowsRead = 0;

while (rowsRead < readCount && currentOffset < rows.Count)


{
results.Add(rows[(int)currentOffset].Data);
rowsRead++;
currentOffset++;
}

return results;
} // Read

/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
/// <param name="offset">Number of rows to offset</param>
/// <param name="origin">Starting row from which to offset</param>
public void Seek(long offset, System.IO.SeekOrigin origin)
{
// get the number of rows in the table which will help in
// calculating current position
string tableName;
int rowNumber;

PathType type = provider.GetNamesFromPath(path, out tableName,


out rowNumber);

if (type == PathType.Invalid)
{
throw new ArgumentException("Path specified must represent a
table or a row :" + path);
}

if (type == PathType.Table)
{
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);

int numRows = rows.Count;

if (offset > rows.Count)


{
throw new
ArgumentException(
"Offset cannot be greater than the number of
rows available"
);
}

if (origin == System.IO.SeekOrigin.Begin)
{
// starting from Beginning with an index 0, the current
offset
// has to be advanced to offset - 1
currentOffset = offset - 1;
}
else if (origin == System.IO.SeekOrigin.End)
{
// starting from the end which is numRows - 1, the
current
// offset is so much less than numRows - 1
currentOffset = numRows - 1 - offset;
}
else
{
// calculate from the previous value of current offset
// advancing forward always
currentOffset += offset;
}
} // if (type...
else
{
// for row, the offset will always be set to 0
currentOffset = 0;
}

} // Seek

/// <summary>
/// Closes the content reader, so all members are reset
/// </summary>
public void Close()
{
Dispose();
} // Close

/// <summary>
/// Dispose any resources being used
/// </summary>
public void Dispose()
{
Seek(0, System.IO.SeekOrigin.Begin);

GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentReader

#endregion AccessDBContentReader

#region AccessDBContentWriter

/// <summary>
/// Content writer used to write data in this provider.
/// </summary>
public class AccessDBContentWriter : IContentWriter
{
// A provider instance is required so as to get "content"
private AccessDBProvider provider;
private string path;
private long currentOffset;

internal AccessDBContentWriter(string path, AccessDBProvider


provider)
{
this.path = path;
this.provider = provider;
}

/// <summary>
/// Write the specified row contents in the source
/// </summary>
/// <param name="content"> The contents to be written to the source.
/// </param>
/// <returns>An array of elements which were successfully written to
/// the source</returns>
///
public IList Write(IList content)
{
if (content == null)
{
return null;
}

// Get the total number of rows currently available it will


// determine how much to overwrite and how much to append at
// the end
string tableName;
int rowNumber;
PathType type = provider.GetNamesFromPath(path, out tableName,
out rowNumber);

if (type == PathType.Table)
{
OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
if (da == null)
{
return null;
}

DataSet ds = provider.GetDataSetForTable(da, tableName);


DataTable table = provider.GetDataTable(ds, tableName);

string[] colValues = (content[0] as string).Split(',');

// set the specified row


DataRow row = table.NewRow();

for (int i = 0; i < colValues.Length; i++)


{
if (!String.IsNullOrEmpty(colValues[i]))
{
row[i] = colValues[i];
}
}

//table.Rows.InsertAt(row, rowNumber);
// Update the table
table.Rows.Add(row);
da.Update(ds, tableName);
}
else
{
throw new InvalidOperationException("Operation not
supported. Content can be added only for tables");
}

return null;
} // Write

/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
/// <param name="offset">Number of rows to offset</param>
/// <param name="origin">Starting row from which to offset</param>
public void Seek(long offset, System.IO.SeekOrigin origin)
{
// get the number of rows in the table which will help in
// calculating current position
string tableName;
int rowNumber;

PathType type = provider.GetNamesFromPath(path, out tableName,


out rowNumber);

if (type == PathType.Invalid)
{
throw new ArgumentException("Path specified should represent
either a table or a row : " + path);
}

Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);

int numRows = rows.Count;

if (offset > rows.Count)


{
throw new
ArgumentException(
"Offset cannot be greater than the number of rows
available"
);
}

if (origin == System.IO.SeekOrigin.Begin)
{
// starting from Beginning with an index 0, the current
offset
// has to be advanced to offset - 1
currentOffset = offset - 1;
}
else if (origin == System.IO.SeekOrigin.End)
{
// starting from the end which is numRows - 1, the current
// offset is so much less than numRows - 1
currentOffset = numRows - 1 - offset;
}
else
{
// calculate from the previous value of current offset
// advancing forward always
currentOffset += offset;
}

} // Seek

/// <summary>
/// Closes the content reader, so all members are reset
/// </summary>
public void Close()
{
Dispose();
} // Close

/// <summary>
/// Dispose any resources being used
/// </summary>
public void Dispose()
{
Seek(0, System.IO.SeekOrigin.Begin);

GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentWriter

#endregion AccessDBContentWriter

#endregion Helper Classes


} // namespace Microsoft.Samples.PowerShell.Providers

Consulte también
System.Management.Automation.Provider.Itemcmdletprovider

System.Management.Automation.Provider.Containercmdletprovider

System.Management.Automation.Provider.Navigationcmdletprovider

Diseño del proveedor de Windows PowerShell


Inicio rápido de Host de Windows
PowerShell
Artículo • 26/01/2022

Para hospedar Windows PowerShell en la aplicación, use la clase


System.Management.Automation.PowerShell. Esta clase proporciona métodos que crean
una canalización de comandos y, a continuación, ejecutan esos comandos en un espacio
de ejecución. La manera más sencilla de crear una aplicación host es usar el espacio de
ejecución predeterminado. El espacio de ejecución predeterminado contiene todos los
comandos principales Windows PowerShell ejecución. Si desea que la aplicación
exponga solo un subconjunto de Windows PowerShell comandos, debe crear un espacio
de ejecución personalizado.

Uso del espacio de ejecución predeterminado


Para empezar, usaremos el espacio de ejecución predeterminado y usaremos los
métodos de la clase System.Management.Automation.PowerShell para agregar
comandos, parámetros, instrucciones y scripts a una canalización.

AddCommand
Use System.Management.Automation.PowerShell. AddCommand método para agregar
comandos a la canalización. Por ejemplo, supongamos que quiere obtener la lista de
procesos en ejecución en la máquina. La manera de ejecutar este comando es la
siguiente.

1. Cree un objeto System.Management.Automation.PowerShell.

C#

PowerShell ps = PowerShell.Create();

2. Agregue el comando que desea ejecutar.

C#

ps.AddCommand("Get-Process");

3. Invoque el comando .
C#

ps.Invoke();

Si llama al método más de una vez antes de llamar al método AddCommand


System.Management.Automation.PowerShell.Invoke, el resultado del primer comando se
canalizará al segundo, etc. Si no desea canalizar el resultado de un comando anterior a
un comando, agrégrelo llamando a System.Management.Automation.PowerShell.
AddStatement en su lugar.

AddParameter
En el ejemplo anterior se ejecuta un único comando sin parámetros. Puede agregar
parámetros al comando mediante System.Management.Automation.PSCommand.
AddParameter . Por ejemplo, el código siguiente obtiene una lista de todos los procesos
denominados que se PowerShell ejecutan en la máquina.

C#

PowerShell.Create().AddCommand("Get-Process")
.AddParameter("Name", "PowerShell")
.Invoke();

Puede agregar parámetros adicionales llamando al AddParameter método varias veces.

C#

PowerShell.Create().AddCommand("Get-ChildItem")
.AddParameter("Path", @"c:\Windows")
.AddParameter("Filter", "*.exe")
.Invoke();

También puede agregar un diccionario de nombres de parámetros y valores llamando a


System.Management.Automation.PowerShell. AddParameter método s.

C#

IDictionary parameters = new Dictionary<String, String>();


parameters.Add("Path", @"c:\Windows");
parameters.Add("Filter", "*.exe");

PowerShell.Create().AddCommand("Get-Process")
.AddParameters(parameters)
.Invoke()
AddStatement
Puede simular el procesamiento por lotes mediante
System.Management.Automation.PowerShell. AddStatement método , que agrega una
instrucción adicional al final de la canalización. El código siguiente obtiene una lista de
procesos en ejecución con el nombre y, a PowerShell continuación, obtiene la lista de
servicios en ejecución.

C#

PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-Process").AddParameter("Name", "PowerShell");
ps.AddStatement().AddCommand("Get-Service");
ps.Invoke();

AddScript
Puede ejecutar un script existente llamando a
System.Management.Automation.PowerShell. AddScript . En el ejemplo siguiente se
agrega un script a la canalización y se ejecuta. En este ejemplo se supone que ya hay un
script denominado MyScript.ps1 en una carpeta denominada D:\PSScripts .

C#

PowerShell ps = PowerShell.Create();
ps.AddScript("D:\PSScripts\MyScript.ps1").Invoke();

También hay una versión del método AddScript que toma un parámetro booleano
denominado useLocalScope . Si este parámetro se establece en true , el script se
ejecuta en el ámbito local. El código siguiente ejecutará el script en el ámbito local.

C#

PowerShell ps = PowerShell.Create();
ps.AddScript(@"D:\PSScripts\MyScript.ps1", true).Invoke();

Creación de un espacio de ejecución


personalizado
Aunque el espacio de ejecución predeterminado usado en los ejemplos anteriores carga
todos los comandos principales Windows PowerShell, puede crear un espacio de
ejecución personalizado que cargue solo un subconjunto especificado de todos los
comandos. Es posible que quiera hacerlo para mejorar el rendimiento (cargar un mayor
número de comandos es un éxito de rendimiento) o restringir la capacidad del usuario
para realizar operaciones. Un espacio de ejecución que expone solo un número limitado
de comandos se denomina espacio de ejecución restringido. Para crear un espacio de
ejecución restringido, use las clases
System.Management.Automation.Runspaces.Runspace y
System.Management.Automation.Runspaces.InitialSessionState.

Creación de un objeto InitialSessionState


Para crear un espacio de ejecución personalizado, primero debe crear un objeto
System.Management.Automation.Runspaces.InitialSessionState. En el ejemplo siguiente,
usamos System.Management.Automation.Runspaces.RunspaceFactory para crear un
espacio de ejecución después de crear un objeto InitialSessionState predeterminado.

C#

InitialSessionState iss = InitialSessionState.CreateDefault();


Runspace rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Get-Command");
ps.Invoke();

Restricción del espacio de ejecución


En el ejemplo anterior, creamos un objeto
System.Management.Automation.Runspaces.InitialSessionState predeterminado que
carga todos los núcleos integrados Windows PowerShell. También podríamos haber
llamado al método
System.Management.Automation.Runspaces.InitialSessionState.CreateDefault2 para
crear un objeto InitialSessionState que cargaría solo los comandos del complemento
Microsoft.PowerShell.Core. Para crear un espacio de ejecución más restringido, debe
crear un objeto InitialSessionState vacío llamando al método
System.Management.Automation.Runspaces.InitialSessionState.Create y, a continuación,
agregar comandos a InitialSessionState.
El uso de un espacio de ejecución que carga solo los comandos que especifique
proporciona un rendimiento considerablemente mejorado.

Use los métodos de la clase


System.Management.Automation.Runspaces.SessionStateCmdletEntry para definir
cmdlets para el estado de sesión inicial. En el ejemplo siguiente se crea un estado de
sesión inicial vacío y, a continuación, se definen y se agregan los Get-Command comandos
y al estado de sesión Import-Module inicial. A continuación, creamos un espacio de
ejecución restringido por ese estado de sesión inicial y ejecutamos los comandos en ese
espacio de ejecución.

Cree el estado de sesión inicial.

C#

InitialSessionState iss = InitialSessionState.Create();

Defina y agregue comandos al estado de sesión inicial.

C#

SessionStateCmdletEntry getCommand = new SessionStateCmdletEntry(


"Get-Command", typeof(Microsoft.PowerShell.Commands.GetCommandCommand),
"");
SessionStateCmdletEntry importModule = new SessionStateCmdletEntry(
"Import-Module",
typeof(Microsoft.PowerShell.Commands.ImportModuleCommand), "");
iss.Commands.Add(getCommand);
iss.Commands.Add(importModule);

Cree y abra el espacio de ejecución.

C#

Runspace rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();

Ejecute un comando y muestre el resultado.

C#

PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Get-Command");
Collection<CommandInfo> result = ps.Invoke<CommandInfo>();
foreach (var entry in result)
{
Console.WriteLine(entry.Name);
}

Cuando se ejecuta, la salida de este código tendrá el siguiente aspecto.

PowerShell

Get-Command
Import-Module
Creación de espacios de ejecución
Artículo • 25/09/2021

Un espacio de ejecución es el entorno operativo para los comandos invocados por una
aplicación host. Este entorno incluye los comandos y los datos que están presentes
actualmente, así como las restricciones de lenguaje que se aplican actualmente.

Las aplicaciones host pueden usar el espacio de ejecución predeterminado


proporcionado por Windows PowerShell, que incluye todos los comandos principales
disponibles, o crear un espacio de ejecución personalizado que incluya solo un
subconjunto de los comandos disponibles. Para crear un espacio de ejecución
personalizado, cree un objeto
System.Management.Automation.Runspaces.Initialsessionstate y asígnelo al espacio de
ejecución.

Tareas de espacio de ejecución


1. Creación de un InitialSessionState

2. Creación de un espacio de ejecución restringido

3. Creación de varios espacios de ejecución

Consulte también
Creación de un InitialSessionState
Artículo • 24/09/2021

Los comandos de PowerShell se ejecutan en un espacio de ejecución. Para hospedar


PowerShell en la aplicación, debe crear un objeto
System.Management.Automation.Runspaces.Runspace. Cada espacio de ejecución tiene
asociado un objeto System.Management.Automation.Runspaces.InitialSessionState.
InitialSessionState especifica características del espacio de ejecución, como qué
comandos, variables y módulos están disponibles para ese espacio de ejecución.

Creación de una initialSessionState


predeterminada
Los métodos CreateDefault y CreateDefault2 de la clase InitialSessionState se pueden
usar para crear un objeto InitialSessionState. El método CreateDefault crea un
InitialSessionState con todos los comandos integrados cargados, mientras que el
método CreateDefault2 carga solo los comandos necesarios para hospedar PowerShell
(los comandos del módulo Microsoft.PowerShell.Core).

Si desea limitar aún más los comandos disponibles en la aplicación host, debe crear un
espacio de ejecución restringido. Para obtener información, vea Creación de un espacio
de ejecución restringido.

El código siguiente muestra cómo crear un InitialSessionState, asignarlo a un espacio


de ejecución, agregar comandos a la canalización en ese espacio de ejecución e invocar
los comandos. Para obtener más información sobre cómo agregar e invocar comandos,
vea Agregar e invocar comandos.

C#

namespace SampleHost
{
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

class HostP4b
{
static void Main(string[] args)
{
// Call the InitialSessionState.CreateDefault method to create
// an empty InitialSessionState object, and then add the
// elements that will be available when the runspace is opened.
InitialSessionState iss = InitialSessionState.CreateDefault();
SessionStateVariableEntry var1 = new
SessionStateVariableEntry("test1",
"MyVar1",
"Initial session state MyVar1 test");
iss.Variables.Add(var1);

SessionStateVariableEntry var2 = new


SessionStateVariableEntry("test2",
"MyVar2",
"Initial session state MyVar2 test");
iss.Variables.Add(var2);

// Call the RunspaceFactory.CreateRunspace(InitialSessionState)


// method to create the runspace where the pipeline is run.
Runspace rs = RunspaceFactory.CreateRunspace(iss);
rs.Open();

// Call the PowerShell.Create() method to create the PowerShell


object,
// and then specify the runspace and commands to the pipeline.
// and create the command pipeline.
PowerShell ps = PowerShell.Create();
ps.Runspace = rs;
ps.AddCommand("Get-Variable");
ps.AddArgument("test*");

Console.WriteLine("Variable Value");
Console.WriteLine("--------------------------");

// Call the PowerShell.Invoke() method to run


// the pipeline synchronously.
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine("{0,-20}{1}",
result.Members["Name"].Value,
result.Members["Value"].Value);
} // End foreach.

// Close the runspace to free resources.


rs.Close();

} // End Main.
} // End SampleHost.
}

Consulte también
Creación de un espacio de ejecución restringido

Adición e invocación de comandos


Creación de un espacio de ejecución
restringido
Artículo • 24/09/2021

Por motivos de rendimiento o seguridad, puede restringir los Windows PowerShell


disponibles para la aplicación host. Para ello, cree un objeto
System.Management.Automation.Runspaces.Initialsessionstate vacío mediante una
llamada al método
System.Management.Automation.Runspaces.Initialsessionstate.Create* y agregue solo
los comandos que desee que estén disponibles.

El uso de un espacio de ejecución que carga solo los comandos que especifique
proporciona un rendimiento considerablemente mejorado.

Use los métodos de la clase


System.Management.Automation.Runspaces.Sessionstatecmdletentry para definir
cmdlets para el estado de sesión inicial.

También puede hacer que los comandos sea privado. La aplicación host puede usar
comandos privados, pero no los usuarios de la aplicación.

Agregar comandos a un espacio de ejecución


vacío
En el ejemplo siguiente se muestra cómo crear un InitialSessionState vacío y agregarle
comandos.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using Microsoft.PowerShell.Commands;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
internal class Runspace10b
{
/// <summary>
/// This sample shows how to create an empty initial session state,
/// how to add commands to the session state, and then how to create a
/// runspace that has only those two commands. A PowerShell object
/// is used to run the Get-Command cmdlet to show that only two commands
/// are available.
/// </summary>
/// <param name="args">Parameter not used.</param>
private static void Main(string[] args)
{
// Create an empty InitialSessionState and then add two commands.
InitialSessionState iss = InitialSessionState.Create();

// Add the Get-Process and Get-Command cmdlets to the session state.


SessionStateCmdletEntry ssce1 = new SessionStateCmdletEntry(
"get-process",

typeof(GetProcessCommand),
null);
iss.Commands.Add(ssce1);

SessionStateCmdletEntry ssce2 = new SessionStateCmdletEntry(


"get-command",

typeof(GetCommandCommand),
null);
iss.Commands.Add(ssce2);

// Create a runspace.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss))
{
myRunSpace.Open();
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = myRunSpace;

// Create a pipeline with the Get-Command command.


powershell.AddCommand("get-command");

Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Verb Noun");
Console.WriteLine("----------------------------");

// Display each result object.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["verb"].Value,
result.Members["Noun"].Value);
}
}

// Close the runspace and release any resources.


myRunSpace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Hacer que los comandos son privados


También puede hacer que un comando sea privado estableciendo su propiedad
System.Management.Automation.Commandinfo.Visibility en
System.Management.Automation.SessionStateEntryVisibility Private. La aplicación host y
otros comandos pueden llamar a ese comando, pero el usuario de la aplicación no. En el
ejemplo siguiente, el comando Get-ChildItem es privado.

C#

defaultSessionState = InitialSessionState.CreateDefault();
commandIndex = GetIndexOfEntry(defaultSessionState.Commands, "get-
childitem");
defaultSessionState.Commands[commandIndex].Visibility =
SessionStateEntryVisibility.Private;

this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();

Consulte también
Creación de un InitialSessionState
Creación de varios espacios de
ejecución
Artículo • 25/09/2021

Si crea un gran número de espacios de ejecución, puede considerar la posibilidad de


crear un grupo de espacios de ejecución. El uso de un objeto
System.Management.Automation.Runspaces.Runspacepool, en lugar de crear un gran
número de espacios de ejecución individuales con las mismas características, puede
mejorar el rendimiento.

Creación y uso de un grupo de espacios de


ejecución.
En el ejemplo siguiente se muestra cómo crear un grupo de espacios de ejecución y
cómo ejecutar un comando de forma asincrónica en un espacio de ejecución del grupo.

C#

namespace HostRunspacePool
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

/// <summary>
/// This class provides the Main entry point for the Host application.
/// </summary>
internal class HostRunspacePool
{
/// <summary>
/// This sample demonstrates the following.
/// 1. Creating and opening a runspace pool.
/// 2. Creating a PowerShell object.
/// 3. Adding commands and arguments to the PowerShell object.
/// 4. Running the commands asynchronously using the runspace
/// of the runspace pool.
/// </summary>
/// <param name="args">Parameter is not used.</param>
private static void Main(string[] args)
{
// Create a pool of runspaces.
using (RunspacePool rsp = RunspaceFactory.CreateRunspacePool())
{
rsp.Open();
// Create a PowerShell object to run the following command.
// get-process wmi*
PowerShell gpc = PowerShell.Create();
// Specify the runspace to use and add commands.
gpc.RunspacePool = rsp;
gpc.AddCommand("Get-Process").AddArgument("wmi*");

// Invoke the command asynchronously.


IAsyncResult gpcAsyncResult = gpc.BeginInvoke();
// Get the results of running the command.
PSDataCollection<PSObject> gpcOutput =
gpc.EndInvoke(gpcAsyncResult);

// Process the output.


Console.WriteLine("The output from running the command: get-process
wmi*");
for (int i= 0; i < gpcOutput.Count; i++)
{
Console.WriteLine(
"Process Name: {0} Process Id: {1}",
gpcOutput[i].Properties["ProcessName"].Value,
gpcOutput[i].Properties["Id"].Value);
}
} // End using.
} // End Main entry point.
} // End HostPs5 class.
}

Consulte también
Creación de un InitialSessionState
Adición e invocación de comandos
Artículo • 25/09/2021

Después de crear un espacio de ejecución, puede agregar Windows comandos y scripts


de PowerShell a una canalización y, a continuación, invocar la canalización de forma
sincrónica o asincrónica.

Creación de una canalización


La clase System.Management.Automation.Powershell proporciona varios métodos para
agregar comandos, parámetros y scripts a la canalización. Puede invocar la canalización
sincrónicamente llamando a una sobrecarga del método
System.Management.Automation.Powershell.Invoke* o de forma asincrónica llamando a
una sobrecarga del método System.Management.Automation.Powershell.Begininvoke*
y, a continuación, al método System.Management.Automation.Powershell.Endinvoke*.

AddCommand
1. Cree un objeto System.Management.Automation.Powershell.

C#

PowerShell ps = PowerShell.Create();

2. Agregue el comando que desea ejecutar.

C#

ps.AddCommand("Get-Process");

3. Invoque el comando .

C#

ps.Invoke();

Si llama al método System.Management.Automation.Powershell.Addcommand* más de


una vez antes de llamar al método System.Management.Automation.Powershell.Invoke*,
el resultado del primer comando se canalizará al segundo, etc. Si no desea canalizar el
resultado de un comando anterior a un comando, agrégrelo llamando a
System.Management.Automation.Powershell.Addstatement* en su lugar.

AddParameter
En el ejemplo anterior se ejecuta un único comando sin parámetros. Puede agregar
parámetros al comando mediante el método
System.Management.Automation.Pscommand.Addparameter*. Por ejemplo, el código
siguiente obtiene una lista de todos los procesos denominados que se ejecutan en la
PowerShell máquina.

C#

PowerShell.Create().AddCommand("Get-Process")
.AddParameter("Name", "PowerShell")
.Invoke();

Puede agregar parámetros adicionales llamando repetidamente a


System.Management.Automation.Pscommand.Addparameter*.

C#

PowerShell.Create().AddCommand("Get-Command")
.AddParameter("Name", "Get-VM")
.AddParameter("Module", "Hyper-V")
.Invoke();

También puede agregar un diccionario de nombres de parámetros y valores llamando al


método System.Management.Automation.Powershell.Addparameters*.

C#

IDictionary parameters = new Dictionary<String, String>();


parameters.Add("Name", "Get-VM");

parameters.Add("Module", "Hyper-V");
PowerShell.Create().AddCommand("Get-Command")
.AddParameters(parameters)
.Invoke()

AddStatement
Puede simular el procesamiento por lotes mediante el método
System.Management.Automation.Powershell.Addstatement*, que agrega una instrucción
adicional al final de la canalización. El código siguiente obtiene una lista de procesos en
ejecución con el nombre y, a continuación, obtiene la lista de servicios en PowerShell
ejecución.

C#

PowerShell ps = PowerShell.Create();
ps.AddCommand("Get-Process").AddParameter("Name", "PowerShell");
ps.AddStatement().AddCommand("Get-Service");
ps.Invoke();

AddScript
Puede ejecutar un script existente llamando al método
System.Management.Automation.Powershell.Addscript*. En el ejemplo siguiente se
agrega un script a la canalización y se ejecuta. En este ejemplo se supone que ya hay un
script denominado MyScript.ps1 en una carpeta denominada D:\PSScripts .

C#

PowerShell ps = PowerShell.Create();
ps.AddScript(File.ReadAllText(@"D:\PSScripts\MyScript.ps1")).Invoke();

También hay una versión del método


System.Management.Automation.Powershell.Addscript* que toma un parámetro
booleano denominado useLocalScope . Si este parámetro se establece en true , el script
se ejecuta en el ámbito local. El código siguiente ejecutará el script en el ámbito local.

C#

PowerShell ps = PowerShell.Create();
ps.AddScript(File.ReadAllText(@"D:\PSScripts\MyScript.ps1"), true).Invoke();

Invocación sincrónica de una canalización


Después de agregar elementos a la canalización, invoquelo. Para invocar la canalización
de forma sincrónica, llame a una sobrecarga del método
System.Management.Automation.Powershell.Invoke*. En el ejemplo siguiente se muestra
cómo invocar sincrónicamente una canalización.
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;

namespace HostPS1e
{
class HostPS1e
{
static void Main(string[] args)
{
// Using the PowerShell.Create and AddCommand
// methods, create a command pipeline.
PowerShell ps = PowerShell.Create().AddCommand ("Sort-Object");

// Using the PowerShell.Invoke method, run the command


// pipeline using the supplied input.
foreach (PSObject result in ps.Invoke(new int[] { 3, 1, 6, 2, 5, 4 }))
{
Console.WriteLine("{0}", result);
} // End foreach.
} // End Main.
} // End HostPS1e.
}

Invocación asincrónica de una canalización


Para invocar una canalización de forma asincrónica, llame a una sobrecarga del objeto
System.Management.Automation.Powershell.Begininvoke* para crear un objeto
IAsyncResult y, a continuación, llame al método
System.Management.Automation.Powershell.Endinvoke*.

En el ejemplo siguiente se muestra cómo invocar una canalización de forma asincrónica.

C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management.Automation;

namespace HostPS3
{
class HostPS3
{
static void Main(string[] args)
{
// Use the PowerShell.Create and PowerShell.AddCommand
// methods to create a command pipeline that includes
// Get-Process cmdlet. Do not include spaces immediately
// before or after the cmdlet name as that will cause
// the command to fail.
PowerShell ps = PowerShell.Create().AddCommand("Get-Process");

// Create an IAsyncResult object and call the


// BeginInvoke method to start running the
// command pipeline asynchronously.
IAsyncResult asyncpl = ps.BeginInvoke();

// Using the PowerShell.Invoke method, run the command


// pipeline using the default runspace.
foreach (PSObject result in ps.EndInvoke(asyncpl))
{
Console.WriteLine("{0,-20}{1}",
result.Members["ProcessName"].Value,
result.Members["Id"].Value);
} // End foreach.
System.Console.WriteLine("Hit any key to exit.");
System.Console.ReadKey();
} // End Main.
} // End HostPS3.
}

Consulte también
Creación de un InitialSessionState

Creación de un espacio de ejecución restringido


Creación de espacios de ejecución
remotos
Artículo • 24/09/2021

Los comandos de PowerShell que toman un parámetro ComputerName se pueden


ejecutar en cualquier equipo que ejecute PowerShell. Para ejecutar comandos que no
toman un parámetro ComputerName, puede usar WS-Management para configurar un
espacio de ejecución que se conecta a un equipo especificado y ejecutar comandos en
ese equipo.

Uso de WSManConnection para crear un


espacio de ejecución remoto
Para crear un espacio de ejecución que se conecte a un equipo remoto, cree un objeto
System.Management.Automation.Runspaces.WSManConnectionInfo. Especifique el
punto de conexión de destino para la conexión estableciendo la propiedad
System.Management.Automation.Runspaces.WSManConnectionInfo.ConnectionUri del
objeto . A continuación, cree un espacio de ejecución mediante una llamada al método
System.Management.Automation.Runspaces.RunspaceFactory.CreateRunspace y
especifique el objeto
System.Management.Automation.Runspaces.WSManConnectionInfo como
connectionInfo parámetro.

En el ejemplo siguiente se muestra cómo crear un espacio de ejecución que se conecta


a un equipo remoto. En el ejemplo, RemoteComputerUri se usa como marcador de
posición para el URI real de un equipo remoto.

C#

namespace Samples
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation; // PowerShell namespace.
using System.Management.Automation.Runspaces; // PowerShell namespace.

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class RemoteRunspace02
{
/// <summary>
/// This sample shows how to create a remote runspace that
/// runs commands on the local computer.
/// </summary>
/// <param name="args">Parameter not used.</param>
private static void Main(string[] args)
{
// Create a WSManConnectionInfo object using the default constructor
// to connect to the "localHost". The WSManConnectionInfo object can
// also be used to specify connections to remote computers.
Uri RemoteComputerUri = new Uri("http://Server01:5985/WSMAN");
WSManConnectionInfo connectionInfo = new
WSManConnectionInfo(RemoteComputerUri);

// Set the OperationTimeout property and OpenTimeout properties.


// The OperationTimeout property is used to tell PowerShell
// how long to wait (in milliseconds) before timing out for an
// operation. The OpenTimeout property is used to tell Windows
// PowerShell how long to wait (in milliseconds) before timing out
// while establishing a remote connection.
connectionInfo.OperationTimeout = 4 * 60 * 1000; // 4 minutes.
connectionInfo.OpenTimeout = 1 * 60 * 1000; // 1 minute.

// Create a remote runspace using the connection information.


//using (Runspace remoteRunspace = RunspaceFactory.CreateRunspace())
using (Runspace remoteRunspace =
RunspaceFactory.CreateRunspace(connectionInfo))
{
// Establish the connection by calling the Open() method to open the
runspace.
// The OpenTimeout value set previously will be applied while
establishing
// the connection. Establishing a remote connection involves sending
and
// receiving some data, so the OperationTimeout will also play a
role in this process.
remoteRunspace.Open();

// Create a PowerShell object to run commands in the remote


runspace.
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = remoteRunspace;
powershell.AddCommand("get-process");
powershell.Invoke();

Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the results.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

// Close the connection. Call the Close() method to close the remote
// runspace. The Dispose() method (called by using primitive) will
call
// the Close() method if it is not already called.
remoteRunspace.Close();
}
}
}
}
Creación de una interfaz de usuario
personalizada
Artículo • 07/10/2021

Windows PowerShell proporciona clases e interfaces abstractas que permiten crear una
interfaz de usuario interactiva personalizada que hospeda el motor Windows PowerShell
usuario. Para crear una interfaz de usuario personalizada, debe implementar la clase
System.Management.Automation.Host.PSHost. Opcionalmente, también puede
implementar las clases System.Management.Automation.Host.Pshostrawuserinterface y
System.Management.Automation.Host.Pshostuserinterface, y las interfaces
System.Management.Automation.Host.Ihostsupportsinteractivesession y
System.Management.Automation.Host.Ihostuisupportsmultiplechoiceselection.
Ejemplos de aplicación host
Artículo • 25/09/2021

En esta sección se incluye código de ejemplo que se proporciona en el SDK Windows


PowerShell 2.0.

En esta sección
Ejemplos de API de PowerShell En esta sección se incluye código de ejemplo que
muestra cómo crear espacios de ejecución que restringen la funcionalidad y cómo
ejecutar comandos de forma asincrónica mediante un grupo de espacios de ejecución
para proporcionar los espacios de ejecución.

Ejemplos de host personalizado Incluye código de ejemplo para escribir un host


personalizado. El host es el componente de Windows PowerShell que proporciona
comunicaciones entre el usuario y el Windows PowerShell motor. Para obtener más
información sobre los hosts personalizados, vea Host personalizado.

Ejemplos de espacio de ejecución Incluye código de ejemplo para crear espacios de


ejecución. Para obtener más información sobre cómo se usan los espacios de ejecución,
vea Host Application Runspaces.

Ejemplos de espacio de ejecución remoto En esta sección se incluye código de ejemplo


que muestra cómo crear espacios de ejecución que se pueden usar para conectarse a un
equipo mediante la comunicación remota Windows PowerShell WS-Management.

Consulte también
Ejemplos de API de Windows
PowerShell
Artículo • 25/09/2021

En esta sección se incluye código de ejemplo que muestra cómo crear espacios de
ejecución que restringen la funcionalidad y cómo ejecutar comandos de forma
asincrónica mediante un grupo de espacios de ejecución para proporcionar los espacios
de ejecución. Puede usar Microsoft Visual Studio para crear una aplicación de consola y,
a continuación, copiar el código de los temas de esta sección en la aplicación host.

En esta sección
Ejemplo de PowerShell01 En este ejemplo se muestra cómo usar un objeto
System.Management.Automation.Runspaces.Initialsessionstate para limitar la
funcionalidad de un espacio de ejecución. La salida de este ejemplo muestra cómo
restringir el modo de lenguaje del espacio de ejecución, cómo marcar un cmdlet como
privado, cómo agregar y quitar cmdlets y proveedores, cómo agregar un comando de
proxy y mucho más.

Ejemplo de PowerShell02 En este ejemplo se muestra cómo ejecutar comandos de


forma asincrónica mediante los espacios de ejecución de un grupo de espacios de
ejecución. El ejemplo genera una lista de comandos y, a continuación, ejecuta esos
comandos mientras el motor de Windows PowerShell abre un espacio de ejecución del
grupo cuando es necesario.
Ejemplo Windows PowerShell01
Artículo • 25/09/2021

En este ejemplo se muestra cómo usar un objeto


System.Management.Automation.Runspaces.Initialsessionstate para limitar la
funcionalidad de un espacio de ejecución. En la salida de este ejemplo se muestra cómo
restringir el modo de lenguaje del espacio de ejecución, cómo marcar un cmdlet como
privado, cómo agregar y quitar cmdlets y proveedores, cómo agregar un comando de
proxy y mucho más. Este ejemplo se centra en cómo restringir el espacio de ejecución
mediante programación. Entre las alternativas de scripting a la restricción del espacio de
ejecución se incluyen los comandos $ExecutionContext.SessionState.LanguageMode y
PSSessionConfiguration.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente:

Restrinja el lenguaje estableciendo la propiedad


System.Management.Automation.Runspaces.Initialsessionstate.Languagemode.

¿Agregar alias al estado de sesión inicial mediante


System.Management.Automation.Runspaces.Sessionstatealiasentry? Objeto
Displayproperty=Fullname.

Marcar los comandos como privados.

Quitar proveedores del estado de sesión inicial mediante la propiedad


System.Management.Automation.Runspaces.Initialsessionstate.Providers.

Quitar comandos del estado de sesión inicial mediante la propiedad


System.Management.Automation.Runspaces.Initialsessionstate.Commands.

Agregar comandos y proveedores al objeto


System.Management.Automation.Runspaces.Initialsessionstate.

Ejemplo
En este ejemplo se muestran varias maneras de limitar la funcionalidad de un espacio de
ejecución.

C#

namespace Sample
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
internal class PowerShell01
{
/// <summary>
/// The runspace used to run commands.
/// </summary>
private Runspace runspace;

/// <summary>
/// Return the first index of the entry in <paramref name="entries"/>
/// with the name <paramref name="name"/>. Return -1 if it is not found.
/// </summary>
/// <typeparam name="T">Type of ConstrainedSessionStateEntry</typeparam>
/// <param name="entries">Collection of entries to search for <paramref
name="name"/> in.</param>
/// <param name="name">Named of the entry we are looking for</param>
/// <returns>
/// The first index of the entry in <paramref name="entries"/> with the
/// name <paramref name="name"/>, or return -1 if it is not found.
/// </returns>
private static int GetIndexOfEntry<T>(
InitialSessionStateEntryCollection<T> entries,
string name) where T : ConstrainedSessionStateEntry
{
int foundIndex = 0;
foreach (T entry in entries)
{
if (entry.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
{
return foundIndex;
}

foundIndex++;
}

return -1;
}

/// <summary>
/// Run commands to demonstrate the ways to constrain the runspace.
/// </summary>
/// <param name="args">This parameter is unused.</param>
private static void Main(string[] args)
{
new PowerShell01().RunCommands();
}

/// <summary>
/// Run a script to display the results and errors.
/// </summary>
/// <param name="script">Script to be run.</param>
/// <param name="scriptComment">Comment to be printed about
/// the script.</param>
private void RunScript(string script, string scriptComment)
{
Console.WriteLine("Running '{0}'\n{1}.\n\nPowerShell Output:", script,
scriptComment);

// Using a PowerShell object, create a pipeline, add the script to the


// pipeline, and specify the runspace where the pipeline is invoked.
PowerShell powerShellCommand = PowerShell.Create();
powerShellCommand.AddScript(script);
powerShellCommand.Runspace = this.runspace;

try
{
Collection<PSObject> results = powerShellCommand.Invoke();

// Display the results.


foreach (PSObject result in results)
{
Console.WriteLine(result);
}

// Display any non-terminating errors.


foreach (ErrorRecord error in powerShellCommand.Streams.Error)
{
Console.WriteLine("PowerShell Error: {0}", error);
}
}
catch (RuntimeException ex)
{
Console.WriteLine("PowerShell Error: {0}", ex.Message);
Console.WriteLine();
}

Console.WriteLine("\n-----------------------------\n");
}

/// <summary>
/// Run some commands to demonstrate the script capabilities.
/// </summary>
private void RunCommands()
{
this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.Open();
this.RunScript("$a=0;$a", "Assigning to a variable will work for a
default InitialSessionState");
this.runspace.Close();

this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.InitialSessionState.LanguageMode =
PSLanguageMode.RestrictedLanguage;
this.runspace.Open();
this.RunScript("$a=0;$a", "Assigning to a variable will not work in
RestrictedLanguage LanguageMode");
this.runspace.Close();

this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.InitialSessionState.LanguageMode =
PSLanguageMode.NoLanguage;
this.runspace.Open();
this.RunScript("10/2", "A script will not work in NoLanguage
LanguageMode.");
this.runspace.Close();

this.runspace =
RunspaceFactory.CreateRunspace(InitialSessionState.CreateDefault());
this.runspace.Open();
string scriptComment = "get-childitem with a default
InitialSessionState will work since the standard \n" +
"PowerShell cmdlets are included in the default
InitialSessionState";
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();

InitialSessionState defaultSessionState =
InitialSessionState.CreateDefault();
defaultSessionState.Commands.Add(new SessionStateAliasEntry("dir2",
"get-childitem"));
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
this.RunScript("dir2", "An alias, like dir2, can be added to
InitialSessionState");
this.runspace.Close();

defaultSessionState = InitialSessionState.CreateDefault();
int commandIndex = GetIndexOfEntry(defaultSessionState.Commands, "get-
childitem");
defaultSessionState.Commands.RemoveItem(commandIndex);
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
scriptComment = "get-childitem was removed from the list of commands
so it\nwill no longer be found";
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();
defaultSessionState = InitialSessionState.CreateDefault();
defaultSessionState.Providers.Clear();
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
this.RunScript("get-childitem", "There are no providers so get-
childitem will not work");
this.runspace.Close();

// Marks a command as private, and then defines a proxy command


// that uses the private command. One reason to define a proxy for
// a command is to remove a parameter of the original command.
// For a more complete sample of a proxy command, see the Runspace11
// sample.
defaultSessionState = InitialSessionState.CreateDefault();
commandIndex = GetIndexOfEntry(defaultSessionState.Commands, "get-
childitem");
defaultSessionState.Commands[commandIndex].Visibility =
SessionStateEntryVisibility.Private;
CommandMetadata getChildItemMetadata = new CommandMetadata(
typeof(Microsoft.PowerShell.Commands.GetChildItemCommand));
getChildItemMetadata.Parameters.Remove("Recurse");
string getChildItemBody = ProxyCommand.Create(getChildItemMetadata);
defaultSessionState.Commands.Add(new SessionStateFunctionEntry("get-
childitem2", getChildItemBody));
this.runspace = RunspaceFactory.CreateRunspace(defaultSessionState);
this.runspace.Open();
this.RunScript("get-childitem", "get-childitem is private so it will
not be available");
scriptComment = "get-childitem2 is a proxy to get-childitem. \n" +
"It works even when get-childitem is private.";
this.RunScript("get-childitem2", scriptComment);
scriptComment = "This will fail. Unlike get-childitem, get-childitem2
does not have -Recurse";
this.RunScript("get-childitem2 -Recurse", scriptComment);

InitialSessionState cleanSessionState = InitialSessionState.Create();


this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState);
this.runspace.Open();
scriptComment = "A script will not work because \n" +
"InitialSessionState.Create() will have the default
LanguageMode of NoLanguage";
this.RunScript("10/2", scriptComment);
this.runspace.Close();

cleanSessionState = InitialSessionState.Create();
cleanSessionState.LanguageMode = PSLanguageMode.FullLanguage;
this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState);
this.runspace.Open();
scriptComment = "get-childitem, standard cmdlets and providers are not
present \n" +
"in an InitialSessionState returned from
InitialSessionState.Create()";
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();
cleanSessionState = InitialSessionState.Create();
cleanSessionState.Commands.Add(
new SessionStateCmdletEntry(
"Get-ChildItem",

typeof(Microsoft.PowerShell.Commands.GetChildItemCommand),
null));
cleanSessionState.Providers.Add(
new SessionStateProviderEntry(
"FileSystem",

typeof(Microsoft.PowerShell.Commands.FileSystemProvider),
null));
cleanSessionState.LanguageMode = PSLanguageMode.FullLanguage;
this.runspace = RunspaceFactory.CreateRunspace(cleanSessionState);
this.runspace.Open();
scriptComment = "get-childitem and the FileSystem provider were
explicitly added\n" +
"so get-childitem will work";
this.RunScript("get-childitem", scriptComment);
this.runspace.Close();

Console.Write("Done...");
Console.ReadLine();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Windows PowerShell02
Artículo • 24/09/2021

En este ejemplo se muestra cómo ejecutar comandos de forma asincrónica mediante los
espacios de ejecución de un grupo de espacios de ejecución. El ejemplo genera una lista
de comandos y, a continuación, ejecuta esos comandos mientras el motor de Windows
PowerShell abre un espacio de ejecución desde el grupo cuando es necesario.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente:

Crear un objeto RunspacePool con un número mínimo y máximo de espacios de


ejecución permitidos para abrirse al mismo tiempo.
Crear una lista de comandos.
Ejecutar los comandos de forma asincrónica.
Llamar al método
System.Management.Automation.Runspaces.Runspacepool.Getavailablerunspaces*
para ver cuántos espacios de ejecución son gratuitos.
Captura de la salida del comando con el método
System.Management.Automation.Powershell.Endinvoke*.

Ejemplo
En este ejemplo se muestra cómo abrir los espacios de ejecución de un grupo de
espacios de ejecución y cómo ejecutar comandos de forma asincrónica en esos espacios
de ejecución.

C#

namespace Sample
{
using System;
using System.Collections;
using System.Collections.Generic;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
internal class PowerShell02
{
/// <summary>
/// Runs many commands with the help of a RunspacePool.
/// </summary>
/// <param name="args">This parameter is unused.</param>
private static void Main(string[] args)
{
// Creating and opening runspace pool. Use a minimum of 1 runspace and
a maximum of
// 5 runspaces can be opened at the same time.
RunspacePool runspacePool = RunspaceFactory.CreateRunspacePool(1, 5);
runspacePool.Open();

using (runspacePool)
{
// Define the commands to be run.
List<PowerShell> powerShellCommands = new List<PowerShell>();

// The command results.


List<IAsyncResult> powerShellCommandResults = new List<IAsyncResult>
();

// The maximum number of runspaces that can be opened at one time is


// 5, but we can queue up many more commands that will use the
// runspace pool.
for (int i = 0; i < 100; i++)
{
// Using a PowerShell object, run the commands.
PowerShell powershell = PowerShell.Create();

// Instead of setting the Runspace property of powershell,


// the RunspacePool property is used. That is the only difference
// between running commands with a runspace and running commands
// with a runspace pool.
powershell.RunspacePool = runspacePool;

// The script to be run outputs a sequence number and the number


of available runspaces
// in the pool.
string script = String.Format(
"write-output ' Command: {0}, Available Runspaces:
{1}'",
i,
runspacePool.GetAvailableRunspaces());

// The three lines below look the same running with a runspace or
// with a runspace pool.
powershell.AddScript(script);
powerShellCommands.Add(powershell);
powerShellCommandResults.Add(powershell.BeginInvoke());
}

// Collect the results.


for (int i = 0; i < 100; i++)
{
// EndInvoke will wait for each command to finish, so we will be
getting the commands
// in the same 0 to 99 order that they have been invoked withy
BeginInvoke.
PSDataCollection<PSObject> results =
powerShellCommands[i].EndInvoke(powerShellCommandResults[i]);

// Print all the results. One PSObject with a plain string is the
expected result.
PowerShell02.PrintCollection(results);
}
}
}

/// <summary>
/// Iterates through a collection printing all items.
/// </summary>
/// <param name="collection">collection to be printed</param>
private static void PrintCollection(IList collection)
{
foreach (object obj in collection)
{
Console.WriteLine("PowerShell Result: {0}", obj);
}
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplos de host personalizado
Artículo • 24/09/2021

En esta sección se incluye código de ejemplo para escribir un host personalizado. Puede
usar Microsoft Visual Studio para crear una aplicación de consola y, a continuación,
copiar el código de los temas de esta sección en la aplicación host.

En esta sección
Ejemplo host01 En este ejemplo se muestra cómo implementar una aplicación host que
usa un host personalizado básico.

Ejemplo de Host02 En este ejemplo se muestra cómo escribir una aplicación host que
usa Windows PowerShell runtime junto con una implementación de host personalizada.
La aplicación host establece la referencia cultural del host en alemán, ejecuta el cmdlet
Get-Process y muestra los resultados como los vería mediante pwrsh.exe y, a
continuación, imprime los datos y la hora actuales en alemán.

Ejemplo host03 En este ejemplo se muestra cómo compilar una aplicación host
interactiva basada en consola que lee comandos desde la línea de comandos, ejecuta
los comandos y, a continuación, muestra los resultados en la consola.

Ejemplo host04 En este ejemplo se muestra cómo compilar una aplicación host
interactiva basada en consola que lee comandos desde la línea de comandos, ejecuta
los comandos y, a continuación, muestra los resultados en la consola. Esta aplicación
host también permite mostrar avisos para que el usuario pueda especificar varias
opciones.

Ejemplo de Host05 En este ejemplo se muestra cómo compilar una aplicación host
interactiva basada en consola que lee comandos desde la línea de comandos, ejecuta
los comandos y, a continuación, muestra los resultados en la consola. Esta aplicación
host también admite llamadas a equipos remotos mediante los cmdlets Enter-PsSession
y Exit-PsSession.

Ejemplo de Host06 En este ejemplo se muestra cómo compilar una aplicación host
interactiva basada en consola que lee comandos desde la línea de comandos, ejecuta
los comandos y, a continuación, muestra los resultados en la consola. Además, este
ejemplo utiliza las API de Tokenizer para especificar el color del texto que el usuario ha
escrito.
Consulte también
Ejemplo Host01
Artículo • 24/09/2021

En este ejemplo se muestra cómo implementar una aplicación host que usa un host
personalizado. En este ejemplo se crea un espacio de ejecución que usa el host
personalizado y, a continuación, se usa la API
System.Management.Automation.Powershell para ejecutar un script que llama a "exit".
La aplicación host examina después la salida del script e imprime los resultados.

En este ejemplo se usan las características predeterminadas de la interfaz de usuario


proporcionadas por Windows PowerShell. Para obtener más información sobre cómo
implementar las características de la interfaz de usuario de un host personalizado, vea
Host02 Sample.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
Crear una clase host personalizada que se derive de la clase
System.Management.Automation.Host.PSHost.

Crear un espacio de ejecución que use la clase host personalizada.

Crear un objeto System.Management.Automation.Powershell que ejecuta un script


que llama a exit.

Comprobar que se usó el código de salida correcto en el proceso de salida.

Ejemplo 1
El código siguiente muestra una implementación de una aplicación host que usa una
interfaz de host personalizada simple.

C#

namespace Microsoft.Samples.PowerShell.Host
{

using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Host01
{

/// <summary>
/// Indicator to tell the host application that it should exit.
/// </summary>
private bool shouldExit;

/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
private int exitCode;

/// <summary>
/// Gets or sets a value indicating whether the
/// host application should exit.
/// </summary>
public bool ShouldExit
{
get { return this.shouldExit; }
set { this.shouldExit = value; }
}

/// <summary>
/// Gets or sets the PSHost implementation that is
/// used to tell the host application what code to use
/// when exiting.
/// </summary>
public int ExitCode
{
get { return this.exitCode; }
set { this.exitCode = value; }
}

/// <summary>
/// This sample uses a PowerShell object to run
/// a script that calls exit. The host application looks at
/// this and prints out the result.
/// </summary>
/// <param name="args">Parameter not used.</param>
private static void Main(string[] args)
{
// Create an instance of this host application class so that
// the Windows PowerShell engine will have access to the
// ShouldExit and ExitCode parameters.
Host01 me = new Host01();

// Create the host instance to use.


MyHost myHost = new MyHost(me);
// Create a runspace that uses the host object and run the
// script using a PowerShell object.
using (Runspace myRunSpace =
RunspaceFactory.CreateRunspace(myHost))
{
// Open the runspace.
myRunSpace.Open();

// Create a PowerShell object to run the script.


using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = myRunSpace;

// Create the pipeline and run the script


// "exit (2+2)".
string script = "exit (2+2)";
powershell.AddScript(script);
powershell.Invoke(script);
}

// Check the flags and see if they were set propertly.


Console.WriteLine(
"ShouldExit={0} (should be True); ExitCode={1} (should
be 4)",
me.ShouldExit,
me.ExitCode);

// close the runspace to free resources.


myRunSpace.Close();
}

Console.WriteLine("Hit any key to exit...");


Console.ReadKey();
}
}
}

Ejemplo 2
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHost que usa esta aplicación host. Los
elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Globalization;
using System.Management.Automation.Host;
/// <summary>
/// This is a sample implementation of the PSHost abstract class for
/// console applications. Not all members are implemented. Those that
/// are not implemented throw a NotImplementedException exception or
/// return nothing.
/// </summary>
internal class MyHost : PSHost
{
/// <summary>
/// A reference to the PSHost implementation.
/// </summary>
private Host01 program;

/// <summary>
/// The culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalCultureInfo =
System.Threading.Thread.CurrentThread.CurrentCulture;

/// <summary>
/// The UI culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalUICultureInfo =
System.Threading.Thread.CurrentThread.CurrentUICulture;

/// <summary>
/// The identifier of this PSHost implementation.
/// </summary>
private Guid myId = Guid.NewGuid();

/// <summary>
/// Initializes a new instance of the MyHost class. Keep
/// a reference to the host application object so that it
/// can be informed of when to exit.
/// </summary>
/// <param name="program">
/// A reference to the host application object.
/// </param>
public MyHost(Host01 program)
{
this.program = program;
}

/// <summary>
/// Return the culture information to use. This implementation
/// returns a snapshot of the culture information of the thread
/// that created this object.
/// </summary>
public override System.Globalization.CultureInfo CurrentCulture
{
get { return this.originalCultureInfo; }
}
/// <summary>
/// Return the UI culture information to use. This implementation
/// returns a snapshot of the UI culture information of the thread
/// that created this object.
/// </summary>
public override System.Globalization.CultureInfo CurrentUICulture
{
get { return this.originalUICultureInfo; }
}

/// <summary>
/// This implementation always returns the GUID allocated at
/// instantiation time.
/// </summary>
public override Guid InstanceId
{
get { return this.myId; }
}

/// <summary>
/// Return a string that contains the name of the host
implementation.
/// Keep in mind that this string may be used by script writers to
/// identify when your host is being used.
/// </summary>
public override string Name
{
get { return "MySampleConsoleHostImplementation"; }
}

/// <summary>
/// This sample does not implement a PSHostUserInterface component
so
/// this property simply returns null.
/// </summary>
public override PSHostUserInterface UI
{
get { return null; }
}

/// <summary>
/// Return the version object for this application. Typically this
/// should match the version resource in the application.
/// </summary>
public override Version Version
{
get { return new Version(1, 0, 0, 0); }
}

/// <summary>
/// Not implemented by this example class. The call fails with
/// a NotImplementedException exception.
/// </summary>
public override void EnterNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// Not implemented by this example class. The call fails
/// with a NotImplementedException exception.
/// </summary>
public override void ExitNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API is called before an external application process is
/// started. Typically it is used to save state so the parent can
/// restore state that has been modified by a child process (after
/// the child exits). In this example, this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyBeginApplication()
{
return;
}

/// <summary>
/// This API is called after an external application process
finishes.
/// Typically it is used to restore state that a child process may
/// have altered. In this example, this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyEndApplication()
{
return;
}

/// <summary>
/// Indicate to the host application that exit has
/// been requested. Pass the exit code that the host
/// application should use when exiting the process.
/// </summary>
/// <param name="exitCode">The exit code to use.</param>
public override void SetShouldExit(int exitCode)
{
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
}
}
}
Consulte también
Ejemplo Host02
Artículo • 25/09/2021

En este ejemplo se muestra cómo escribir una aplicación host que usa el entorno
Windows PowerShell tiempo de ejecución junto con una implementación de host
personalizada. La aplicación host establece la referencia cultural del host en alemán,
ejecuta el cmdlet Get-Process, muestra los resultados tal como los vería con pwrsh.exe e
imprime los datos y la hora actuales en alemán.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
Crear un host personalizado cuyas clases derivan de la clase
System.Management.Automation.Host.PSHost, la clase
System.Management.Automation.Host.PSHostUserInterface y la clase
System.Management.Automation.Host.PSHostRawUserInterface.

Crear un espacio de ejecución que use el host personalizado.

Establecer la referencia cultural del host en alemán.

Al crear un objeto System.Management.Automation.Powershell que ejecuta un


script para recuperar y ordenar los procesos, se recupera la fecha actual que se
muestra en alemán.

Ejemplo 1
El código siguiente muestra una implementación de una aplicación host que usa el host
personalizado.

C#

// Copyright (c) 2006 Microsoft Corporation. All rights reserved.


//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Host
{
class Host02
{
/// <summary>
/// Define the property that the PSHost implementation will
/// use to tell the host application that it should exit.
/// </summary>
public bool ShouldExit
{
get { return shouldExit; }
set { shouldExit = value; }
}
private bool shouldExit;

/// <summary>
/// Define the property that the PSHost implementation will
/// use to tell the host application what exit code to use
/// when exiting.
/// </summary>
public int ExitCode
{
get { return exitCode; }
set { exitCode = value; }
}
private int exitCode;

/// <summary>
/// This sample uses the PowerShell runtime along with a host
/// implementation to call get-process and display the results
/// as you would see them in powershell.exe.
/// </summary>
/// <param name="args">Ignored</param>
static void Main(string[] args)
{
// Set the current culture to German. We want this to be picked up
when the MyHost
// instance is created...
System.Threading.Thread.CurrentThread.CurrentCulture =
CultureInfo.GetCultureInfo("de-de");

// Create the runspace so that you can access the pipeline.


MyHost myHost = new MyHost(new Host02());

Runspace myRunSpace = RunspaceFactory.CreateRunspace(myHost);


myRunSpace.Open();
// Create the pipeline.
Pipeline pipe = myRunSpace.CreatePipeline();

// Add the script we want to run. This script does two things.
// First, it runs the Get-Process cmdlet with the cmdlet output
// sorted by handle count. Second, the GetDate cmdlet is piped
// to the Out-String cmdlet so that we can see the
// date displayed in German.

pipe.Commands.AddScript(@"
get-process | sort handlecount
# This should display the date in German...
get-date | out-string
");

// Add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// and PSHostUserInterface classes instead of returning objects to the
hosting
// application.
pipe.Commands.Add("out-default");

pipe.Commands[0].MergeMyResults(PipelineResultTypes.Error,PipelineResultType
s.Output);

// Invoke the pipeline. There will not be any objects


// returned. The Out-Default cmdlet consumes the objects.
pipe.Invoke();

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Ejemplo 2
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHost que usa esta aplicación host. Los
elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Globalization;
using System.Management.Automation.Host;
/// <summary>
/// This is a sample implementation of the PSHost abstract class for
/// console applications. Not all members are implemented. Those that
/// are not implemented throw a NotImplementedException exception or
/// return nothing.
/// </summary>
internal class MyHost : PSHost
{
/// <summary>
/// A reference to the PSHost implementation.
/// </summary>
private Host02 program;

/// <summary>
/// The culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalCultureInfo =
System.Threading.Thread.CurrentThread.CurrentCulture;

/// <summary>
/// The UI culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalUICultureInfo =
System.Threading.Thread.CurrentThread.CurrentUICulture;

/// <summary>
/// The identifier of this PSHost implementation.
/// </summary>
private Guid myId = Guid.NewGuid();

/// <summary>
/// Initializes a new instance of the MyHost class. Keep
/// a reference to the host application object so that it
/// can be informed of when to exit.
/// </summary>
/// <param name="program">
/// A reference to the host application object.
/// </param>
public MyHost(Host02 program)
{
this.program = program;
}

/// <summary>
/// A reference to the implementation of the PSHostUserInterface
/// class for this application.
/// </summary>
private MyHostUserInterface myHostUserInterface = new
MyHostUserInterface();

/// <summary>
/// Gets the culture information to use. This implementation
/// returns a snapshot of the culture information of the thread
/// that created this object.
/// </summary>
public override System.Globalization.CultureInfo CurrentCulture
{
get { return this.originalCultureInfo; }
}

/// <summary>
/// Gets the UI culture information to use. This implementation
/// returns a snapshot of the UI culture information of the thread
/// that created this object.
/// </summary>
public override System.Globalization.CultureInfo CurrentUICulture
{
get { return this.originalUICultureInfo; }
}

/// <summary>
/// Gets an identifier for this host. This implementation always
/// returns the GUID allocated at instantiation time.
/// </summary>
public override Guid InstanceId
{
get { return this.myId; }
}

/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// identify when your host is being used.
/// </summary>
public override string Name
{
get { return "MySampleConsoleHostImplementation"; }
}

/// <summary>
/// Gets an instance of the implementation of the PSHostUserInterface
/// class for this application. This instance is allocated once at
startup time
/// and returned every time thereafter.
/// </summary>
public override PSHostUserInterface UI
{
get { return this.myHostUserInterface; }
}

/// <summary>
/// Gets the version object for this application. Typically this
/// should match the version resource in the application.
/// </summary>
public override Version Version
{
get { return new Version(1, 0, 0, 0); }
}
/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// functionality is not needed so the method throws a
/// NotImplementedException exception.
/// </summary>
public override void EnterNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// In this example this functionality is not needed so the method
/// throws a NotImplementedException exception.
/// </summary>
public override void ExitNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API is called before an external application process is
/// started. Typically it is used to save state so that the parent
/// can restore state that has been modified by a child process (after
/// the child exits). In this example this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyBeginApplication()
{
return;
}

/// <summary>
/// This API is called after an external application process finishes.
/// Typically it is used to restore state that a child process has
/// altered. In this example, this functionality is not needed so
/// the method returns nothing.
/// </summary>
public override void NotifyEndApplication()
{
return;
}

/// <summary>
/// Indicate to the host application that exit has
/// been requested. Pass the exit code that the host
/// application should use when exiting the process.
/// </summary>
/// <param name="exitCode">The exit code that the
/// host application should use.</param>
public override void SetShouldExit(int exitCode)
{
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
}
}
}

Ejemplo 3
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHostUserInterface que usa esta aplicación
host.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;

/// <summary>
/// A sample implementation of the PSHostUserInterface abstract class for
/// console applications. Not all members are implemented. Those that are
/// not implemented throw a NotImplementedException exception. Members
that
/// are implemented include those that map easily to Console APIs.
/// </summary>
internal class MyHostUserInterface : PSHostUserInterface
{
/// <summary>
/// An instance of the PSRawUserInterface class.
/// </summary>
private MyRawUserInterface myRawUi = new MyRawUserInterface();

/// <summary>
/// Gets an instance of the PSRawUserInterface class for this host
/// application.
/// </summary>
public override PSHostRawUserInterface RawUI
{
get { return this.myRawUi; }
}

/// <summary>
/// Prompts the user for input. In this example this functionality is
not
/// needed so the method throws a NotImplementException exception.
/// </summary>
/// <param name="caption">The caption or title of the prompt.</param>
/// <param name="message">The text of the prompt.</param>
/// <param name="descriptions">A collection of FieldDescription objects
that
/// describe each field of the prompt.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override Dictionary<string, PSObject> Prompt(
string caption,
string message,

System.Collections.ObjectModel.Collection<FieldDescription> descriptions)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// Provides a set of choices that enable the user to choose a
/// single option from a set of options. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
describes
/// each choice.</param>
/// <param name="defaultChoice">The index of the label in the Choices
parameter
/// collection. To indicate no default choice, set to -1.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override int PromptForChoice(string caption, string message,
System.Collections.ObjectModel.Collection<ChoiceDescription> choices, int
defaultChoice)
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Prompts the user for credentials with a specified prompt window
caption,
/// prompt message, user name, and target name. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
prompted for.</param>
/// <param name="targetName">The name of the target for which the
credential is collected.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName)
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Prompts the user for credentials by using a specified prompt window
caption,
/// prompt message, user name and target name, credential types allowed
to be
/// returned, and UI behavior options. In this example this
functionality
/// is not needed so the method throws a NotImplementException
exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
prompted for.</param>
/// <param name="targetName">The name of the target for which the
credential is collected.</param>
/// <param name="allowedCredentialTypes">A PSCredentialTypes constant
that
/// identifies the type of credentials that can be returned.</param>
/// <param name="options">A PSCredentialUIOptions constant that
identifies the UI
/// behavior when it gathers the credentials.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions
options)
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Reads characters that are entered by the user until a newline
/// (carriage return) is encountered.
/// </summary>
/// <returns>The characters that are entered by the user.</returns>
public override string ReadLine()
{
return Console.ReadLine();
}

/// <summary>
/// Reads characters entered by the user until a newline (carriage
return)
/// is encountered and returns the characters as a secure string. In
this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <returns>Throws a NotImplemented exception.</returns>
public override System.Security.SecureString ReadLineAsSecureString()
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Writes characters to the output display of the host.
/// </summary>
/// <param name="value">The characters to be written.</param>
public override void Write(string value)
{
System.Console.Write(value);
}

/// <summary>
/// Writes characters to the output display of the host and specifies
the
/// foreground and background colors of the characters. This
implementation
/// ignores the colors.
/// </summary>
/// <param name="foregroundColor">The color of the characters.</param>
/// <param name="backgroundColor">The background color to use.</param>
/// <param name="value">The characters to be written.</param>
public override void Write(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
// Colors are ignored.
System.Console.Write(value);
}

/// <summary>
/// Writes a debug message to the output display of the host.
/// </summary>
/// <param name="message">The debug message that is displayed.</param>
public override void WriteDebugLine(string message)
{
Console.WriteLine(String.Format(
CultureInfo.CurrentCulture,
"DEBUG: {0}",
message));
}

/// <summary>
/// Writes an error message to the output display of the host.
/// </summary>
/// <param name="value">The error message that is displayed.</param>
public override void WriteErrorLine(string value)
{
Console.WriteLine(String.Format(
CultureInfo.CurrentCulture,
"ERROR: {0}",
value));
}

/// <summary>
/// Writes a newline character (carriage return)
/// to the output display of the host.
/// </summary>
public override void WriteLine()
{
System.Console.WriteLine();
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// and appends a newline character(carriage return).
/// </summary>
/// <param name="value">The line to be written.</param>
public override void WriteLine(string value)
{
System.Console.WriteLine(value);
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// with foreground and background colors and appends a newline
(carriage return).
/// </summary>
/// <param name="foregroundColor">The foreground color of the display.
</param>
/// <param name="backgroundColor">The background color of the display.
</param>
/// <param name="value">The line to be written.</param>
public override void WriteLine(ConsoleColor foregroundColor,
ConsoleColor backgroundColor, string value)
{
// Write to the output stream, ignore the colors
System.Console.WriteLine(value);
}

/// <summary>
/// Writes a progress report to the output display of the host.
/// </summary>
/// <param name="sourceId">Unique identifier of the source of the
record. </param>
/// <param name="record">A ProgressReport object.</param>
public override void WriteProgress(long sourceId, ProgressRecord record)
{
}

/// <summary>
/// Writes a verbose message to the output display of the host.
/// </summary>
/// <param name="message">The verbose message that is displayed.</param>
public override void WriteVerboseLine(string message)
{
Console.WriteLine(String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
}

/// <summary>
/// Writes a warning message to the output display of the host.
/// </summary>
/// <param name="message">The warning message that is displayed.</param>
public override void WriteWarningLine(string message)
{
Console.WriteLine(String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
}
}
}

Ejemplo 4
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHostRawUserInterface que usa esta aplicación
host. Los elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Management.Automation.Host;

/// <summary>
/// A sample implementation of the PSHostRawUserInterface for console
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// implemented and throw a NotImplementedException exception.
/// </summary>
internal class MyRawUserInterface : PSHostRawUserInterface
{
/// <summary>
/// Gets or sets the background color of the displayed text.
/// This maps to the corresponding Console.Background property.
/// </summary>
public override ConsoleColor BackgroundColor
{
get { return Console.BackgroundColor; }
set { Console.BackgroundColor = value; }
}

/// <summary>
/// Gets or sets the size of the host buffer. In this example the
/// buffer size is adapted from the Console buffer size members.
/// </summary>
public override Size BufferSize
{
get { return new Size(Console.BufferWidth, Console.BufferHeight); }
set { Console.SetBufferSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the cursor position. In this example this
/// functionality is not needed so the property throws a
/// NotImplementException exception.
/// </summary>
public override Coordinates CursorPosition
{
get { throw new NotImplementedException(
"The method or operation is not implemented."); }
set { throw new NotImplementedException(
"The method or operation is not implemented."); }
}

/// <summary>
/// Gets or sets the size of the displayed cursor. In this example
/// the cursor size is taken directly from the Console.CursorSize
/// property.
/// </summary>
public override int CursorSize
{
get { return Console.CursorSize; }
set { Console.CursorSize = value; }
}

/// <summary>
/// Gets or sets the foreground color of the displayed text.
/// This maps to the corresponding Console.ForegroundColor property.
/// </summary>
public override ConsoleColor ForegroundColor
{
get { return Console.ForegroundColor; }
set { Console.ForegroundColor = value; }
}

/// <summary>
/// Gets a value indicating whether the user has pressed a key. This
maps
/// to the corresponding Console.KeyAvailable property.
/// </summary>
public override bool KeyAvailable
{
get { return Console.KeyAvailable; }
}

/// <summary>
/// Gets the dimensions of the largest window that could be
/// rendered in the current display, if the buffer was at the least
/// that large. This example uses the Console.LargestWindowWidth and
/// Console.LargestWindowHeight properties to determine the returned
/// value of this property.
/// </summary>
public override Size MaxPhysicalWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets the dimensions of the largest window size that can be
/// displayed. This example uses the Console.LargestWindowWidth and
/// console.LargestWindowHeight properties to determine the returned
/// value of this property.
/// </summary>
public override Size MaxWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets or sets the position of the displayed window. This example
/// uses the Console window position APIs to determine the returned
/// value of this property.
/// </summary>
public override Coordinates WindowPosition
{
get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
set { Console.SetWindowPosition(value.X, value.Y); }
}

/// <summary>
/// Gets or sets the size of the displayed window. This example
/// uses the corresponding Console window size APIs to determine the
/// returned value of this property.
/// </summary>
public override Size WindowSize
{
get { return new Size(Console.WindowWidth, Console.WindowHeight); }
set { Console.SetWindowSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the title of the displayed window. The example
/// maps the Console.Title property to the value of this property.
/// </summary>
public override string WindowTitle
{
get { return Console.Title; }
set { Console.Title = value; }
}

/// <summary>
/// This API resets the input buffer. In this example this
/// functionality is not needed so the method returns nothing.
/// </summary>
public override void FlushInputBuffer()
{
}

/// <summary>
/// This API returns a rectangular region of the screen buffer. In
/// this example this functionality is not needed so the method throws
/// a NotImplementException exception.
/// </summary>
/// <param name="rectangle">Defines the size of the rectangle.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API reads a pressed, released, or pressed and released
keystroke
/// from the keyboard device, blocking processing until a keystroke is
/// typed that matches the specified keystroke options. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="options">Options, such as IncludeKeyDown, used when
/// reading the keyboard.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override KeyInfo ReadKey(ReadKeyOptions options)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API crops a region of the screen buffer. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="source">The region of the screen to be scrolled.
</param>
/// <param name="destination">The region of the screen to receive the
/// source region contents.</param>
/// <param name="clip">The region of the screen to include in the
operation.</param>
/// <param name="fill">The character and attributes to be used to fill
all cell.</param>
public override void ScrollBufferContents(Rectangle source, Coordinates
destination, Rectangle clip, BufferCell fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This method copies an array of buffer cells into the screen buffer
/// at a specified location. In this example this functionality is
/// not needed so the method throws a NotImplementedException exception.
/// </summary>
/// <param name="origin">The parameter is not used.</param>
/// <param name="contents">The parameter is not used.</param>
public override void SetBufferContents(Coordinates origin,
BufferCell[,] contents)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This method copies a given character, foreground color, and
background
/// color to a region of the screen buffer. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception./// </summary>
/// <param name="rectangle">Defines the area to be filled. </param>
/// <param name="fill">Defines the fill character.</param>
public override void SetBufferContents(Rectangle rectangle, BufferCell
fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
}
}

Consulte también
System.Management.Automation.Powershell

System.Management.Automation.Host.PSHost

System.Management.Automation.Host.Pshostuserinterface

System.Management.Automation.Host.Pshostrawuserinterface
Ejemplo Host03
Artículo • 24/09/2021

En este ejemplo se muestra cómo compilar una aplicación host interactiva basada en
consola que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
Crear un host personalizado cuyas clases derivan de la clase
System.Management.Automation.Host.PSHost, la clase
System.Management.Automation.Host.PSHostUserInterface y la clase
System.Management.Automation.Host.PSHostRawUserInterface.

Compilación de una aplicación de consola que usa estas clases host para compilar
un shell Windows PowerShell interactivo.

Ejemplo 1
Este ejemplo permite al usuario escribir comandos en una línea de comandos, procesa
esos comandos y, a continuación, imprime los resultados.

C#

// Copyright (c) 2006 Microsoft Corporation. All rights reserved.


//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;
/// This class contains the Main entry point for this host application.
internal class PSListenerConsoleSample
{
/// Indicator to tell the host application that it should exit.
private bool shouldExit;

/// The exit code that the host application will use to exit.
private int exitCode;

/// Holds the instance of the PSHost implementation for this


interpreter.
private MyHost myHost;

/// Holds the runspace for this interpreter.


private Runspace myRunSpace;

/// Holds a reference to the currently executing pipeline so it can be


/// stopped by the control-C handler.
private PowerShell currentPowerShell;

/// Used to serialize access to instance data.


private object instanceLock = new object();

/// Create this instance of the console listener.


private PSListenerConsoleSample()
{
// Create the host and runspace instances for this interpreter.
// Note that this application does not support console files so
// only the default snapins will be available.
this.myHost = new MyHost(this);
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();
}

/// Gets or sets a value indicating whether the host application


/// should exit.
public bool ShouldExit
{
get { return this.shouldExit; }
set { this.shouldExit = value; }
}

/// Gets or sets the exit code that the host application will use
/// when exiting.
public int ExitCode
{
get { return this.exitCode; }
set { this.exitCode = value; }
}

/// Creates and initiates the listener instance.


/// param name="args";This parameter is not used.
private static void Main(string[] args)
{
// Display the welcome message...
Console.Title = "PowerShell Console Host Sample Application";
ConsoleColor oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" PowerShell Console Host Interactive Sample");
Console.WriteLine(" =====================================");
Console.WriteLine(string.Empty);
Console.WriteLine("This is an example of a simple interactive console
host that uses the ");
Console.WriteLine("Windows PowerShell engine to interpret commands.
Type 'exit' to exit.");
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;

// Create the listener and run it - this never returns...


PSListenerConsoleSample listener = new PSListenerConsoleSample();
listener.Run();
}

/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// the caller. Since all output goes to the default outputter, this
method()
/// won't return anything.
/// param name="cmd"; The script to run.
/// param name="input";Any input arguments to pass to the script. If
null
/// then nothing is passed in.
private void executeHelper(string cmd, object input)
{
// Ignore empty command lines.
if (String.IsNullOrEmpty(cmd))
{
return;
}

// Create the pipeline object and make it available


// to the ctrl-C handle through the currentPowerShell instance
// variable
lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

this.currentPowerShell.Runspace = this.myRunSpace;

// Create a pipeline for this execution. Place the result in the


// currentPowerShell instance variable so that it is available
// to be stopped.
try
{
this.currentPowerShell.AddScript(cmd);
// Now add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// and PSHostUserInterface classes instead of returning objects to
the hosting
// application.
this.currentPowerShell.AddCommand("out-default");

this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);

// If there was any input specified, pass it in, otherwise just


// execute the pipeline.
if (input != null)
{
this.currentPowerShell.Invoke(new object[] { input });
}
else
{
this.currentPowerShell.Invoke();
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because
// currentPowerShell may be accessed by the ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}

/// An exception occurred that we want to display


/// using the display formatter. To do this we run
/// a second pipeline passing in the error record.
/// The runtime will bind this to the $input variable
/// which is why $input is being piped to out-string.
/// We then call WriteErrorLine to make sure the error
/// gets displayed in the correct error color.

/// param name="e"; The exception to display.


private void ReportException(Exception e)
{
if (e != null)
{
object error;
IContainsErrorRecord icer = e as IContainsErrorRecord;
if (icer != null)
{
error = icer.ErrorRecord;
}
else
{
error = (object)new ErrorRecord(e, "Host.ReportException",
ErrorCategory.NotSpecified, null);
}

lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

this.currentPowerShell.Runspace = this.myRunSpace;

try
{
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");

// Do not merge errors, this function will swallow errors.


Collection<PSObject> result;
PSDataCollection<object> inputCollection = new
PSDataCollection<object>();
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);

if (result.Count > 0)
{
string str = result[0].BaseObject as string;
if (!string.IsNullOrEmpty(str))
{
// Remove \r\n that is added by Out-string.
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
}
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because
currentPowerShell
// may be accessed by the ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}
}

/// Basic script execution routine - any runtime exceptions are


/// caught and passed back into the engine to display.

/// param name="cmd"; The parameter is not used.


private void Execute(string cmd)
{
try
{
// Execute the command with no input.
this.executeHelper(cmd, null);
}
catch (RuntimeException rte)
{
this.ReportException(rte);
}
}

/// Method used to handle control-C's from the user. It calls the
/// pipeline Stop() method to stop execution. If any exceptions occur
/// they are printed to the console but otherwise ignored.

/// param name="sender"; See sender property of


ConsoleCancelEventHandler documentation.
/// param name="e"; See e property of ConsoleCancelEventHandler
documentation.
private void HandleControlC(object sender, ConsoleCancelEventArgs e)
{
try
{
lock (this.instanceLock)
{
if (this.currentPowerShell != null &&
this.currentPowerShell.InvocationStateInfo.State ==
PSInvocationState.Running)
{
this.currentPowerShell.Stop();
}
}

e.Cancel = true;
}
catch (Exception exception)
{
this.myHost.UI.WriteErrorLine(exception.ToString());
}
}

/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// flag is set.
private void Run()
{
// Set up the control-C handler.
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;

// Read commands to execute until ShouldExit is set by


// the user calling "exit".
while (!this.ShouldExit)
{
this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black,
"\nPSConsoleSample: ");
string cmd = Console.ReadLine();
this.Execute(cmd);
}

// Exit with the desired exit code that was set by exit command.
// This is set in the host by the MyHost.SetShouldExit()
implementation.
Environment.Exit(this.ExitCode);
}
}
}

Ejemplo 2
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHost que usa esta aplicación host. Los
elementos que no se implementan inician una excepción o no devuelven nada.

C#

// Copyright (c) 2006 Microsoft Corporation. All rights reserved.


//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;

namespace Microsoft.Samples.PowerShell.Host
{
/// <summary>
/// Simple PowerShell interactive console host listener implementation.
This class
/// implements a basic read-evaluate-print loop or 'listener' allowing you
to
/// interactively work with the PowerShell runtime.
/// </summary>
class PSListenerConsoleSample
{
/// <summary>
/// Define the property that the PSHost implementation will use to tell
the host
/// application that it should exit.
/// </summary>
public bool ShouldExit
{
get { return shouldExit; }
set { shouldExit = value; }
}
private bool shouldExit;

/// <summary>
/// Define the property that the PSHost implementation will use to tell
the host
/// application what code to use when exiting.
/// </summary>
public int ExitCode
{
get { return exitCode; }
set { exitCode = value; }
}
private int exitCode;
/// <summary>
/// Holds the instance of the PSHost implementation for this
interpreter.
/// </summary>
private MyHost myHost;

/// <summary>
/// Holds the runspace for this interpreter.
/// </summary>
private Runspace myRunSpace;

/// <summary>
/// Holds a reference to the currently executing pipeline so it can be
/// stopped by the control-C handler.
/// </summary>
private Pipeline currentPipeline;

/// <summary>
/// Used to serialize access to instance data...
/// </summary>
private object instanceLock = new object();

/// <summary>
/// Create this instance of the console listener.
/// </summary>
PSListenerConsoleSample()
{
// Create the host and runspace instances for this interpreter. Note
that
// this application doesn't support console files so only the default
snapins
// will be available.
myHost = new MyHost(this);
myRunSpace = RunspaceFactory.CreateRunspace(myHost);
myRunSpace.Open();
}

/// <summary>
/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// the caller. Since all output goes to the default outputter, this
method()
/// won't return anything.
/// </summary>
/// <param name="cmd">The script to run</param>
/// <param name="input">Any input arguments to pass to the script. If
null
/// then nothing is passed in.</param>
void executeHelper(string cmd, object input)
{
// Ignore empty command lines.
if (String.IsNullOrEmpty(cmd))
return;

// Create the pipeline object and make it available


// to the ctrl-C handle through the currentPipeline instance
// variable.
lock (instanceLock)
{
currentPipeline = myRunSpace.CreatePipeline();
}

// Create a pipeline for this execution. Place the result in the


currentPipeline
// instance variable so that it is available to be stopped.
try
{
currentPipeline.Commands.AddScript(cmd);

// Now add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// and PSHostUserInterface classes instead of returning objects to
the hosting
// application.
currentPipeline.Commands.Add("out-default");

currentPipeline.Commands[0].MergeMyResults(PipelineResultTypes.Error,
PipelineResultTypes.Output);

// If there was any input specified, pass it in, otherwise just


// execute the pipeline.
if (input != null)
{
currentPipeline.Invoke(new object[] { input });
}
else
{
currentPipeline.Invoke();
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because
currentPipeline
// may be accessed by the ctrl-C handler.
lock (instanceLock)
{
currentPipeline.Dispose();
currentPipeline = null;
}
}
}

/// <summary>
/// Basic script execution routine - any runtime exceptions are
/// caught and passed back into the runtime to display.
/// </summary>
/// <param name="cmd"></param>
void Execute(string cmd)
{
try
{
// execute the command with no input...
executeHelper(cmd, null);
}
catch (RuntimeException rte)
{
// An exception occurred that we want to display
// using the display formatter. To do this we run
// a second pipeline passing in the error record.
// The runtime will bind this to the $input variable
// which is why $input is being piped to out-default
executeHelper("$input | out-default", rte.ErrorRecord);
}
}

/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// pipeline Stop() method to stop execution. If any exceptions occur,
/// they are printed to the console; otherwise they are ignored.
/// </summary>
/// <param name="sender">See ConsoleCancelEventHandler
documentation</param>
/// <param name="e">See ConsoleCancelEventHandler documentation</param>
void HandleControlC(object sender, ConsoleCancelEventArgs e)
{
try
{
lock (instanceLock)
{
if (currentPipeline != null &&
currentPipeline.PipelineStateInfo.State == PipelineState.Running)
currentPipeline.Stop();
}
e.Cancel = true;
}
catch (Exception exception)
{
this.myHost.UI.WriteErrorLine(exception.ToString());
}
}

/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// flag is set.
/// </summary>
private void Run()
{
// Set up the control-C handler.
Console.CancelKeyPress += new
ConsoleCancelEventHandler(HandleControlC);
Console.TreatControlCAsInput = false;

// Loop reading commands to execute until ShouldExit is set by


// the user calling "exit".
while (!ShouldExit)
{
myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black,
"\nPSConsoleSample: ");
string cmd = Console.ReadLine();
Execute(cmd);
}

// Exit with the desired exit code that was set by exit command.
// This is set in the host by the MyHost.SetShouldExit()
implementation.
Environment.Exit(ExitCode);
}

/// <summary>
/// Creates and initiates the listener instance.
/// </summary>
/// <param name="args">Ignored for now.</param>
static void Main(string[] args)
{
// Display the welcome message.
Console.Title = "PowerShell Console Host Sample Application";
ConsoleColor oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" PowerShell Console Host Interactive Sample");
Console.WriteLine(" =====================================");
Console.WriteLine("");
Console.WriteLine("This is an example of a simple interactive console
host using the PowerShell");
Console.WriteLine("engine to interpret commands. Type 'exit' to
exit.");
Console.WriteLine("");
Console.ForegroundColor = oldFg;

// Create the listener and run it - this never returns.


PSListenerConsoleSample listener = new PSListenerConsoleSample();
listener.Run();
}
}
}

Ejemplo 3
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHostUserInterface que usa esta aplicación
host.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;

/// <summary>
/// A sample implementation of the PSHostUserInterface abstract class for
/// console applications. Not all members are implemented. Those that are
/// not implemented throw a NotImplementedException exception or return
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
internal class MyHostUserInterface : PSHostUserInterface
{
/// <summary>
/// An instance of the PSRawUserInterface object.
/// </summary>
private MyRawUserInterface myRawUi = new MyRawUserInterface();

/// <summary>
/// Gets an instance of the PSRawUserInterface object for this host
/// application.
/// </summary>
public override PSHostRawUserInterface RawUI
{
get { return this.myRawUi; }
}

/// <summary>
/// Prompts the user for input.
/// <param name="caption">The caption or title of the prompt.</param>
/// <param name="message">The text of the prompt.</param>
/// <param name="descriptions">A collection of FieldDescription objects
that
/// describe each field of the prompt.</param>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
public override Dictionary<string, PSObject> Prompt(
string caption,
string message,
Collection<FieldDescription>
descriptions)
{
this.Write(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + " ");
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
foreach (FieldDescription fd in descriptions)
{
string[] label = GetHotkeyAndLabel(fd.Label);
this.WriteLine(label[1]);
string userData = Console.ReadLine();
if (userData == null)
{
return null;
}

results[fd.Name] = PSObject.AsPSObject(userData);
}

return results;
}

/// <summary>

/// Provides a set of choices that enable the user to choose a


/// single option from a set of options.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
describe
/// each choice.</param>
/// <param name="defaultChoice">The index of the label in the Choices
parameter
/// collection. To indicate no default choice, set to -1.</param>
/// <returns>The index of the Choices parameter collection element that
corresponds
/// to the option that is selected by the user.</returns>
public override int PromptForChoice(
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
{
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + "\n");

// Convert the choice collection into something that is easier to


// work with. See the BuildHotkeysAndPlainLabels method for details.
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
string[,] promptData = BuildHotkeysAndPlainLabels(choices);

// Format the overall choice prompt string to display...


StringBuilder sb = new StringBuilder();
for (int element = 0; element < choices.Count; element++)
{
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"|{0}> {1} ",
promptData[0, element],
promptData[1, element]));
}

sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));

// Read prompts until a match is made, the default is


// chosen, or the loop is interrupted with ctrl-C.
while (true)
{
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);

// If the choice string was empty, use the default selection.


if (data.Length == 0)
{
return defaultChoice;
}

// See if the selection matched and return the


// corresponding index if it did.
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
{
return i;
}
}

this.WriteErrorLine("Invalid choice: " + data);


}
}

/// <summary>
/// Prompts the user for credentials with a specified prompt window
caption,
/// prompt message, user name, and target name. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
prompted for.</param>
/// <param name="targetName">The name of the target for which the
credential is collected.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName)
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Prompts the user for credentials by using a specified prompt window
caption,
/// prompt message, user name and target name, credential types allowed
to be
/// returned, and UI behavior options. In this example this
functionality
/// is not needed so the method throws a NotImplementException
exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
prompted for.</param>
/// <param name="targetName">The name of the target for which the
credential is collected.</param>
/// <param name="allowedCredentialTypes">A PSCredentialTypes constant
that
/// identifies the type of credentials that can be returned.</param>
/// <param name="options">A PSCredentialUIOptions constant that
identifies the UI
/// behavior when it gathers the credentials.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions
options)
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Reads characters that are entered by the user until a newline
/// (carriage return) is encountered.
/// </summary>
/// <returns>The characters that are entered by the user.</returns>
public override string ReadLine()
{
return Console.ReadLine();
}

/// <summary>
/// Reads characters entered by the user until a newline (carriage
return)
/// is encountered and returns the characters as a secure string. In
this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <returns>Throws a NotImplemented exception.</returns>
public override System.Security.SecureString ReadLineAsSecureString()
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Writes characters to the output display of the host.
/// </summary>
/// <param name="value">The characters to be written.</param>
public override void Write(string value)
{
Console.Write(value);
}

/// <summary>
/// Writes characters to the output display of the host with possible
/// foreground and background colors.
/// </summary>
/// <param name="foregroundColor">The color of the characters.</param>
/// <param name="backgroundColor">The background color to use.</param>
/// <param name="value">The characters to be written.</param>
public override void Write(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// with foreground and background colors and appends a newline
(carriage return).
/// </summary>
/// <param name="foregroundColor">The foreground color of the display.
</param>
/// <param name="backgroundColor">The background color of the display.
</param>
/// <param name="value">The line to be written.</param>
public override void WriteLine(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}

/// <summary>
/// Writes a debug message to the output display of the host.
/// </summary>
/// <param name="message">The debug message that is displayed.</param>
public override void WriteDebugLine(string message)
{
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}",
message));
}
/// <summary>
/// Writes an error message to the output display of the host.
/// </summary>
/// <param name="value">The error message that is displayed.</param>
public override void WriteErrorLine(string value)
{
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
}

/// <summary>
/// Writes a newline character (carriage return)
/// to the output display of the host.
/// </summary>
public override void WriteLine()
{
Console.WriteLine();
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// and appends a newline character(carriage return).
/// </summary>
/// <param name="value">The line to be written.</param>
public override void WriteLine(string value)
{
Console.WriteLine(value);
}

/// <summary>
/// Writes a progress report to the output display of the host.
/// </summary>
/// <param name="sourceId">Unique identifier of the source of the
record. </param>
/// <param name="record">A ProgressReport object.</param>
public override void WriteProgress(long sourceId, ProgressRecord record)
{

/// <summary>
/// Writes a verbose message to the output display of the host.
/// </summary>
/// <param name="message">The verbose message that is displayed.</param>
public override void WriteVerboseLine(string message)
{
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
}
/// <summary>
/// Writes a warning message to the output display of the host.
/// </summary>
/// <param name="message">The warning message that is displayed.</param>
public override void WriteWarningLine(string message)
{
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
}

/// <summary>
/// This is a private worker function splits out the
/// accelerator keys from the menu and builds a two
/// dimensional array with the first access containing the
/// accelerator and the second containing the label string
/// with the & removed.
/// </summary>
/// <param name="choices">The choice collection to process</param>
/// <returns>
/// A two dimensional array containing the accelerator characters
/// and the cleaned-up labels</returns>
private static string[,] BuildHotkeysAndPlainLabels(
Collection<ChoiceDescription> choices)
{
// Allocate the result array.
string[,] hotkeysAndPlainLabels = new string[2, choices.Count];
for (int i = 0; i < choices.Count; ++i)
{
string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}

return hotkeysAndPlainLabels;
}

/// <summary>
/// Parse a string containing a hotkey character.
/// Take a string of the form
/// Yes to &all
/// and returns a two-dimensional array split out as
/// "A", "Yes to all".
/// </summary>
/// <param name="input">The string to process</param>
/// <returns>
/// A two dimensional array containing the parsed components.
/// </returns>
private static string[] GetHotkeyAndLabel(string input)
{
string[] result = new string[] { String.Empty, String.Empty };
string[] fragments = input.Split('&');
if (fragments.Length == 2)
{
if (fragments[1].Length > 0)
{
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
}

result[1] = (fragments[0] + fragments[1]).Trim();


}
else
{
result[1] = input;
}

return result;
}
}
}

Ejemplo 4
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHostRawUserInterface que usa esta aplicación
host. Los elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Management.Automation.Host;

/// <summary>
/// A sample implementation of the PSHostRawUserInterface for console
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// implemented and throw a NotImplementedException exception.
/// </summary>
internal class MyRawUserInterface : PSHostRawUserInterface
{
/// <summary>
/// Gets or sets the background color of text to be written.
/// This maps to the corresponding Console.Background property.
/// </summary>
public override ConsoleColor BackgroundColor
{
get { return Console.BackgroundColor; }
set { Console.BackgroundColor = value; }
}
/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// size members.
/// </summary>
public override Size BufferSize
{
get { return new Size(Console.BufferWidth, Console.BufferHeight); }
set { Console.SetBufferSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the cursor position. In this example this
/// functionality is not needed so the property throws a
/// NotImplementException exception.
/// </summary>
public override Coordinates CursorPosition
{
get { throw new NotImplementedException(
"The method or operation is not implemented."); }
set { throw new NotImplementedException(
"The method or operation is not implemented."); }
}

/// <summary>
/// Gets or sets the cursor size taken directly from the
/// Console.CursorSize property.
/// </summary>
public override int CursorSize
{
get { return Console.CursorSize; }
set { Console.CursorSize = value; }
}

/// <summary>
/// Gets or sets the foreground color of the text to be written.
/// This maps to the corresponding Console.ForegroundColor property.
/// </summary>
public override ConsoleColor ForegroundColor
{
get { return Console.ForegroundColor; }
set { Console.ForegroundColor = value; }
}

/// <summary>
/// Gets a value indicating whether a key is available. This maps to
/// the corresponding Console.KeyAvailable property.
/// </summary>
public override bool KeyAvailable
{
get { return Console.KeyAvailable; }
}

/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// Console.LargestWindowWidth and Console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxPhysicalWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets the maximum window size adapted from the
/// Console.LargestWindowWidth and console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
public override Coordinates WindowPosition
{
get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
set { Console.SetWindowPosition(value.X, value.Y); }
}

/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
public override Size WindowSize
{
get { return new Size(Console.WindowWidth, Console.WindowHeight); }
set { Console.SetWindowSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
public override string WindowTitle
{
get { return Console.Title; }
set { Console.Title = value; }
}

/// <summary>
/// This API resets the input buffer. In this example this
/// functionality is not needed so the method returns nothing.
/// </summary>
public override void FlushInputBuffer()
{
}

/// <summary>
/// This API returns a rectangular region of the screen buffer. In
/// this example this functionality is not needed so the method throws
/// a NotImplementException exception.
/// </summary>
/// <param name="rectangle">Defines the size of the rectangle.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Reads a pressed, released, or pressed and released
keystroke
/// from the keyboard device, blocking processing until a keystroke is
/// typed that matches the specified keystroke options. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="options">Options, such as IncludeKeyDown, used when
/// reading the keyboard.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override KeyInfo ReadKey(ReadKeyOptions options)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API crops a region of the screen buffer. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="source">The region of the screen to be scrolled.
</param>
/// <param name="destination">The region of the screen to receive the
/// source region contents.</param>
/// <param name="clip">The region of the screen to include in the
operation.</param>
/// <param name="fill">The character and attributes to be used to fill
all cell.</param>
public override void ScrollBufferContents(Rectangle source, Coordinates
destination, Rectangle clip, BufferCell fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// at a specified location. In this example this functionality is
/// not needed si the method throws a NotImplementedException
exception.
/// </summary>
/// <param name="origin">The parameter is not used.</param>
/// <param name="contents">The parameter is not used.</param>
public override void SetBufferContents(Coordinates origin, BufferCell[,]
contents)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Copies a given character, foreground color, and background
/// color to a region of the screen buffer. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception./// </summary>
/// <param name="rectangle">Defines the area to be filled. </param>
/// <param name="fill">Defines the fill character.</param>
public override void SetBufferContents(Rectangle rectangle, BufferCell
fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
}
}

Consulte también
System.Management.Automation.Host.PSHost

System.Management.Automation.Host.Pshostuserinterface

System.Management.Automation.Host.Pshostrawuserinterface
Ejemplo Host04
Artículo • 25/09/2021

En este ejemplo se muestra cómo compilar una aplicación host interactiva basada en
consola que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola. Esta aplicación host también permite
mostrar avisos para que el usuario pueda especificar varias opciones.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
Crear un host personalizado cuyas clases derivan de la clase
System.Management.Automation.Host.PSHost, la clase
System.Management.Automation.Host.PSHostUserInterface y la clase
System.Management.Automation.Host.PSHostRawUserInterface.

Compilación de una aplicación de consola que usa estas clases host para compilar
un shell Windows PowerShell interactivo.

Crear una $profile variable y cargar los perfiles siguientes.


usuario actual, host actual
usuario actual, todos los hosts
todos los usuarios, host actual
todos los usuarios, todos los hosts

Implemente la interfaz
System.Management.Automation.Host.IHostUISupportsMultipleChoiceSelection.

Ejemplo 1
Este ejemplo permite al usuario escribir comandos en una línea de comandos, los
procesa y, a continuación, imprime los resultados.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class PSListenerConsoleSample
{
/// <summary>
/// Indicator to tell the host application that it should exit.
/// </summary>
private bool shouldExit;

/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
private int exitCode;

/// <summary>
/// Holds a reference to the PSHost object for this interpreter.
/// </summary>
private MyHost myHost;

/// <summary>
/// Holds a reference to the runspace for this interpreter.
/// </summary>
private Runspace myRunSpace;

/// <summary>
/// Holds a reference to the currently executing pipeline so that
/// it can be stopped by the control-C handler.
/// </summary>
private PowerShell currentPowerShell;

/// <summary>
/// Used to serialize access to instance data.
/// </summary>
private object instanceLock = new object();

/// <summary>
/// Gets or sets a value indicating whether the host application
/// should exit.
/// </summary>
public bool ShouldExit
{
get { return this.shouldExit; }
set { this.shouldExit = value; }
}

/// <summary>
/// Gets or sets the exit code that the host application will use
/// when exiting.
/// </summary>
public int ExitCode
{
get { return this.exitCode; }
set { this.exitCode = value; }
}

/// <summary>
/// Creates and initiates the listener.
/// </summary>
/// <param name="args">The parameter is not used</param>
private static void Main(string[] args)
{
// Display the welcome message.
Console.Title = "Windows PowerShell Console Host Application Sample";
ConsoleColor oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" Windows PowerShell Console Host Interactive
Sample");
Console.WriteLine("
==================================================");
Console.WriteLine(string.Empty);
Console.WriteLine("This is an example of a simple interactive console
host that uses ");
Console.WriteLine("the Windows PowerShell engine to interpret
commands.");
Console.WriteLine("Type 'exit' to exit.");
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;

// Create the listener and run it. This never returns.


PSListenerConsoleSample listener = new PSListenerConsoleSample();
listener.Run();
}

/// <summary>
/// Create this instance of the console listener.
/// </summary>
private PSListenerConsoleSample()
{
// Create the host and runspace instances for this interpreter. Note
that
// this application doesn't support console files so only the default
snapins
// will be available.
this.myHost = new MyHost(this);
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();

// Create a PowerShell object that will be used to execute the


commands
// to create $profile and load the profiles.
lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}
try
{
this.currentPowerShell.Runspace = this.myRunSpace;

PSCommand[] profileCommands =
Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHo
st04");
foreach (PSCommand command in profileCommands)
{
this.currentPowerShell.Commands = command;
this.currentPowerShell.Invoke();
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because
currentPowerShell
// may be accessed by the ctrl-C handler...
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}

/// <summary>
/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// the caller. Since all output goes to the default outputter, this
method
/// returns nothing.
/// </summary>
/// <param name="cmd">The script to run</param>
/// <param name="input">Any input arguments to pass to the script. If
null
/// then nothing is passed in.</param>
private void executeHelper(string cmd, object input)
{
// Ignore empty command lines.
if (String.IsNullOrEmpty(cmd))
{
return;
}

// Create the pipeline object and make it available


// to the ctrl-C handle through the currentPowerShell instance
// variable.
lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}
this.currentPowerShell.Runspace = this.myRunSpace;

// Create a pipeline for this execution. Place the result in the


// currentPowerShell instance variable so that it is available to
// be stopped.
try
{
this.currentPowerShell.AddScript(cmd);

// Now add the default outputter to the end of the pipe and indicate
// that it should handle both output and errors from the previous
// commands. This will result in the output being written using the
PSHost
// and PSHostUserInterface classes instead of returning objects to
the hosting
// application.
this.currentPowerShell.AddCommand("out-default");

this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);

// If there was any input specified, pass it in, otherwise just


// execute the pipeline.
if (input != null)
{
this.currentPowerShell.Invoke(new object[] { input });
}
else
{
this.currentPowerShell.Invoke();
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because
currentPowerShell
// may be accessed by the ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}

/// <summary>
/// An exception occurred that we want to display
/// using the display formatter. To do this we run
/// a second pipeline passing in the error record.
/// The runtime will bind this to the $input variable
/// which is why $input is being piped to out-string.
/// We then call WriteErrorLine to make sure the error
/// gets displayed in the correct error color.
/// </summary>
/// <param name="e">The exception to display</param>
private void ReportException(Exception e)
{
if (e != null)
{
object error;
IContainsErrorRecord icer = e as IContainsErrorRecord;
if (icer != null)
{
error = icer.ErrorRecord;
}
else
{
error = (object)new ErrorRecord(e, "Host.ReportException",
ErrorCategory.NotSpecified, null);
}

lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

this.currentPowerShell.Runspace = this.myRunSpace;

try
{
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");

// Do not merge errors, this function will swallow errors.


Collection<PSObject> result;
PSDataCollection<object> inputCollection = new
PSDataCollection<object>();
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);

if (result.Count > 0)
{
string str = result[0].BaseObject as string;
if (!string.IsNullOrEmpty(str))
{
// Remove \r\n that is added by out-string.
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
}
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because
currentPowerShell
// may be accessed by the ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}
}

/// <summary>
/// Basic script execution routine - any runtime exceptions are
/// caught and passed back into the engine to display.
/// </summary>
/// <param name="cmd">The parameter is not used.</param>
private void Execute(string cmd)
{
try
{
// Execute the command with no input.
this.executeHelper(cmd, null);
}
catch (RuntimeException rte)
{
this.ReportException(rte);
}
}

/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// pipeline Stop() method to stop execution. If any exceptions occur
/// they are printed to the console but otherwise ignored.
/// </summary>
/// <param name="sender">See sender property of
ConsoleCancelEventHandler documentation.</param>
/// <param name="e">See e property of ConsoleCancelEventHandler
documentation</param>
private void HandleControlC(object sender, ConsoleCancelEventArgs e)
{
try
{
lock (this.instanceLock)
{
if (this.currentPowerShell != null &&
this.currentPowerShell.InvocationStateInfo.State ==
PSInvocationState.Running)
{
this.currentPowerShell.Stop();
}
}

e.Cancel = true;
}
catch (Exception exception)
{
this.myHost.UI.WriteErrorLine(exception.ToString());
}
}
/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// flag is set.
/// </summary>
private void Run()
{
// Set up the control-C handler.
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;

// Read commands to execute until ShouldExit is set by


// the user calling "exit".
while (!this.ShouldExit)
{
this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black,
"\nPSConsoleSample: ");
string cmd = Console.ReadLine();
this.Execute(cmd);
}

// Exit with the desired exit code that was set by exit command.
// This is set in the host by the MyHost.SetShouldExit()
implementation.
Environment.Exit(this.ExitCode);
}
}
}

Ejemplo 2
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHost que usa esta aplicación host. Los
elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Globalization;
using System.Management.Automation.Host;

/// <summary>
/// This is a sample implementation of the PSHost abstract class for
/// console applications. Not all members are implemented. Those that
/// are not implemented throw a NotImplementedException exception or
/// return nothing.
/// </summary>
internal class MyHost : PSHost
{
/// <summary>
/// A reference to the PSHost implementation.
/// </summary>
private PSListenerConsoleSample program;

/// <summary>
/// The culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalCultureInfo =
System.Threading.Thread.CurrentThread.CurrentCulture;

/// <summary>
/// The UI culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalUICultureInfo =
System.Threading.Thread.CurrentThread.CurrentUICulture;

/// <summary>
/// The identifier of this PSHost implementation.
/// </summary>
private static Guid instanceId = Guid.NewGuid();

/// <summary>
/// Initializes a new instance of the MyHost class. Keep
/// a reference to the host application object so that it
/// can be informed of when to exit.
/// </summary>
/// <param name="program">
/// A reference to the host application object.
/// </param>
public MyHost(PSListenerConsoleSample program)
{
this.program = program;
}

/// <summary>
/// A reference to the implementation of the PSHostUserInterface
/// class for this application.
/// </summary>
private MyHostUserInterface myHostUserInterface = new
MyHostUserInterface();

/// <summary>
/// Gets the culture information to use. This implementation
/// returns a snapshot of the culture information of the thread
/// that created this object.
/// </summary>
public override CultureInfo CurrentCulture
{
get { return this.originalCultureInfo; }
}

/// <summary>
/// Gets the UI culture information to use. This implementation
/// returns a snapshot of the UI culture information of the thread
/// that created this object.
/// </summary>
public override CultureInfo CurrentUICulture
{
get { return this.originalUICultureInfo; }
}

/// <summary>
/// Gets an identifier for this host. This implementation always
/// returns the GUID allocated at instantiation time.
/// </summary>
public override Guid InstanceId
{
get { return instanceId; }
}

/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// identify when your host is being used.
/// </summary>
public override string Name
{
get { return "MySampleConsoleHostImplementation"; }
}

/// <summary>
/// Gets an instance of the implementation of the PSHostUserInterface
/// class for this application. This instance is allocated once at
startup time
/// and returned every time thereafter.
/// </summary>
public override PSHostUserInterface UI
{
get { return this.myHostUserInterface; }
}

/// <summary>
/// Gets the version object for this application. Typically this
/// should match the version resource in the application.
/// </summary>
public override Version Version
{
get { return new Version(1, 0, 0, 0); }
}

/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// functionality is not needed so the method throws a
/// NotImplementedException exception.
/// </summary>
public override void EnterNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// In this example this functionality is not needed so the method
/// throws a NotImplementedException exception.
/// </summary>
public override void ExitNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API is called before an external application process is
/// started. Typically it is used to save state so that the parent
/// can restore state that has been modified by a child process (after
/// the child exits). In this example this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyBeginApplication()
{
return;
}

/// <summary>
/// This API is called after an external application process finishes.
/// Typically it is used to restore state that a child process has
/// altered. In this example, this functionality is not needed so
/// the method returns nothing.
/// </summary>
public override void NotifyEndApplication()
{
return;
}

/// <summary>
/// Indicate to the host application that exit has
/// been requested. Pass the exit code that the host
/// application should use when exiting the process.
/// </summary>
/// <param name="exitCode">The exit code that the
/// host application should use.</param>
public override void SetShouldExit(int exitCode)
{
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
}
}
}

Ejemplo 3
El código siguiente es la implementación de la clase
System.Management.Automation.Host.Pshostuserinterface que usa esta aplicación host.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;

/// <summary>
/// A sample implementation of the PSHostUserInterface abstract class for
/// console applications. Not all members are implemented. Those that are
/// not implemented throw a NotImplementedException exception or return
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
internal class MyHostUserInterface : PSHostUserInterface,
IHostUISupportsMultipleChoiceSelection
{
/// <summary>
/// A reference to the PSRawUserInterface implementation.
/// </summary>
private MyRawUserInterface myRawUi = new MyRawUserInterface();

/// <summary>
/// Gets an instance of the PSRawUserInterface object for this host
/// application.
/// </summary>
public override PSHostRawUserInterface RawUI
{
get { return this.myRawUi; }
}

/// <summary>
/// Prompts the user for input.
/// <param name="caption">The caption or title of the prompt.</param>
/// <param name="message">The text of the prompt.</param>
/// <param name="descriptions">A collection of FieldDescription objects
/// that describe each field of the prompt.</param>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
public override Dictionary<string, PSObject> Prompt(
string caption,
string message,
Collection<FieldDescription> descriptions)
{
this.Write(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + " ");
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
foreach (FieldDescription fd in descriptions)
{
string[] label = GetHotkeyAndLabel(fd.Label);
this.WriteLine(label[1]);
string userData = Console.ReadLine();
if (userData == null)
{
return null;
}

results[fd.Name] = PSObject.AsPSObject(userData);
}

return results;
}

/// <summary>

/// Provides a set of choices that enable the user to choose a


/// single option from a set of options.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
/// describe each choice.</param>
/// <param name="defaultChoice">The index of the label in the Choices
/// parameter collection. To indicate no default choice, set to -1.
</param>
/// <returns>The index of the Choices parameter collection element that
/// corresponds to the option that is selected by the user.</returns>
public override int PromptForChoice(
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
{
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + "\n");

// Convert the choice collection into something that is


// easier to work with. See the BuildHotkeysAndPlainLabels
// method for details.
string[,] promptData = BuildHotkeysAndPlainLabels(choices);

// Format the overall choice prompt string to display.


StringBuilder sb = new StringBuilder();
for (int element = 0; element < choices.Count; element++)
{
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"|{0}> {1} ",
promptData[0, element],
promptData[1, element]));
}

sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));

// Read prompts until a match is made, the default is


// chosen, or the loop is interrupted with ctrl-C.
while (true)
{
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);

// If the choice string was empty, use the default selection.


if (data.Length == 0)
{
return defaultChoice;
}

// See if the selection matched and return the


// corresponding index if it did.
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
{
return i;
}
}

this.WriteErrorLine("Invalid choice: " + data);


}
}

#region IHostUISupportsMultipleChoiceSelection Members

/// <summary>
/// Provides a set of choices that enable the user to choose a one or
/// more options from a set of options.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
/// describe each choice.</param>
/// <param name="defaultChoices">The index of the label in the Choices
/// parameter collection. To indicate no default choice, set to -1.
</param>
/// <returns>The index of the Choices parameter collection element that
/// corresponds to the option that is selected by the user.</returns>
public Collection<int> PromptForChoice(
string caption,
string message,
Collection<ChoiceDescription>
choices,
IEnumerable<int> defaultChoices)
{
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + "\n");

// Convert the choice collection into something that is


// easier to work with. See the BuildHotkeysAndPlainLabels
// method for details.
string[,] promptData = BuildHotkeysAndPlainLabels(choices);

// Format the overall choice prompt string to display.


StringBuilder sb = new StringBuilder();
for (int element = 0; element < choices.Count; element++)
{
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"|{0}> {1} ",
promptData[0, element],
promptData[1, element]));
}

Collection<int> defaultResults = new Collection<int>();


if (defaultChoices != null)
{
int countDefaults = 0;
foreach (int defaultChoice in defaultChoices)
{
++countDefaults;
defaultResults.Add(defaultChoice);
}

if (countDefaults != 0)
{
sb.Append(countDefaults == 1 ? "[Default choice is " : "[Default
choices are ");
foreach (int defaultChoice in defaultChoices)
{
sb.AppendFormat(
CultureInfo.CurrentCulture,
"\"{0}\",",
promptData[0, defaultChoice]);
}

sb.Remove(sb.Length - 1, 1);
sb.Append("]");
}
}

this.WriteLine(
ConsoleColor.Cyan,
ConsoleColor.Black,
sb.ToString());
// Read prompts until a match is made, the default is
// chosen, or the loop is interrupted with ctrl-C.
Collection<int> results = new Collection<int>();
while (true)
{
ReadNext:
string prompt = string.Format(CultureInfo.CurrentCulture,
"Choice[{0}]:", results.Count);
this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);

// If the choice string was empty, no more choices have been made.
// If there were no choices made, return the defaults
if (data.Length == 0)
{
return (results.Count == 0) ? defaultResults : results;
}

// See if the selection matched and return the


// corresponding index if it did.
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
{
results.Add(i);
goto ReadNext;
}
}

this.WriteErrorLine("Invalid choice: " + data);


}
}

#endregion

/// <summary>
/// Prompts the user for credentials with a specified prompt window
/// caption, prompt message, user name, and target name. In this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
/// prompted for.</param>
/// <param name="targetName">The name of the target for which the
/// credential is collected.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// Prompts the user for credentials by using a specified prompt window
/// caption, prompt message, user name and target name, credential
/// types allowed to be returned, and UI behavior options. In this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
/// prompted for.</param>
/// <param name="targetName">The name of the target for which the
/// credential is collected.</param>
/// <param name="allowedCredentialTypes">A PSCredentialTypes constant
/// that identifies the type of credentials that can be returned.
</param>
/// <param name="options">A PSCredentialUIOptions constant that
/// identifies the UI behavior when it gathers the credentials.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions options)
{
throw new NotImplementedException(
"The method or operation is not
implemented.");
}
/// <summary>
/// Reads characters that are entered by the user until a newline
/// (carriage return) is encountered.
/// </summary>
/// <returns>The characters that are entered by the user.</returns>
public override string ReadLine()
{
return Console.ReadLine();
}

/// <summary>
/// Reads characters entered by the user until a newline (carriage
return)
/// is encountered and returns the characters as a secure string. In
this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <returns>Throws a NotImplemented exception.</returns>
public override System.Security.SecureString ReadLineAsSecureString()
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Writes characters to the output display of the host.
/// </summary>
/// <param name="value">The characters to be written.</param>
public override void Write(string value)
{
Console.Write(value);
}

/// <summary>
/// Writes characters to the output display of the host with possible
/// foreground and background colors.
/// </summary>
/// <param name="foregroundColor">The color of the characters.</param>
/// <param name="backgroundColor">The background color to use.</param>
/// <param name="value">The characters to be written.</param>
public override void Write(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}
/// <summary>
/// Writes a line of characters to the output display of the host
/// with foreground and background colors and appends a newline
(carriage return).
/// </summary>
/// <param name="foregroundColor">The foreground color of the display.
</param>
/// <param name="backgroundColor">The background color of the display.
</param>
/// <param name="value">The line to be written.</param>
public override void WriteLine(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}

/// <summary>
/// Writes a debug message to the output display of the host.
/// </summary>
/// <param name="message">The debug message that is displayed.</param>
public override void WriteDebugLine(string message)
{
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}",
message));
}

/// <summary>
/// Writes an error message to the output display of the host.
/// </summary>
/// <param name="value">The error message that is displayed.</param>
public override void WriteErrorLine(string value)
{
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
}

/// <summary>
/// Writes a newline character (carriage return)
/// to the output display of the host.
/// </summary>
public override void WriteLine()
{
Console.WriteLine();
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// and appends a newline character(carriage return).
/// </summary>
/// <param name="value">The line to be written.</param>
public override void WriteLine(string value)
{
Console.WriteLine(value);
}

/// <summary>
/// Writes a progress report to the output display of the host.
/// </summary>
/// <param name="sourceId">Unique identifier of the source of the
record. </param>
/// <param name="record">A ProgressReport object.</param>
public override void WriteProgress(long sourceId, ProgressRecord record)
{

/// <summary>
/// Writes a verbose message to the output display of the host.
/// </summary>
/// <param name="message">The verbose message that is displayed.</param>
public override void WriteVerboseLine(string message)
{
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
}

/// <summary>
/// Writes a warning message to the output display of the host.
/// </summary>
/// <param name="message">The warning message that is displayed.</param>
public override void WriteWarningLine(string message)
{
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
}

/// <summary>
/// Parse a string containing a hotkey character.
/// Take a string of the form
/// Yes to &all
/// and returns a two-dimensional array split out as
/// "A", "Yes to all".
/// </summary>
/// <param name="input">The string to process</param>
/// <returns>
/// A two dimensional array containing the parsed components.
/// </returns>
private static string[] GetHotkeyAndLabel(string input)
{
string[] result = new string[] { String.Empty, String.Empty };
string[] fragments = input.Split('&');
if (fragments.Length == 2)
{
if (fragments[1].Length > 0)
{
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
}

result[1] = (fragments[0] + fragments[1]).Trim();


}
else
{
result[1] = input;
}

return result;
}

/// <summary>
/// This is a private worker function splits out the
/// accelerator keys from the menu and builds a two
/// dimensional array with the first access containing the
/// accelerator and the second containing the label string
/// with the & removed.
/// </summary>
/// <param name="choices">The choice collection to process</param>
/// <returns>
/// A two dimensional array containing the accelerator characters
/// and the cleaned-up labels</returns>
private static string[,] BuildHotkeysAndPlainLabels(
Collection<ChoiceDescription> choices)
{
// Allocate the result array
string[,] hotkeysAndPlainLabels = new string[2, choices.Count];

for (int i = 0; i < choices.Count; ++i)


{
string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}

return hotkeysAndPlainLabels;
}
}
}

Ejemplo 4
El código siguiente es la implementación de la clase
System.Management.Automation.Host.Pshostrawuserinterface que usa esta aplicación
host. Los elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Management.Automation.Host;

/// <summary>
/// A sample implementation of the PSHostRawUserInterface for console
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// implemented and throw a NotImplementedException exception.
/// </summary>
internal class MyRawUserInterface : PSHostRawUserInterface
{
/// <summary>
/// Gets or sets the background color of text to be written.
/// This maps to the corresponding Console.Background property.
/// </summary>
public override ConsoleColor BackgroundColor
{
get { return Console.BackgroundColor; }
set { Console.BackgroundColor = value; }
}

/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// size members.
/// </summary>
public override Size BufferSize
{
get { return new Size(Console.BufferWidth, Console.BufferHeight); }
set { Console.SetBufferSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the cursor position. In this example this
/// functionality is not needed so the property throws a
/// NotImplementException exception.
/// </summary>
public override Coordinates CursorPosition
{
get { throw new NotImplementedException(
"The method or operation is not implemented."); }
set { throw new NotImplementedException(
"The method or operation is not implemented."); }
}

/// <summary>
/// Gets or sets the cursor size taken directly from the
/// Console.CursorSize property.
/// </summary>
public override int CursorSize
{
get { return Console.CursorSize; }
set { Console.CursorSize = value; }
}

/// <summary>
/// Gets or sets the foreground color of the text to be written.
/// This maps to the corresponding Console.ForegroundColor property.
/// </summary>
public override ConsoleColor ForegroundColor
{
get { return Console.ForegroundColor; }
set { Console.ForegroundColor = value; }
}

/// <summary>
/// Gets a value indicating whether a key is available. This maps to
/// the corresponding Console.KeyAvailable property.
/// </summary>
public override bool KeyAvailable
{
get { return Console.KeyAvailable; }
}

/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// Console.LargestWindowWidth and Console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxPhysicalWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets the maximum window size adapted from the
/// Console.LargestWindowWidth and console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
public override Coordinates WindowPosition
{
get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
set { Console.SetWindowPosition(value.X, value.Y); }
}

/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
public override Size WindowSize
{
get { return new Size(Console.WindowWidth, Console.WindowHeight); }
set { Console.SetWindowSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
public override string WindowTitle
{
get { return Console.Title; }
set { Console.Title = value; }
}

/// <summary>
/// This API resets the input buffer. In this example this
/// functionality is not needed so the method returns nothing.
/// </summary>
public override void FlushInputBuffer()
{
}

/// <summary>
/// This API returns a rectangular region of the screen buffer. In
/// this example this functionality is not needed so the method throws
/// a NotImplementException exception.
/// </summary>
/// <param name="rectangle">Defines the size of the rectangle.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Reads a pressed, released, or pressed and released
keystroke
/// from the keyboard device, blocking processing until a keystroke is
/// typed that matches the specified keystroke options. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="options">Options, such as IncludeKeyDown, used when
/// reading the keyboard.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override KeyInfo ReadKey(ReadKeyOptions options)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API crops a region of the screen buffer. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="source">The region of the screen to be scrolled.
</param>
/// <param name="destination">The region of the screen to receive the
/// source region contents.</param>
/// <param name="clip">The region of the screen to include in the
operation.</param>
/// <param name="fill">The character and attributes to be used to fill
all cell.</param>
public override void ScrollBufferContents(Rectangle source, Coordinates
destination, Rectangle clip, BufferCell fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// at a specified location. In this example this functionality is
/// not needed si the method throws a NotImplementedException
exception.
/// </summary>
/// <param name="origin">The parameter is not used.</param>
/// <param name="contents">The parameter is not used.</param>
public override void SetBufferContents(Coordinates origin, BufferCell[,]
contents)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Copies a given character, foreground color, and background
/// color to a region of the screen buffer. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception./// </summary>
/// <param name="rectangle">Defines the area to be filled. </param>
/// <param name="fill">Defines the fill character.</param>
public override void SetBufferContents(Rectangle rectangle, BufferCell
fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
}
}

Consulte también
System.Management.Automation.Host.PSHost

System.Management.Automation.Host.Pshostuserinterface

System.Management.Automation.Host.Pshostrawuserinterface
Ejemplo Host05
Artículo • 24/09/2021

En este ejemplo se muestra cómo compilar una aplicación host interactiva basada en
consola que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola. Esta aplicación host también admite
llamadas a equipos remotos mediante los cmdlets Enter-PsSession y Exit-PsSession.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Esta aplicación debe ejecutarse en modo con privilegios elevados (Ejecutar como
administrador).

Muestra
Crear un host personalizado cuyas clases derivan de la clase
System.Management.Automation.Host.PSHost, la clase
System.Management.Automation.Host.Pshostuserinterface y la clase
System.Management.Automation.Host.Pshostrawuserinterface.

Compilación de una aplicación de consola que usa estas clases host para compilar
un shell Windows PowerShell interactivo.

Crear una $profile variable y cargar los perfiles siguientes.


usuario actual, host actual
usuario actual, todos los hosts
todos los usuarios, host actual
todos los usuarios, todos los hosts

Implemente la interfaz
System.Management.Automation.Host.IHostUISupportsMultipleChoiceSelection.

Implemente la interfaz
System.Management.Automation.Host.IHostSupportsInteractiveSession para
admitir la comunicación remota interactiva mediante los cmdlets Enter-PsSession y
Exit-PsSession.

Ejemplo 1
Este ejemplo permite al usuario escribir comandos en una línea de comandos, procesa
esos comandos y, a continuación, imprime los resultados.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Text;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// Simple PowerShell interactive console host listener implementation.
This class
/// implements a basic read-evaluate-print loop or 'listener' allowing you
to
/// interactively work with the PowerShell engine.
/// </summary>
internal class PSListenerConsoleSample
{
/// <summary>
/// Holds a reference to the runspace for this interpreter.
/// </summary>
internal Runspace myRunSpace;

/// <summary>
/// Indicator to tell the host application that it should exit.
/// </summary>
private bool shouldExit;

/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
private int exitCode;

/// <summary>
/// Holds a reference to the PSHost object for this interpreter.
/// </summary>
private MyHost myHost;

/// <summary>
/// Holds a reference to the currently executing pipeline so that
/// it can be stopped by the control-C handler.
/// </summary>
private PowerShell currentPowerShell;

/// <summary>
/// Used to serialize access to instance data.
/// </summary>
private object instanceLock = new object();

/// <summary>
/// Gets or sets a value indicating whether the host application
/// should exit.
/// </summary>
public bool ShouldExit
{
get { return this.shouldExit; }
set { this.shouldExit = value; }
}

/// <summary>
/// Gets or sets the exit code that the host application will use
/// when exiting.
/// </summary>
public int ExitCode
{
get { return this.exitCode; }
set { this.exitCode = value; }
}

/// <summary>
/// Creates and initiates the listener.
/// </summary>
/// <param name="args">The parameter is not used.</param>
private static void Main(string[] args)
{
// Display the welcome message.
Console.Title = "Windows PowerShell Console Host Application Sample";
ConsoleColor oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" Windows PowerShell Console Host Interactive
Sample");
Console.WriteLine("
==================================================");
Console.WriteLine(string.Empty);
Console.WriteLine("This is an example of a simple interactive console
host that uses ");
Console.WriteLine("the Windows PowerShell engine to interpret
commands.");
Console.WriteLine("Type 'exit' to exit.");
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;

// Create the listener and runs it. This method never returns.
PSListenerConsoleSample listener = new PSListenerConsoleSample();
listener.Run();
}

/// <summary>
/// Create an instance of the console listener.
/// </summary>
private PSListenerConsoleSample()
{
// Create the host and runspace instances for this interpreter. Note
// that this application doesn't support console files so only the
// default snap-ins will be available.
this.myHost = new MyHost(this);
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();

// Create a PowerShell object to run the commands used to create


// $profile and load the profiles.
lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

try
{
this.currentPowerShell.Runspace = this.myRunSpace;

PSCommand[] profileCommands =
Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHo
st05");
foreach (PSCommand command in profileCommands)
{
this.currentPowerShell.Commands = command;
this.currentPowerShell.Invoke();
}
}
finally
{
// Dispose of the pipeline line and set it to null, locked because
currentPowerShell
// may be accessed by the ctrl-C handler...
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}

/// <summary>
/// A helper class that builds and executes a pipeline that writes to
the
/// default output path. Any exceptions that are thrown are just passed
to
/// the caller. Since all output goes to the default
/// outputter, this method does not return anything.
/// </summary>
/// <param name="cmd">The script to run.</param>
/// <param name="input">Any input arguments to pass to the script.
/// If null then nothing is passed in.</param>
private void executeHelper(string cmd, object input)
{
// Ignore empty command lines.
if (String.IsNullOrEmpty(cmd))
{
return;
}

// Create the pipeline object and make it available to the


// ctrl-C handle through the currentPowerShell instance
// variable.
lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

// Create a pipeline for this execution, and then place the


// result in the currentPowerShell variable so it is available
// to be stopped.
try
{
this.currentPowerShell.Runspace = this.myRunSpace;
this.currentPowerShell.AddScript(cmd);

// Add the default outputter to the end of the pipe and then
// call the MergeMyResults method to merge the output and
// error streams from the pipeline. This will result in the
// output being written using the PSHost and PSHostUserInterface
// classes instead of returning objects to the host application.
this.currentPowerShell.AddCommand("out-default");

this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);

// If there is any input pass it in, otherwise just invoke the


// the pipeline.
if (input != null)
{
this.currentPowerShell.Invoke(new object[] { input });
}
else
{
this.currentPowerShell.Invoke();
}
}
finally
{
// Dispose the PowerShell object and set currentPowerShell to null.
// It is locked because currentPowerShell may be accessed by the
// ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}

/// <summary>
/// To display an exception using the display formatter,
/// run a second pipeline passing in the error record.
/// The runtime will bind this to the $input variable,
/// which is why $input is being piped to the Out-String
/// cmdlet. The WriteErrorLine method is called to make sure
/// the error gets displayed in the correct error color.
/// </summary>
/// <param name="e">The exception to display.</param>
private void ReportException(Exception e)
{
if (e != null)
{
object error;
IContainsErrorRecord icer = e as IContainsErrorRecord;
if (icer != null)
{
error = icer.ErrorRecord;
}
else
{
error = (object)new ErrorRecord(e, "Host.ReportException",
ErrorCategory.NotSpecified, null);
}

lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

this.currentPowerShell.Runspace = this.myRunSpace;

try
{
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");

// Do not merge errors, this function will swallow errors.


Collection<PSObject> result;
PSDataCollection<object> inputCollection = new
PSDataCollection<object>();
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);

if (result.Count > 0)
{
string str = result[0].BaseObject as string;
if (!string.IsNullOrEmpty(str))
{
// Remove \r\n, which is added by the Out-String cmdlet.
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
}
}
}
finally
{
// Dispose of the pipeline and set it to null, locking it because
// currentPowerShell may be accessed by the ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}
}

/// <summary>
/// Basic script execution routine. Any runtime exceptions are
/// caught and passed back to the Windows PowerShell engine to
/// display.
/// </summary>
/// <param name="cmd">Script to run.</param>
private void Execute(string cmd)
{
try
{
// Execute the command with no input.
this.executeHelper(cmd, null);
}
catch (RuntimeException rte)
{
this.ReportException(rte);
}
}

/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// pipeline Stop() method to stop execution. If any exceptions occur
/// they are printed to the console but otherwise ignored.
/// </summary>
/// <param name="sender">See sender property documentation of
/// ConsoleCancelEventHandler.</param>
/// <param name="e">See e property documentation of
/// ConsoleCancelEventHandler.</param>
private void HandleControlC(object sender, ConsoleCancelEventArgs e)
{
try
{
lock (this.instanceLock)
{
if (this.currentPowerShell != null &&
this.currentPowerShell.InvocationStateInfo.State ==
PSInvocationState.Running)
{
this.currentPowerShell.Stop();
}
}
e.Cancel = true;
}
catch (Exception exception)
{
this.myHost.UI.WriteErrorLine(exception.ToString());
}
}

/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// flag is set.
/// </summary>
private void Run()
{
// Set up the control-C handler.
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;

// Read commands to execute until ShouldExit is set by


// the user calling "exit".
while (!this.ShouldExit)
{
string prompt;
if (this.myHost.IsRunspacePushed)
{
prompt = string.Format("\n[{0}] PSConsoleSample: ",
this.myRunSpace.ConnectionInfo.ComputerName);
}
else
{
prompt = "\nPSConsoleSample: ";
}

this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);


string cmd = Console.ReadLine();
this.Execute(cmd);
}

// Exit with the desired exit code that was set by exit command.
// This is set in the host by the MyHost.SetShouldExit()
implementation.
Environment.Exit(this.ExitCode);
}
}
}

Ejemplo 2
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHost que usa esta aplicación host. Los
elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Globalization;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;

/// <summary>
/// This is a sample implementation of the PSHost abstract class for
/// console applications. Not all members are implemented. Those that
/// are not implemented throw a NotImplementedException exception or
/// return nothing.
/// </summary>
internal class MyHost : PSHost, IHostSupportsInteractiveSession
{

/// <summary>
/// A reference to the PSHost implementation.
/// </summary>
private PSListenerConsoleSample program;

/// <summary>
/// The culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalCultureInfo =
System.Threading.Thread.CurrentThread.CurrentCulture;

/// <summary>
/// The UI culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalUICultureInfo =
System.Threading.Thread.CurrentThread.CurrentUICulture;

/// <summary>
/// The identifier of this PSHost implementation.
/// </summary>
private static Guid instanceId = Guid.NewGuid();

/// <summary>
/// Initializes a new instance of the MyHost class. Keep
/// a reference to the host application object so that it
/// can be informed of when to exit.
/// </summary>
/// <param name="program">
/// A reference to the host application object.
/// </param>
public MyHost(PSListenerConsoleSample program)
{
this.program = program;
}

/// <summary>
/// A reference to the implementation of the PSHostUserInterface
/// class for this application.
/// </summary>
private MyHostUserInterface myHostUserInterface = new
MyHostUserInterface();

/// <summary>
/// A reference to the runspace used to start an interactive session.
/// </summary>
public Runspace pushedRunspace = null;

/// <summary>
/// Gets the culture information to use. This implementation
/// returns a snapshot of the culture information of the thread
/// that created this object.
/// </summary>
public override CultureInfo CurrentCulture
{
get { return this.originalCultureInfo; }
}

/// <summary>
/// Gets the UI culture information to use. This implementation
/// returns a snapshot of the UI culture information of the thread
/// that created this object.
/// </summary>
public override CultureInfo CurrentUICulture
{
get { return this.originalUICultureInfo; }
}

/// <summary>
/// Gets an identifier for this host. This implementation always
/// returns the GUID allocated at instantiation time.
/// </summary>
public override Guid InstanceId
{
get { return instanceId; }
}

/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// identify when your host is being used.
/// </summary>
public override string Name
{
get { return "MySampleConsoleHostImplementation"; }
}

/// <summary>
/// Gets an instance of the implementation of the PSHostUserInterface
/// class for this application. This instance is allocated once at
startup time
/// and returned every time thereafter.
/// </summary>
public override PSHostUserInterface UI
{
get { return this.myHostUserInterface; }
}

/// <summary>
/// Gets the version object for this application. Typically this
/// should match the version resource in the application.
/// </summary>
public override Version Version
{
get { return new Version(1, 0, 0, 0); }
}

#region IHostSupportsInteractiveSession Properties

/// <summary>
/// Gets a value indicating whether a request
/// to open a PSSession has been made.
/// </summary>
public bool IsRunspacePushed
{
get { return this.pushedRunspace != null; }
}

/// <summary>
/// Gets or sets the runspace used by the PSSession.
/// </summary>
public Runspace Runspace
{
get { return this.program.myRunSpace; }
internal set { this.program.myRunSpace = value; }
}
#endregion IHostSupportsInteractiveSession Properties

/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// functionality is not needed so the method throws a
/// NotImplementedException exception.
/// </summary>
public override void EnterNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// In this example this functionality is not needed so the method
/// throws a NotImplementedException exception.
/// </summary>
public override void ExitNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API is called before an external application process is
/// started. Typically it is used to save state so that the parent
/// can restore state that has been modified by a child process (after
/// the child exits). In this example this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyBeginApplication()
{
return;
}

/// <summary>
/// This API is called after an external application process finishes.
/// Typically it is used to restore state that a child process has
/// altered. In this example, this functionality is not needed so
/// the method returns nothing.
/// </summary>
public override void NotifyEndApplication()
{
return;
}

/// <summary>
/// Indicate to the host application that exit has
/// been requested. Pass the exit code that the host
/// application should use when exiting the process.
/// </summary>
/// <param name="exitCode">The exit code that the
/// host application should use.</param>
public override void SetShouldExit(int exitCode)
{
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
}

#region IHostSupportsInteractiveSession Methods

/// <summary>
/// Requests to close a PSSession.
/// </summary>
public void PopRunspace()
{
Runspace = this.pushedRunspace;
this.pushedRunspace = null;
}

/// <summary>
/// Requests to open a PSSession.
/// </summary>
/// <param name="runspace">Runspace to use.</param>
public void PushRunspace(Runspace runspace)
{
this.pushedRunspace = Runspace;
Runspace = runspace;
}

#endregion IHostSupportsInteractiveSession Methods


}
}

Ejemplo 3
El código siguiente es la implementación de la clase
System.Management.Automation.Host.Pshostuserinterface que usa esta aplicación host.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;

/// <summary>
/// A sample implementation of the PSHostUserInterface abstract class for
/// console applications. Not all members are implemented. Those that are
/// not implemented throw a NotImplementedException exception or return
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
internal class MyHostUserInterface : PSHostUserInterface,
IHostUISupportsMultipleChoiceSelection
{
/// <summary>
/// A reference to the PSRawUserInterface implementation.
/// </summary>
private MyRawUserInterface myRawUi = new MyRawUserInterface();

/// <summary>
/// Gets an instance of the PSRawUserInterface object for this host
/// application.
/// </summary>
public override PSHostRawUserInterface RawUI
{
get { return this.myRawUi; }
}

/// <summary>
/// Prompts the user for input.
/// <param name="caption">The caption or title of the prompt.</param>
/// <param name="message">The text of the prompt.</param>
/// <param name="descriptions">A collection of FieldDescription objects
/// that describe each field of the prompt.</param>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
public override Dictionary<string, PSObject> Prompt(
string caption,
string message,
Collection<FieldDescription> descriptions)
{
this.Write(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + " ");
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
foreach (FieldDescription fd in descriptions)
{
string[] label = GetHotkeyAndLabel(fd.Label);
this.WriteLine(label[1]);
string userData = Console.ReadLine();
if (userData == null)
{
return null;
}

results[fd.Name] = PSObject.AsPSObject(userData);
}

return results;
}

/// <summary>

/// Provides a set of choices that enable the user to choose a


/// single option from a set of options.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
/// describe each choice.</param>
/// <param name="defaultChoice">The index of the label in the Choices
/// parameter collection. To indicate no default choice, set to -1.
</param>
/// <returns>The index of the Choices parameter collection element that
/// corresponds to the option that is selected by the user.</returns>
public override int PromptForChoice(
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
{
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + "\n");

// Convert the choice collection into something that is


// easier to work with. See the BuildHotkeysAndPlainLabels
// method for details.
string[,] promptData = BuildHotkeysAndPlainLabels(choices);

// Format the overall choice prompt string to display.


StringBuilder sb = new StringBuilder();
for (int element = 0; element < choices.Count; element++)
{
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"|{0}> {1} ",
promptData[0, element],
promptData[1, element]));
}

sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));

// Read prompts until a match is made, the default is


// chosen, or the loop is interrupted with ctrl-C.
while (true)
{
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);

// If the choice string was empty, use the default selection.


if (data.Length == 0)
{
return defaultChoice;
}

// See if the selection matched and return the


// corresponding index if it did.
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
{
return i;
}
}

this.WriteErrorLine("Invalid choice: " + data);


}
}

#region IHostUISupportsMultipleChoiceSelection Members

/// <summary>
/// Provides a set of choices that enable the user to choose a one or
/// more options from a set of options.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
/// describe each choice.</param>
/// <param name="defaultChoices">The index of the label in the Choices
/// parameter collection. To indicate no default choice, set to -1.
</param>
/// <returns>The index of the Choices parameter collection element that
/// corresponds to the option that is selected by the user.</returns>
public Collection<int> PromptForChoice(
string caption,
string message,
Collection<ChoiceDescription>
choices,
IEnumerable<int> defaultChoices)
{
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + "\n");

// Convert the choice collection into something that is


// easier to work with. See the BuildHotkeysAndPlainLabels
// method for details.
string[,] promptData = BuildHotkeysAndPlainLabels(choices);

// Format the overall choice prompt string to display.


StringBuilder sb = new StringBuilder();
for (int element = 0; element < choices.Count; element++)
{
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"|{0}> {1} ",
promptData[0, element],
promptData[1, element]));
}
Collection<int> defaultResults = new Collection<int>();
if (defaultChoices != null)
{
int countDefaults = 0;
foreach (int defaultChoice in defaultChoices)
{
++countDefaults;
defaultResults.Add(defaultChoice);
}

if (countDefaults != 0)
{
sb.Append(countDefaults == 1 ? "[Default choice is " : "[Default
choices are ");
foreach (int defaultChoice in defaultChoices)
{
sb.AppendFormat(
CultureInfo.CurrentCulture,
"\"{0}\",",
promptData[0, defaultChoice]);
}

sb.Remove(sb.Length - 1, 1);
sb.Append("]");
}
}

this.WriteLine(
ConsoleColor.Cyan,
ConsoleColor.Black,
sb.ToString());

// Read prompts until a match is made, the default is


// chosen, or the loop is interrupted with ctrl-C.
Collection<int> results = new Collection<int>();
while (true)
{
ReadNext:
string prompt = string.Format(CultureInfo.CurrentCulture,
"Choice[{0}]:", results.Count);
this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);

// If the choice string was empty, no more choices have been made.
// If there were no choices made, return the defaults
if (data.Length == 0)
{
return (results.Count == 0) ? defaultResults : results;
}

// See if the selection matched and return the


// corresponding index if it did.
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
{
results.Add(i);
goto ReadNext;
}
}

this.WriteErrorLine("Invalid choice: " + data);


}
}

#endregion

/// <summary>
/// Prompts the user for credentials with a specified prompt window
/// caption, prompt message, user name, and target name. In this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
/// prompted for.</param>
/// <param name="targetName">The name of the target for which the
/// credential is collected.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// Prompts the user for credentials by using a specified prompt window
/// caption, prompt message, user name and target name, credential
/// types allowed to be returned, and UI behavior options. In this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
/// prompted for.</param>
/// <param name="targetName">The name of the target for which the
/// credential is collected.</param>
/// <param name="allowedCredentialTypes">A PSCredentialTypes constant
/// that identifies the type of credentials that can be returned.
</param>
/// <param name="options">A PSCredentialUIOptions constant that
/// identifies the UI behavior when it gathers the credentials.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions options)
{
throw new NotImplementedException(
"The method or operation is not
implemented.");
}

/// <summary>
/// Reads characters that are entered by the user until a newline
/// (carriage return) is encountered.
/// </summary>
/// <returns>The characters that are entered by the user.</returns>
public override string ReadLine()
{
return Console.ReadLine();
}

/// <summary>
/// Reads characters entered by the user until a newline (carriage
return)
/// is encountered and returns the characters as a secure string. In
this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <returns>Throws a NotImplemented exception.</returns>
public override System.Security.SecureString ReadLineAsSecureString()
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Writes characters to the output display of the host.
/// </summary>
/// <param name="value">The characters to be written.</param>
public override void Write(string value)
{
Console.Write(value);
}

/// <summary>
/// Writes characters to the output display of the host with possible
/// foreground and background colors.
/// </summary>
/// <param name="foregroundColor">The color of the characters.</param>
/// <param name="backgroundColor">The background color to use.</param>
/// <param name="value">The characters to be written.</param>
public override void Write(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// with foreground and background colors and appends a newline
(carriage return).
/// </summary>
/// <param name="foregroundColor">The foreground color of the display.
</param>
/// <param name="backgroundColor">The background color of the display.
</param>
/// <param name="value">The line to be written.</param>
public override void WriteLine(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}

/// <summary>
/// Writes a debug message to the output display of the host.
/// </summary>
/// <param name="message">The debug message that is displayed.</param>
public override void WriteDebugLine(string message)
{
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}",
message));
}

/// <summary>
/// Writes an error message to the output display of the host.
/// </summary>
/// <param name="value">The error message that is displayed.</param>
public override void WriteErrorLine(string value)
{
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
}

/// <summary>
/// Writes a newline character (carriage return)
/// to the output display of the host.
/// </summary>
public override void WriteLine()
{
Console.WriteLine();
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// and appends a newline character(carriage return).
/// </summary>
/// <param name="value">The line to be written.</param>
public override void WriteLine(string value)
{
Console.WriteLine(value);
}

/// <summary>
/// Writes a progress report to the output display of the host.
/// </summary>
/// <param name="sourceId">Unique identifier of the source of the
record. </param>
/// <param name="record">A ProgressReport object.</param>
public override void WriteProgress(long sourceId, ProgressRecord record)
{

/// <summary>
/// Writes a verbose message to the output display of the host.
/// </summary>
/// <param name="message">The verbose message that is displayed.</param>
public override void WriteVerboseLine(string message)
{
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
}

/// <summary>
/// Writes a warning message to the output display of the host.
/// </summary>
/// <param name="message">The warning message that is displayed.</param>
public override void WriteWarningLine(string message)
{
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
}

/// <summary>
/// Parse a string containing a hotkey character.
/// Take a string of the form
/// Yes to &all
/// and returns a two-dimensional array split out as
/// "A", "Yes to all".
/// </summary>
/// <param name="input">The string to process</param>
/// <returns>
/// A two dimensional array containing the parsed components.
/// </returns>
private static string[] GetHotkeyAndLabel(string input)
{
string[] result = new string[] { String.Empty, String.Empty };
string[] fragments = input.Split('&');
if (fragments.Length == 2)
{
if (fragments[1].Length > 0)
{
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
}

result[1] = (fragments[0] + fragments[1]).Trim();


}
else
{
result[1] = input;
}

return result;
}

/// <summary>
/// This is a private worker function splits out the
/// accelerator keys from the menu and builds a two
/// dimensional array with the first access containing the
/// accelerator and the second containing the label string
/// with the & removed.
/// </summary>
/// <param name="choices">The choice collection to process</param>
/// <returns>
/// A two dimensional array containing the accelerator characters
/// and the cleaned-up labels</returns>
private static string[,] BuildHotkeysAndPlainLabels(
Collection<ChoiceDescription> choices)
{
// Allocate the result array
string[,] hotkeysAndPlainLabels = new string[2, choices.Count];

for (int i = 0; i < choices.Count; ++i)


{
string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}

return hotkeysAndPlainLabels;
}
}
}

Ejemplo 4
El código siguiente es la implementación de la clase
System.Management.Automation.Host.Pshostrawuserinterface que usa esta aplicación
host. Los elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Management.Automation.Host;

/// <summary>
/// A sample implementation of the PSHostRawUserInterface for console
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// implemented and throw a NotImplementedException exception.
/// </summary>
internal class MyRawUserInterface : PSHostRawUserInterface
{
/// <summary>
/// Gets or sets the background color of text to be written.
/// This maps to the corresponding Console.Background property.
/// </summary>
public override ConsoleColor BackgroundColor
{
get { return Console.BackgroundColor; }
set { Console.BackgroundColor = value; }
}

/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// size members.
/// </summary>
public override Size BufferSize
{
get { return new Size(Console.BufferWidth, Console.BufferHeight); }
set { Console.SetBufferSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the cursor position. In this example this
/// functionality is not needed so the property throws a
/// NotImplementException exception.
/// </summary>
public override Coordinates CursorPosition
{
get { throw new NotImplementedException(
"The method or operation is not implemented."); }
set { throw new NotImplementedException(
"The method or operation is not implemented."); }
}

/// <summary>
/// Gets or sets the cursor size taken directly from the
/// Console.CursorSize property.
/// </summary>
public override int CursorSize
{
get { return Console.CursorSize; }
set { Console.CursorSize = value; }
}

/// <summary>
/// Gets or sets the foreground color of the text to be written.
/// This maps to the corresponding Console.ForegroundColor property.
/// </summary>
public override ConsoleColor ForegroundColor
{
get { return Console.ForegroundColor; }
set { Console.ForegroundColor = value; }
}

/// <summary>
/// Gets a value indicating whether a key is available. This maps to
/// the corresponding Console.KeyAvailable property.
/// </summary>
public override bool KeyAvailable
{
get { return Console.KeyAvailable; }
}

/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// Console.LargestWindowWidth and Console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxPhysicalWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets the maximum window size adapted from the
/// Console.LargestWindowWidth and console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
public override Coordinates WindowPosition
{
get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
set { Console.SetWindowPosition(value.X, value.Y); }
}

/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
public override Size WindowSize
{
get { return new Size(Console.WindowWidth, Console.WindowHeight); }
set { Console.SetWindowSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
public override string WindowTitle
{
get { return Console.Title; }
set { Console.Title = value; }
}

/// <summary>
/// This API resets the input buffer. In this example this
/// functionality is not needed so the method returns nothing.
/// </summary>
public override void FlushInputBuffer()
{
}
/// <summary>
/// This API returns a rectangular region of the screen buffer. In
/// this example this functionality is not needed so the method throws
/// a NotImplementException exception.
/// </summary>
/// <param name="rectangle">Defines the size of the rectangle.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Reads a pressed, released, or pressed and released
keystroke
/// from the keyboard device, blocking processing until a keystroke is
/// typed that matches the specified keystroke options. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="options">Options, such as IncludeKeyDown, used when
/// reading the keyboard.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override KeyInfo ReadKey(ReadKeyOptions options)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API crops a region of the screen buffer. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="source">The region of the screen to be scrolled.
</param>
/// <param name="destination">The region of the screen to receive the
/// source region contents.</param>
/// <param name="clip">The region of the screen to include in the
operation.</param>
/// <param name="fill">The character and attributes to be used to fill
all cell.</param>
public override void ScrollBufferContents(Rectangle source, Coordinates
destination, Rectangle clip, BufferCell fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// at a specified location. In this example this functionality is
/// not needed si the method throws a NotImplementedException
exception.
/// </summary>
/// <param name="origin">The parameter is not used.</param>
/// <param name="contents">The parameter is not used.</param>
public override void SetBufferContents(Coordinates origin, BufferCell[,]
contents)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Copies a given character, foreground color, and background
/// color to a region of the screen buffer. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception./// </summary>
/// <param name="rectangle">Defines the area to be filled. </param>
/// <param name="fill">Defines the fill character.</param>
public override void SetBufferContents(Rectangle rectangle, BufferCell
fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
}
}

Consulte también
System.Management.Automation.Host.PSHost

System.Management.Automation.Host.Pshostuserinterface

System.Management.Automation.Host.Pshostrawuserinterface
Ejemplo Host06
Artículo • 25/09/2021

En este ejemplo se muestra cómo compilar una aplicación host interactiva basada en
consola que lee comandos desde la línea de comandos, ejecuta los comandos y, a
continuación, muestra los resultados en la consola. Además, este ejemplo utiliza las API
de Tokenizer para especificar el color del texto que el usuario ha escrito.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.
Esta aplicación debe ejecutarse en modo con privilegios elevados (Ejecutar como
administrador).

Muestra
Crear un host personalizado cuyas clases derivan de la clase
System.Management.Automation.Host.PSHost, la clase
System.Management.Automation.Host.Pshostuserinterface y la clase
System.Management.Automation.Host.Pshostrawuserinterface.

Compilación de una aplicación de consola que usa estas clases host para compilar
un shell Windows PowerShell interactivo.

Crear una $profile variable y cargar los perfiles siguientes.


usuario actual, host actual
usuario actual, todos los hosts
todos los usuarios, host actual
todos los usuarios, todos los hosts

Implemente la interfaz
System.Management.Automation.Host.IHostUISupportsMultipleChoiceSelection.

Implemente la interfaz
System.Management.Automation.Host.IHostSupportsInteractiveSession para
admitir la comunicación remota interactiva mediante los cmdlets Enter-PsSession y
Exit-PsSession.

Use tokenize API para colorear la línea de comandos a medida que se escribe.
Ejemplo 1
Este ejemplo permite al usuario escribir comandos en una línea de comandos, procesa
esos comandos y, a continuación, imprime los resultados.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;
using System.Text;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This sample shows how to implement a basic read-evaluate-print
/// loop (or 'listener') that allowing you to interactively work
/// with the Windows PowerShell engine.
/// </summary>
internal class PSListenerConsoleSample
{
/// <summary>
/// Used to read user input.
/// </summary>
internal ConsoleReadLine consoleReadLine = new ConsoleReadLine();

/// <summary>
/// Holds a reference to the runspace for this interpreter.
/// </summary>
internal Runspace myRunSpace;

/// <summary>
/// Indicator to tell the host application that it should exit.
/// </summary>
private bool shouldExit;

/// <summary>
/// The exit code that the host application will use to exit.
/// </summary>
private int exitCode;

/// <summary>
/// Holds a reference to the PSHost implementation for this interpreter.
/// </summary>
private MyHost myHost;

/// <summary>
/// Holds a reference to the currently executing pipeline so that it can
be
/// stopped by the control-C handler.
/// </summary>
private PowerShell currentPowerShell;

/// <summary>
/// Used to serialize access to instance data.
/// </summary>
private object instanceLock = new object();

/// <summary>
/// Gets or sets a value indicating whether the host application
/// should exit.
/// </summary>
public bool ShouldExit
{
get { return this.shouldExit; }
set { this.shouldExit = value; }
}

/// <summary>
/// Gets or sets a value indicating whether the host application
/// should exit.
/// </summary>
public int ExitCode
{
get { return this.exitCode; }
set { this.exitCode = value; }
}

/// <summary>
/// Creates and initiates the listener instance.
/// </summary>
/// <param name="args">This parameter is not used.</param>
private static void Main(string[] args)
{
// Display the welcome message.
Console.Title = "PowerShell Console Host Sample Application";
ConsoleColor oldFg = Console.ForegroundColor;
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine(" Windows PowerShell Console Host Application
Sample");
Console.WriteLine("
==================================================");
Console.WriteLine(string.Empty);
Console.WriteLine("This is an example of a simple interactive console
host uses ");
Console.WriteLine("the Windows PowerShell engine to interpret
commands.");
Console.WriteLine("Type 'exit' to exit.");
Console.WriteLine(string.Empty);
Console.ForegroundColor = oldFg;

// Create the listener and run it. This method never returns.
PSListenerConsoleSample listener = new PSListenerConsoleSample();
listener.Run();
}

/// <summary>
/// Initializes a new instance of the PSListenerConsoleSample class.
/// </summary>
public PSListenerConsoleSample()
{
// Create the host and runspace instances for this interpreter.
// Note that this application does not support console files so
// only the default snap-ins will be available.
this.myHost = new MyHost(this);
this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost);
this.myRunSpace.Open();

// Create a PowerShell object to run the commands used to create


// $profile and load the profiles.
lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

try
{
this.currentPowerShell.Runspace = this.myRunSpace;

PSCommand[] profileCommands =
Microsoft.Samples.PowerShell.Host.HostUtilities.GetProfileCommands("SampleHo
st06");
foreach (PSCommand command in profileCommands)
{
this.currentPowerShell.Commands = command;
this.currentPowerShell.Invoke();
}
}
finally
{
// Dispose the PowerShell object and set currentPowerShell
// to null. It is locked because currentPowerShell may be
// accessed by the ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}

/// <summary>
/// A helper class that builds and executes a pipeline that writes
/// to the default output path. Any exceptions that are thrown are
/// just passed to the caller. Since all output goes to the default
/// outputter, this method does not return anything.
/// </summary>
/// <param name="cmd">The script to run.</param>
/// <param name="input">Any input arguments to pass to the script.
/// If null then nothing is passed in.</param>
private void executeHelper(string cmd, object input)
{
// Ignore empty command lines.
if (String.IsNullOrEmpty(cmd))
{
return;
}

// Create the pipeline object and make it available to the


// ctrl-C handle through the currentPowerShell instance
// variable.
lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

// Add a script and command to the pipeline and then run the pipeline.
Place
// the results in the currentPowerShell variable so that the pipeline
can be
// stopped.
try
{
this.currentPowerShell.Runspace = this.myRunSpace;

this.currentPowerShell.AddScript(cmd);

// Add the default outputter to the end of the pipe and then call
the
// MergeMyResults method to merge the output and error streams from
the
// pipeline. This will result in the output being written using the
PSHost
// and PSHostUserInterface classes instead of returning objects to
the host
// application.
this.currentPowerShell.AddCommand("out-default");

this.currentPowerShell.Commands.Commands[0].MergeMyResults(PipelineResultTyp
es.Error, PipelineResultTypes.Output);

// If there is any input pass it in, otherwise just invoke the


// the pipeline.
if (input != null)
{
this.currentPowerShell.Invoke(new object[] { input });
}
else
{
this.currentPowerShell.Invoke();
}
}
finally
{
// Dispose the PowerShell object and set currentPowerShell to null.
// It is locked because currentPowerShell may be accessed by the
// ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}

/// <summary>
/// To display an exception using the display formatter,
/// run a second pipeline passing in the error record.
/// The runtime will bind this to the $input variable,
/// which is why $input is being piped to the Out-String
/// cmdlet. The WriteErrorLine method is called to make sure
/// the error gets displayed in the correct error color.
/// </summary>
/// <param name="e">The exception to display.</param>
private void ReportException(Exception e)
{
if (e != null)
{
object error;
IContainsErrorRecord icer = e as IContainsErrorRecord;
if (icer != null)
{
error = icer.ErrorRecord;
}
else
{
error = (object)new ErrorRecord(e, "Host.ReportException",
ErrorCategory.NotSpecified, null);
}

lock (this.instanceLock)
{
this.currentPowerShell = PowerShell.Create();
}

this.currentPowerShell.Runspace = this.myRunSpace;

try
{
this.currentPowerShell.AddScript("$input").AddCommand("out-
string");

// Do not merge errors, this function will swallow errors.


Collection<PSObject> result;
PSDataCollection<object> inputCollection = new
PSDataCollection<object>();
inputCollection.Add(error);
inputCollection.Complete();
result = this.currentPowerShell.Invoke(inputCollection);
if (result.Count > 0)
{
string str = result[0].BaseObject as string;
if (!string.IsNullOrEmpty(str))
{
// Remove \r\n, which is added by the Out-String cmdlet.
this.myHost.UI.WriteErrorLine(str.Substring(0, str.Length -
2));
}
}
}
finally
{
// Dispose of the pipeline and set it to null, locking it because
// currentPowerShell may be accessed by the ctrl-C handler.
lock (this.instanceLock)
{
this.currentPowerShell.Dispose();
this.currentPowerShell = null;
}
}
}
}

/// <summary>
/// Basic script execution routine. Any runtime exceptions are
/// caught and passed back to the Windows PowerShell engine to
/// display.
/// </summary>
/// <param name="cmd">Script to run.</param>
private void Execute(string cmd)
{
try
{
// Run the command with no input.
this.executeHelper(cmd, null);
}
catch (RuntimeException rte)
{
this.ReportException(rte);
}
}

/// <summary>
/// Method used to handle control-C's from the user. It calls the
/// pipeline Stop() method to stop execution. If any exceptions occur
/// they are printed to the console but otherwise ignored.
/// </summary>
/// <param name="sender">See sender property documentation of
/// ConsoleCancelEventHandler.</param>
/// <param name="e">See e property documentation of
/// ConsoleCancelEventHandler.</param>
private void HandleControlC(object sender, ConsoleCancelEventArgs e)
{
try
{
lock (this.instanceLock)
{
if (this.currentPowerShell != null &&
this.currentPowerShell.InvocationStateInfo.State ==
PSInvocationState.Running)
{
this.currentPowerShell.Stop();
}
}

e.Cancel = true;
}
catch (Exception exception)
{
this.myHost.UI.WriteErrorLine(exception.ToString());
}
}

/// <summary>
/// Implements the basic listener loop. It sets up the ctrl-C handler,
then
/// reads a command from the user, executes it and repeats until the
ShouldExit
/// flag is set.
/// </summary>
private void Run()
{
// Set up the control-C handler.
Console.CancelKeyPress += new
ConsoleCancelEventHandler(this.HandleControlC);
Console.TreatControlCAsInput = false;

// Read commands and run them until the ShouldExit flag is set by
// the user calling "exit".
while (!this.ShouldExit)
{
string prompt;
if (this.myHost.IsRunspacePushed)
{
prompt = string.Format("\n[{0}] PSConsoleSample: ",
this.myRunSpace.ConnectionInfo.ComputerName);
}
else
{
prompt = "\nPSConsoleSample: ";
}

this.myHost.UI.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);


string cmd = this.consoleReadLine.Read();
this.Execute(cmd);
}

// Exit with the desired exit code that was set by the exit command.
// The exit code is set in the host by the MyHost.SetShouldExit()
method.
Environment.Exit(this.ExitCode);
}
}
}

Ejemplo 2
El código siguiente es la implementación de la clase
System.Management.Automation.Host.PSHost que usa esta aplicación host. Los
elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Globalization;
using System.Management.Automation.Host;
using System.Management.Automation.Runspaces;

/// <summary>
/// This is a sample implementation of the PSHost abstract class for
/// console applications. Not all members are implemented. Those that
/// are not implemented throw a NotImplementedException exception or
/// return nothing.
/// </summary>
internal class MyHost : PSHost, IHostSupportsInteractiveSession
{
public MyHost(PSListenerConsoleSample program)
{
this.program = program;
}

/// <summary>
/// A reference to the PSHost implementation.
/// </summary>
private PSListenerConsoleSample program;

/// <summary>
/// The culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalCultureInfo =
System.Threading.Thread.CurrentThread.CurrentCulture;

/// <summary>
/// The UI culture information of the thread that created
/// this object.
/// </summary>
private CultureInfo originalUICultureInfo =
System.Threading.Thread.CurrentThread.CurrentUICulture;

/// <summary>
/// The identifier of this PSHost implementation.
/// </summary>
private static Guid instanceId = Guid.NewGuid();

/// <summary>
/// A reference to the implementation of the PSHostUserInterface
/// class for this application.
/// </summary>
private MyHostUserInterface myHostUserInterface = new
MyHostUserInterface();

/// <summary>
/// A reference to the runspace used to start an interactive session.
/// </summary>
public Runspace pushedRunspace = null;

/// <summary>
/// Gets the culture information to use. This implementation
/// returns a snapshot of the culture information of the thread
/// that created this object.
/// </summary>
public override CultureInfo CurrentCulture
{
get { return this.originalCultureInfo; }
}

/// <summary>
/// Gets the UI culture information to use. This implementation
/// returns a snapshot of the UI culture information of the thread
/// that created this object.
/// </summary>
public override CultureInfo CurrentUICulture
{
get { return this.originalUICultureInfo; }
}

/// <summary>
/// Gets an identifier for this host. This implementation always
/// returns the GUID allocated at instantiation time.
/// </summary>
public override Guid InstanceId
{
get { return instanceId; }
}

/// <summary>
/// Gets a string that contains the name of this host implementation.
/// Keep in mind that this string may be used by script writers to
/// identify when your host is being used.
/// </summary>
public override string Name
{
get { return "MySampleConsoleHostImplementation"; }
}

/// <summary>
/// Gets an instance of the implementation of the PSHostUserInterface
/// class for this application. This instance is allocated once at
startup time
/// and returned every time thereafter.
/// </summary>
public override PSHostUserInterface UI
{
get { return this.myHostUserInterface; }
}

/// <summary>
/// Gets the version object for this application. Typically this
/// should match the version resource in the application.
/// </summary>
public override Version Version
{
get { return new Version(1, 0, 0, 0); }
}

#region IHostSupportsInteractiveSession Properties

/// <summary>
/// Gets a value indicating whether a request
/// to open a PSSession has been made.
/// </summary>
public bool IsRunspacePushed
{
get { return this.pushedRunspace != null; }
}

/// <summary>
/// Gets or sets the runspace used by the PSSession.
/// </summary>
public Runspace Runspace
{
get { return this.program.myRunSpace; }
internal set { this.program.myRunSpace = value; }
}
#endregion IHostSupportsInteractiveSession Properties

/// <summary>
/// This API Instructs the host to interrupt the currently running
/// pipeline and start a new nested input loop. In this example this
/// functionality is not needed so the method throws a
/// NotImplementedException exception.
/// </summary>
public override void EnterNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API instructs the host to exit the currently running input
loop.
/// In this example this functionality is not needed so the method
/// throws a NotImplementedException exception.
/// </summary>
public override void ExitNestedPrompt()
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API is called before an external application process is
/// started. Typically it is used to save state so that the parent
/// can restore state that has been modified by a child process (after
/// the child exits). In this example this functionality is not
/// needed so the method returns nothing.
/// </summary>
public override void NotifyBeginApplication()
{
return;
}

/// <summary>
/// This API is called after an external application process finishes.
/// Typically it is used to restore state that a child process has
/// altered. In this example, this functionality is not needed so
/// the method returns nothing.
/// </summary>
public override void NotifyEndApplication()
{
return;
}

/// <summary>
/// Indicate to the host application that exit has
/// been requested. Pass the exit code that the host
/// application should use when exiting the process.
/// </summary>
/// <param name="exitCode">The exit code that the
/// host application should use.</param>
public override void SetShouldExit(int exitCode)
{
this.program.ShouldExit = true;
this.program.ExitCode = exitCode;
}

#region IHostSupportsInteractiveSession Methods

/// <summary>
/// Requests to close a PSSession.
/// </summary>
public void PopRunspace()
{
Runspace = this.pushedRunspace;
this.pushedRunspace = null;
}

/// <summary>
/// Requests to open a PSSession.
/// </summary>
/// <param name="runspace">Runspace to use.</param>
public void PushRunspace(Runspace runspace)
{
this.pushedRunspace = Runspace;
Runspace = runspace;
}

#endregion IHostSupportsInteractiveSession Methods


}
}

Ejemplo 3
El código siguiente es la implementación de la clase
System.Management.Automation.Host.Pshostuserinterface que usa esta aplicación host.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Management.Automation;
using System.Management.Automation.Host;
using System.Text;

/// <summary>
/// A sample implementation of the PSHostUserInterface abstract class for
/// console applications. Not all members are implemented. Those that are
/// not implemented throw a NotImplementedException exception or return
/// nothing. Members that are implemented include those that map easily to
/// Console APIs and a basic implementation of the prompt API provided.
/// </summary>
internal class MyHostUserInterface : PSHostUserInterface,
IHostUISupportsMultipleChoiceSelection
{
/// <summary>
/// A reference to the PSRawUserInterface implementation.
/// </summary>
private MyRawUserInterface myRawUi = new MyRawUserInterface();
/// <summary>
/// Gets an instance of the PSRawUserInterface class for this host
/// application.
/// </summary>
public override PSHostRawUserInterface RawUI
{
get { return this.myRawUi; }
}

/// <summary>
/// Prompts the user for input.
/// <param name="caption">The caption or title of the prompt.</param>
/// <param name="message">The text of the prompt.</param>
/// <param name="descriptions">A collection of FieldDescription objects
/// that describe each field of the prompt.</param>
/// <returns>A dictionary object that contains the results of the user
/// prompts.</returns>
public override Dictionary<string, PSObject> Prompt(
string caption,
string message,
Collection<FieldDescription> descriptions)
{
this.Write(
ConsoleColor.DarkCyan,
ConsoleColor.Black,
caption + "\n" + message + " ");
Dictionary<string, PSObject> results =
new Dictionary<string, PSObject>();
foreach (FieldDescription fd in descriptions)
{
string[] label = GetHotkeyAndLabel(fd.Label);
this.WriteLine(label[1]);
string userData = Console.ReadLine();
if (userData == null)
{
return null;
}

results[fd.Name] = PSObject.AsPSObject(userData);
}

return results;
}

/// <summary>

/// Provides a set of choices that enable the user to choose a


/// single option from a set of options.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
/// describe each choice.</param>
/// <param name="defaultChoice">The index of the label in the Choices
/// parameter collection. To indicate no default choice, set to -1.
</param>
/// <returns>The index of the Choices parameter collection element that
/// corresponds to the option that is selected by the user.</returns>
public override int PromptForChoice(
string caption,
string message,
Collection<ChoiceDescription>
choices,
int defaultChoice)
{
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + "\n");

// Convert the choice collection into something that is


// easier to work with. See the BuildHotkeysAndPlainLabels
// method for details.
string[,] promptData = BuildHotkeysAndPlainLabels(choices);

// Format the overall choice prompt string to display.


StringBuilder sb = new StringBuilder();
for (int element = 0; element < choices.Count; element++)
{
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"|{0}> {1} ",
promptData[0, element],
promptData[1, element]));
}

sb.Append(String.Format(
CultureInfo.CurrentCulture,
"[Default is ({0}]",
promptData[0, defaultChoice]));

// Read prompts until a match is made, the default is


// chosen, or the loop is interrupted with ctrl-C.
while (true)
{
this.WriteLine(ConsoleColor.Cyan, ConsoleColor.Black,
sb.ToString());
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);

// If the choice string was empty, use the default selection.


if (data.Length == 0)
{
return defaultChoice;
}

// See if the selection matched and return the


// corresponding index if it did.
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
{
return i;
}
}

this.WriteErrorLine("Invalid choice: " + data);


}
}

#region IHostUISupportsMultipleChoiceSelection Members

/// <summary>
/// Provides a set of choices that enable the user to choose a one or
/// more options from a set of options.
/// </summary>
/// <param name="caption">Text that proceeds (a title) the choices.
</param>
/// <param name="message">A message that describes the choice.</param>
/// <param name="choices">A collection of ChoiceDescription objects that
/// describe each choice.</param>
/// <param name="defaultChoices">The index of the label in the Choices
/// parameter collection. To indicate no default choice, set to -1.
</param>
/// <returns>The index of the Choices parameter collection element that
/// corresponds to the option that is selected by the user.</returns>
public Collection<int> PromptForChoice(
string caption,
string message,
Collection<ChoiceDescription>
choices,
IEnumerable<int> defaultChoices)
{
// Write the caption and message strings in Blue.
this.WriteLine(
ConsoleColor.Blue,
ConsoleColor.Black,
caption + "\n" + message + "\n");

// Convert the choice collection into something that is


// easier to work with. See the BuildHotkeysAndPlainLabels
// method for details.
string[,] promptData = BuildHotkeysAndPlainLabels(choices);

// Format the overall choice prompt string to display.


StringBuilder sb = new StringBuilder();
for (int element = 0; element < choices.Count; element++)
{
sb.Append(String.Format(
CultureInfo.CurrentCulture,
"|{0}> {1} ",
promptData[0, element],
promptData[1, element]));
}

Collection<int> defaultResults = new Collection<int>();


if (defaultChoices != null)
{
int countDefaults = 0;
foreach (int defaultChoice in defaultChoices)
{
++countDefaults;
defaultResults.Add(defaultChoice);
}

if (countDefaults != 0)
{
sb.Append(countDefaults == 1 ? "[Default choice is " : "[Default
choices are ");
foreach (int defaultChoice in defaultChoices)
{
sb.AppendFormat(
CultureInfo.CurrentCulture,
"\"{0}\",",
promptData[0, defaultChoice]);
}

sb.Remove(sb.Length - 1, 1);
sb.Append("]");
}
}

this.WriteLine(
ConsoleColor.Cyan,
ConsoleColor.Black,
sb.ToString());
// Read prompts until a match is made, the default is
// chosen, or the loop is interrupted with ctrl-C.
Collection<int> results = new Collection<int>();
while (true)
{
ReadNext:
string prompt = string.Format(CultureInfo.CurrentCulture,
"Choice[{0}]:", results.Count);
this.Write(ConsoleColor.Cyan, ConsoleColor.Black, prompt);
string data =
Console.ReadLine().Trim().ToUpper(CultureInfo.CurrentCulture);

// If the choice string was empty, no more choices have been made.
// If there were no choices made, return the defaults
if (data.Length == 0)
{
return (results.Count == 0) ? defaultResults : results;
}

// See if the selection matched and return the


// corresponding index if it did.
for (int i = 0; i < choices.Count; i++)
{
if (promptData[0, i] == data)
{
results.Add(i);
goto ReadNext;
}
}

this.WriteErrorLine("Invalid choice: " + data);


}
}

#endregion

/// <summary>
/// Prompts the user for credentials with a specified prompt window
/// caption, prompt message, user name, and target name. In this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
/// prompted for.</param>
/// <param name="targetName">The name of the target for which the
/// credential is collected.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// Prompts the user for credentials by using a specified prompt window
/// caption, prompt message, user name and target name, credential
/// types allowed to be returned, and UI behavior options. In this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="caption">The caption for the message window.</param>
/// <param name="message">The text of the message.</param>
/// <param name="userName">The user name whose credential is to be
/// prompted for.</param>
/// <param name="targetName">The name of the target for which the
/// credential is collected.</param>
/// <param name="allowedCredentialTypes">A PSCredentialTypes constant
/// that identifies the type of credentials that can be returned.
</param>
/// <param name="options">A PSCredentialUIOptions constant that
/// identifies the UI behavior when it gathers the credentials.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override PSCredential PromptForCredential(
string caption,
string message,
string userName,
string targetName,
PSCredentialTypes
allowedCredentialTypes,
PSCredentialUIOptions options)
{
throw new NotImplementedException(
"The method or operation is not
implemented.");
}

/// <summary>
/// Reads characters that are entered by the user until a newline
/// (carriage return) is encountered.
/// </summary>
/// <returns>The characters that are entered by the user.</returns>
public override string ReadLine()
{
return Console.ReadLine();
}

/// <summary>
/// Reads characters entered by the user until a newline (carriage
return)
/// is encountered and returns the characters as a secure string. In
this
/// example this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <returns>Throws a NotImplemented exception.</returns>
public override System.Security.SecureString ReadLineAsSecureString()
{
throw new NotImplementedException("The method or operation is not
implemented.");
}

/// <summary>
/// Writes characters to the output display of the host.
/// </summary>
/// <param name="value">The characters to be written.</param>
public override void Write(string value)
{
Console.Write(value);
}

/// <summary>
/// Writes characters to the output display of the host with possible
/// foreground and background colors.
/// </summary>
/// <param name="foregroundColor">The color of the characters.</param>
/// <param name="backgroundColor">The background color to use.</param>
/// <param name="value">The characters to be written.</param>
public override void Write(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.Write(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// with foreground and background colors and appends a newline
(carriage return).
/// </summary>
/// <param name="foregroundColor">The foreground color of the display.
</param>
/// <param name="backgroundColor">The background color of the display.
</param>
/// <param name="value">The line to be written.</param>
public override void WriteLine(
ConsoleColor foregroundColor,
ConsoleColor backgroundColor,
string value)
{
ConsoleColor oldFg = Console.ForegroundColor;
ConsoleColor oldBg = Console.BackgroundColor;
Console.ForegroundColor = foregroundColor;
Console.BackgroundColor = backgroundColor;
Console.WriteLine(value);
Console.ForegroundColor = oldFg;
Console.BackgroundColor = oldBg;
}

/// <summary>
/// Writes a debug message to the output display of the host.
/// </summary>
/// <param name="message">The debug message that is displayed.</param>
public override void WriteDebugLine(string message)
{
this.WriteLine(
ConsoleColor.DarkYellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "DEBUG: {0}",
message));
}

/// <summary>
/// Writes an error message to the output display of the host.
/// </summary>
/// <param name="value">The error message that is displayed.</param>
public override void WriteErrorLine(string value)
{
this.WriteLine(
ConsoleColor.Red,
ConsoleColor.Black,
value);
}

/// <summary>
/// Writes a newline character (carriage return)
/// to the output display of the host.
/// </summary>
public override void WriteLine()
{
Console.WriteLine();
}

/// <summary>
/// Writes a line of characters to the output display of the host
/// and appends a newline character(carriage return).
/// </summary>
/// <param name="value">The line to be written.</param>
public override void WriteLine(string value)
{
Console.WriteLine(value);
}

/// <summary>
/// Writes a progress report to the output display of the host.
/// </summary>
/// <param name="sourceId">Unique identifier of the source of the
record. </param>
/// <param name="record">A ProgressReport object.</param>
public override void WriteProgress(long sourceId, ProgressRecord record)
{

/// <summary>
/// Writes a verbose message to the output display of the host.
/// </summary>
/// <param name="message">The verbose message that is displayed.</param>
public override void WriteVerboseLine(string message)
{
this.WriteLine(
ConsoleColor.Green,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "VERBOSE:
{0}", message));
}

/// <summary>
/// Writes a warning message to the output display of the host.
/// </summary>
/// <param name="message">The warning message that is displayed.</param>
public override void WriteWarningLine(string message)
{
this.WriteLine(
ConsoleColor.Yellow,
ConsoleColor.Black,
String.Format(CultureInfo.CurrentCulture, "WARNING:
{0}", message));
}

/// <summary>
/// Parse a string containing a hotkey character.
/// Take a string of the form
/// Yes to &all
/// and returns a two-dimensional array split out as
/// "A", "Yes to all".
/// </summary>
/// <param name="input">The string to process</param>
/// <returns>
/// A two dimensional array containing the parsed components.
/// </returns>
private static string[] GetHotkeyAndLabel(string input)
{
string[] result = new string[] { String.Empty, String.Empty };
string[] fragments = input.Split('&');
if (fragments.Length == 2)
{
if (fragments[1].Length > 0)
{
result[0] = fragments[1][0].ToString().
ToUpper(CultureInfo.CurrentCulture);
}

result[1] = (fragments[0] + fragments[1]).Trim();


}
else
{
result[1] = input;
}

return result;
}

/// <summary>
/// This is a private worker function splits out the
/// accelerator keys from the menu and builds a two
/// dimensional array with the first access containing the
/// accelerator and the second containing the label string
/// with the & removed.
/// </summary>
/// <param name="choices">The choice collection to process</param>
/// <returns>
/// A two dimensional array containing the accelerator characters
/// and the cleaned-up labels</returns>
private static string[,] BuildHotkeysAndPlainLabels(
Collection<ChoiceDescription> choices)
{
// Allocate the result array
string[,] hotkeysAndPlainLabels = new string[2, choices.Count];

for (int i = 0; i < choices.Count; ++i)


{
string[] hotkeyAndLabel = GetHotkeyAndLabel(choices[i].Label);
hotkeysAndPlainLabels[0, i] = hotkeyAndLabel[0];
hotkeysAndPlainLabels[1, i] = hotkeyAndLabel[1];
}

return hotkeysAndPlainLabels;
}
}
}

Ejemplo 4
El código siguiente es la implementación de la clase
System.Management.Automation.Host.Pshostrawuserinterface que usa esta aplicación
host. Los elementos que no se implementan inician una excepción o no devuelven nada.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Management.Automation.Host;

/// <summary>
/// A sample implementation of the PSHostRawUserInterface for console
/// applications. Members of this class that easily map to the .NET
/// console class are implemented. More complex methods are not
/// implemented and throw a NotImplementedException exception.
/// </summary>
internal class MyRawUserInterface : PSHostRawUserInterface
{
/// <summary>
/// Gets or sets the background color of text to be written.
/// This maps to the corresponding Console.Background property.
/// </summary>
public override ConsoleColor BackgroundColor
{
get { return Console.BackgroundColor; }
set { Console.BackgroundColor = value; }
}

/// <summary>
/// Gets or sets the host buffer size adapted from the Console buffer
/// size members.
/// </summary>
public override Size BufferSize
{
get { return new Size(Console.BufferWidth, Console.BufferHeight); }
set { Console.SetBufferSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the cursor position. In this example this
/// functionality is not needed so the property throws a
/// NotImplementException exception.
/// </summary>
public override Coordinates CursorPosition
{
get { throw new NotImplementedException(
"The method or operation is not implemented."); }
set { throw new NotImplementedException(
"The method or operation is not implemented."); }
}

/// <summary>
/// Gets or sets the cursor size taken directly from the
/// Console.CursorSize property.
/// </summary>
public override int CursorSize
{
get { return Console.CursorSize; }
set { Console.CursorSize = value; }
}

/// <summary>
/// Gets or sets the foreground color of the text to be written.
/// This maps to the corresponding Console.ForegroundColor property.
/// </summary>
public override ConsoleColor ForegroundColor
{
get { return Console.ForegroundColor; }
set { Console.ForegroundColor = value; }
}

/// <summary>
/// Gets a value indicating whether a key is available. This maps to
/// the corresponding Console.KeyAvailable property.
/// </summary>
public override bool KeyAvailable
{
get { return Console.KeyAvailable; }
}

/// <summary>
/// Gets the maximum physical size of the window adapted from the
/// Console.LargestWindowWidth and Console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxPhysicalWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets the maximum window size adapted from the
/// Console.LargestWindowWidth and console.LargestWindowHeight
/// properties.
/// </summary>
public override Size MaxWindowSize
{
get { return new Size(Console.LargestWindowWidth,
Console.LargestWindowHeight); }
}

/// <summary>
/// Gets or sets the window position adapted from the Console window
position
/// members.
/// </summary>
public override Coordinates WindowPosition
{
get { return new Coordinates(Console.WindowLeft, Console.WindowTop); }
set { Console.SetWindowPosition(value.X, value.Y); }
}

/// <summary>
/// Gets or sets the window size adapted from the corresponding Console
/// calls.
/// </summary>
public override Size WindowSize
{
get { return new Size(Console.WindowWidth, Console.WindowHeight); }
set { Console.SetWindowSize(value.Width, value.Height); }
}

/// <summary>
/// Gets or sets the title of the window mapped to the Console.Title
/// property.
/// </summary>
public override string WindowTitle
{
get { return Console.Title; }
set { Console.Title = value; }
}

/// <summary>
/// This API resets the input buffer. In this example this
/// functionality is not needed so the method returns nothing.
/// </summary>
public override void FlushInputBuffer()
{
}
/// <summary>
/// This API returns a rectangular region of the screen buffer. In
/// this example this functionality is not needed so the method throws
/// a NotImplementException exception.
/// </summary>
/// <param name="rectangle">Defines the size of the rectangle.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override BufferCell[,] GetBufferContents(Rectangle rectangle)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Reads a pressed, released, or pressed and released
keystroke
/// from the keyboard device, blocking processing until a keystroke is
/// typed that matches the specified keystroke options. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="options">Options, such as IncludeKeyDown, used when
/// reading the keyboard.</param>
/// <returns>Throws a NotImplementedException exception.</returns>
public override KeyInfo ReadKey(ReadKeyOptions options)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API crops a region of the screen buffer. In this example
/// this functionality is not needed so the method throws a
/// NotImplementException exception.
/// </summary>
/// <param name="source">The region of the screen to be scrolled.
</param>
/// <param name="destination">The region of the screen to receive the
/// source region contents.</param>
/// <param name="clip">The region of the screen to include in the
operation.</param>
/// <param name="fill">The character and attributes to be used to fill
all cell.</param>
public override void ScrollBufferContents(Rectangle source, Coordinates
destination, Rectangle clip, BufferCell fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API copies an array of buffer cells into the screen buffer
/// at a specified location. In this example this functionality is
/// not needed si the method throws a NotImplementedException
exception.
/// </summary>
/// <param name="origin">The parameter is not used.</param>
/// <param name="contents">The parameter is not used.</param>
public override void SetBufferContents(Coordinates origin, BufferCell[,]
contents)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}

/// <summary>
/// This API Copies a given character, foreground color, and background
/// color to a region of the screen buffer. In this example this
/// functionality is not needed so the method throws a
/// NotImplementException exception./// </summary>
/// <param name="rectangle">Defines the area to be filled. </param>
/// <param name="fill">Defines the fill character.</param>
public override void SetBufferContents(Rectangle rectangle, BufferCell
fill)
{
throw new NotImplementedException(
"The method or operation is not implemented.");
}
}
}

Ejemplo 5
El código siguiente lee la línea de comandos y colore el texto a medida que se
introduce. Los tokens se determinan mediante el método
System.Management.Automation.Psparser.Tokenize*.

C#

namespace Microsoft.Samples.PowerShell.Host
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Text;

/// <summary>
/// This class is used to read the command line and color the text as
/// it is entered. Tokens are determined using the PSParser.Tokenize
/// method.
/// </summary>
internal class ConsoleReadLine
{
/// <summary>
/// The buffer used to edit.
/// </summary>
private StringBuilder buffer = new StringBuilder();

/// <summary>
/// The position of the cursor within the buffer.
/// </summary>
private int current;

/// <summary>
/// The count of characters in buffer rendered.
/// </summary>
private int rendered;

/// <summary>
/// Store the anchor and handle cursor movement
/// </summary>
private Cursor cursor;

/// <summary>
/// The array of colors for tokens, indexed by PSTokenType
/// </summary>
private ConsoleColor[] tokenColors;

/// <summary>
/// We do not pick different colors for every token, those tokens
/// use this default.
/// </summary>
private ConsoleColor defaultColor = Console.ForegroundColor;

/// <summary>
/// Initializes a new instance of the ConsoleReadLine class.
/// </summary>
public ConsoleReadLine()
{
this.tokenColors = new ConsoleColor[]
{
this.defaultColor, // Unknown
ConsoleColor.Yellow, // Command
ConsoleColor.Green, // CommandParameter
ConsoleColor.Cyan, // CommandArgument
ConsoleColor.Cyan, // Number
ConsoleColor.Cyan, // String
ConsoleColor.Green, // Variable
this.defaultColor, // Member
this.defaultColor, // LoopLabel
ConsoleColor.DarkYellow, // Attribute
ConsoleColor.DarkYellow, // Type
ConsoleColor.DarkCyan, // Operator
this.defaultColor, // GroupStart
this.defaultColor, // GroupEnd
ConsoleColor.Magenta, // Keyword
ConsoleColor.Red, // Comment
ConsoleColor.DarkCyan, // StatementSeparator
this.defaultColor, // NewLine
this.defaultColor, // LineContinuation
this.defaultColor, // Position
};
}

/// <summary>
/// Read a line of text, colorizing while typing.
/// </summary>
/// <returns>The command line read</returns>
public string Read()
{
this.Initialize();

while (true)
{
ConsoleKeyInfo key = Console.ReadKey(true);

switch (key.Key)
{
case ConsoleKey.Backspace:
this.OnBackspace();
break;
case ConsoleKey.Delete:
this.OnDelete();
break;
case ConsoleKey.Enter:
return this.OnEnter();
case ConsoleKey.RightArrow:
this.OnRight(key.Modifiers);
break;
case ConsoleKey.LeftArrow:
this.OnLeft(key.Modifiers);
break;
case ConsoleKey.Escape:
this.OnEscape();
break;
case ConsoleKey.Home:
this.OnHome();
break;
case ConsoleKey.End:
this.OnEnd();
break;
case ConsoleKey.UpArrow:
case ConsoleKey.DownArrow:
case ConsoleKey.LeftWindows:
case ConsoleKey.RightWindows:
// ignore these
continue;

default:
if (key.KeyChar == '\x0D')
{
goto case ConsoleKey.Enter; // Ctrl-M
}

if (key.KeyChar == '\x08')
{
goto case ConsoleKey.Backspace; // Ctrl-H
}

this.Insert(key);
break;
}
}
}

/// <summary>
/// Initializes the buffer.
/// </summary>
private void Initialize()
{
this.buffer.Length = 0;
this.current = 0;
this.rendered = 0;
this.cursor = new Cursor();
}

/// <summary>
/// Inserts a key.
/// </summary>
/// <param name="key">The key to insert.</param>
private void Insert(ConsoleKeyInfo key)
{
this.buffer.Insert(this.current, key.KeyChar);
this.current++;
this.Render();
}

/// <summary>
/// The End key was entered..
/// </summary>
private void OnEnd()
{
this.current = this.buffer.Length;
this.cursor.Place(this.rendered);
}

/// <summary>
/// The Home key was entered.
/// </summary>
private void OnHome()
{
this.current = 0;
this.cursor.Reset();
}

/// <summary>
/// The Escape key was entered.
/// </summary>
private void OnEscape()
{
this.buffer.Length = 0;
this.current = 0;
this.Render();
}

/// <summary>
/// Moves to the left of the cursor position.
/// </summary>
/// <param name="consoleModifiers">Enumeration for Alt, Control,
/// and Shift keys.</param>
private void OnLeft(ConsoleModifiers consoleModifiers)
{
if ((consoleModifiers & ConsoleModifiers.Control) != 0)
{
// Move back to the start of the previous word.
if (this.buffer.Length > 0 && this.current != 0)
{
bool nonLetter = IsSeparator(this.buffer[this.current - 1]);
while (this.current > 0 && (this.current - 1 <
this.buffer.Length))
{
this.MoveLeft();

if (IsSeparator(this.buffer[this.current]) != nonLetter)
{
if (!nonLetter)
{
this.MoveRight();
break;
}

nonLetter = false;
}
}
}
}
else
{
this.MoveLeft();
}
}

/// <summary>
/// Determines if a character is a separator.
/// </summary>
/// <param name="ch">Character to investigate.</param>
/// <returns>A value that indicates whether the character
/// is a separator.</returns>
private static bool IsSeparator(char ch)
{
return !Char.IsLetter(ch);
}

/// <summary>
/// Moves to what is to the right of the cursor position.
/// </summary>
/// <param name="consoleModifiers">Enumeration for Alt, Control,
/// and Shift keys.</param>
private void OnRight(ConsoleModifiers consoleModifiers)
{
if ((consoleModifiers & ConsoleModifiers.Control) != 0)
{
// Move to the next word.
if (this.buffer.Length != 0 && this.current < this.buffer.Length)
{
bool nonLetter = IsSeparator(this.buffer[this.current]);
while (this.current < this.buffer.Length)
{
this.MoveRight();

if (this.current == this.buffer.Length)
{
break;
}

if (IsSeparator(this.buffer[this.current]) != nonLetter)
{
if (nonLetter)
{
break;
}

nonLetter = true;
}
}
}
}
else
{
this.MoveRight();
}
}

/// <summary>
/// Moves the cursor one character to the right.
/// </summary>
private void MoveRight()
{
if (this.current < this.buffer.Length)
{
char c = this.buffer[this.current];
this.current++;
Cursor.Move(1);
}
}

/// <summary>
/// Moves the cursor one character to the left.
/// </summary>
private void MoveLeft()
{
if (this.current > 0 && (this.current - 1 < this.buffer.Length))
{
this.current--;
char c = this.buffer[this.current];
Cursor.Move(-1);
}
}

/// <summary>
/// The Enter key was entered.
/// </summary>
/// <returns>A newline character.</returns>
private string OnEnter()
{
Console.Out.Write("\n");
return this.buffer.ToString();
}

/// <summary>
/// The delete key was entered.
/// </summary>
private void OnDelete()
{
if (this.buffer.Length > 0 && this.current < this.buffer.Length)
{
this.buffer.Remove(this.current, 1);
this.Render();
}
}

/// <summary>
/// The Backspace key was entered.
/// </summary>
private void OnBackspace()
{
if (this.buffer.Length > 0 && this.current > 0)
{
this.buffer.Remove(this.current - 1, 1);
this.current--;
this.Render();
}
}

/// <summary>
/// Displays the line.
/// </summary>
private void Render()
{
string text = this.buffer.ToString();

// The PowerShell tokenizer is used to decide how to colorize


// the input. Any errors in the input are returned in 'errors',
// but we won't be looking at those here.
Collection<PSParseError> errors = null;
Collection<PSToken> tokens = PSParser.Tokenize(text, out errors);

if (tokens.Count > 0)
{
// We can skip rendering tokens that end before the cursor.
int i;
for (i = 0; i < tokens.Count; ++i)
{
if (this.current >= tokens[i].Start)
{
break;
}
}

// Place the cursor at the start of the first token to render. The
// last edit may require changes to the colorization of characters
// preceding the cursor.
this.cursor.Place(tokens[i].Start);

for (; i < tokens.Count; ++i)


{
// Write out the token. We don't use tokens[i].Content, instead
we
// use the actual text from our input because the content
sometimes
// excludes part of the token, e.g. the quote characters of a
string.
Console.ForegroundColor = this.tokenColors[(int)tokens[i].Type];
Console.Out.Write(text.Substring(tokens[i].Start,
tokens[i].Length));

// Whitespace doesn't show up in the array of tokens. Write it


out here.
if (i != (tokens.Count - 1))
{
Console.ForegroundColor = this.defaultColor;
for (int j = (tokens[i].Start + tokens[i].Length); j < tokens[i
+ 1].Start; ++j)
{
Console.Out.Write(text[j]);
}
}
}

// It's possible there is text left over to output. This happens


when there is
// some error during tokenization, e.g. a string literal is missing
a closing quote.
Console.ForegroundColor = this.defaultColor;
for (int j = tokens[i - 1].Start + tokens[i - 1].Length; j <
text.Length; ++j)
{
Console.Out.Write(text[j]);
}
}
else
{
// If tokenization completely failed, just redraw the whole line.
This
// happens most frequently when the first token is incomplete, like
a string
// literal missing a closing quote.
this.cursor.Reset();
Console.Out.Write(text);
}

// If characters were deleted, we must write over previously written


characters
if (text.Length < this.rendered)
{
Console.Out.Write(new string(' ', this.rendered - text.Length));
}

this.rendered = text.Length;
this.cursor.Place(this.current);
}

/// <summary>
/// A helper class for maintaining the cursor while editing the command
line.
/// </summary>
internal class Cursor
{
/// <summary>
/// The top anchor for reposition the cursor.
/// </summary>
private int anchorTop;

/// <summary>
/// The left anchor for repositioning the cursor.
/// </summary>
private int anchorLeft;

/// <summary>
/// Initializes a new instance of the Cursor class.
/// </summary>
public Cursor()
{
this.anchorTop = Console.CursorTop;
this.anchorLeft = Console.CursorLeft;
}

/// <summary>
/// Moves the cursor.
/// </summary>
/// <param name="delta">The number of characters to move.</param>
internal static void Move(int delta)
{
int position = Console.CursorTop * Console.BufferWidth +
Console.CursorLeft + delta;
Console.CursorLeft = position % Console.BufferWidth;
Console.CursorTop = position / Console.BufferWidth;
}

/// <summary>
/// Resets the cursor position.
/// </summary>
internal void Reset()
{
Console.CursorTop = this.anchorTop;
Console.CursorLeft = this.anchorLeft;
}

/// <summary>
/// Moves the cursor to a specific position.
/// </summary>
/// <param name="position">The new position.</param>
internal void Place(int position)
{
Console.CursorLeft = (this.anchorLeft + position) %
Console.BufferWidth;
int cursorTop = this.anchorTop + (this.anchorLeft + position) /
Console.BufferWidth;
if (cursorTop >= Console.BufferHeight)
{
this.anchorTop -= cursorTop - Console.BufferHeight + 1;
cursorTop = Console.BufferHeight - 1;
}

Console.CursorTop = cursorTop;
}
} // End Cursor
}
}

Consulte también
System.Management.Automation.Host.PSHost

System.Management.Automation.Host.Pshostuserinterface

System.Management.Automation.Host.Pshostrawuserinterface
Ejemplos de espacio de ejecución
Artículo • 25/09/2021

En esta sección se incluye código de ejemplo que muestra cómo usar diferentes tipos de
espacios de ejecución para ejecutar comandos de forma sincrónica y asincrónica. Puede
usar Microsoft Visual Studio para crear una aplicación de consola y, a continuación,
copiar el código de los temas de esta sección en la aplicación host.

En esta sección

7 Nota

Para obtener ejemplos de aplicaciones host que crean interfaces de host


personalizadas, vea Ejemplos de host personalizados.

Ejemplo Runspace01 En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar el cmdlet Get-Process de
forma sincrónica y mostrar su salida en una ventana de consola.

Ejemplo runspace02 En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar los cmdlets Get-Process y
Sort-Object de forma sincrónica. Los resultados de estos comandos se muestran
mediante system.Windows. Control Forms.Datagridview.

Ejemplo Runspace03 En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar un script sincrónicamente y
cómo controlar los errores de no terminación. El script recibe una lista de nombres de
procesos y después los recupera. Los resultados del script, incluidos los errores de no
terminación generados al ejecutarlo, se muestran en una ventana de consola.

Ejemplo Runspace04 En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar comandos y cómo detectar
los errores de terminación que se producen al ejecutar los comandos. Se ejecutan dos
comandos; al último, se le pasa un argumento de parámetro que no es válido. Como
resultado, no se devuelve ningún objeto y se produce un error de terminación.

Ejemplo Runspace05 En este ejemplo se muestra cómo agregar un complemento a un


objeto System.Management.Automation.Runspaces.Initialsessionstate para que el
cmdlet del complemento esté disponible cuando se abra el espacio de ejecución. El
complemento proporciona un cmdlet Get-Proc (definido por el ejemplo
GetProcessSample01)que se ejecuta sincrónicamente mediante un objeto
System.Management.Automation.Powershell.

Ejemplo runspace06 En este ejemplo se muestra cómo agregar un módulo a un objeto


System.Management.Automation.Runspaces.Initialsessionstate para que el módulo se
cargue cuando se abra el espacio de ejecución. El módulo proporciona un cmdlet Get-
Proc (definido por el ejemplo GetProcessSample02)que se ejecuta sincrónicamente
mediante un objeto System.Management.Automation.Powershell.

Ejemplo Runspace07 En este ejemplo se muestra cómo crear un espacio de ejecución y,


a continuación, usar ese espacio de ejecución para ejecutar dos cmdlets de forma
sincrónica mediante un objeto System.Management.Automation.Powershell.

Ejemplo Runspace08 En este ejemplo se muestra cómo agregar comandos y


argumentos a la canalización de un objeto System.Management.Automation.Powershell
y cómo ejecutar los comandos sincrónicamente.

Ejemplo Runspace09 En este ejemplo se muestra cómo agregar un script a la


canalización de un objeto System.Management.Automation.Powershell y cómo ejecutar
el script de forma asincrónica. Los eventos se usan para controlar la salida del script.

Ejemplo runspace10 En este ejemplo se muestra cómo crear un estado de sesión inicial
predeterminado, cómo agregar un cmdlet a
System.Management.Automation.Runspaces.Initialsessionstate,cómo crear un espacio
de ejecución que usa el estado de sesión inicial y cómo ejecutar el comando mediante
un objeto System.Management.Automation.Powershell.

Ejemplo Runspace11 Esto muestra cómo usar la clase


System.Management.Automation.Proxycommand para crear un comando de proxy que
llama a un cmdlet existente, pero restringe el conjunto de parámetros disponibles. El
comando de proxy se agrega entonces a un estado de sesión inicial que se usa para
crear un espacio de ejecución restringido. Esto significa que el usuario puede tener
acceso a la funcionalidad del cmdlet solo mediante el comando de proxy.

Consulte también
Ejemplo Runspace01
Artículo • 24/09/2021

En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar el cmdlet Get-Process de
forma sincrónica. El cmdlet Get-Process devuelve objetos System.Diagnostics.Process
para cada proceso que se ejecuta en el equipo local. Los valores de las propiedades
System.Diagnostics.Process.Processname* y System.Diagnostics.Process.Handlecount* se
extraen de los objetos devueltos y se muestran en una ventana de consola.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
Crear un objeto System.Management.Automation.Powershell para ejecutar un
comando.

Agregar un comando a la canalización del objeto


System.Management.Automation.Powershell.

Ejecutar el comando de forma sincrónica.

Usar objetos System.Management.Automation.PSObject para extraer propiedades


de los objetos devueltos por el comando.

Ejemplo
En este ejemplo se ejecuta el cmdlet Get-Process de forma sincrónica en el espacio de
ejecución predeterminado proporcionado por Windows PowerShell.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Management.Automation;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace01
{
/// <summary>
/// This sample uses the PowerShell class to execute
/// the get-process cmdlet synchronously. The name and
/// handlecount are then extracted from the PSObjects
/// returned and displayed.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerShell object to run a command.
/// 2. Adding a command to the pipeline of the PowerShell object.
/// 3. Running the command synchronously.
/// 4. Using PSObject objects to extract properties from the objects
/// returned by the command.
/// </remarks>
private static void Main(string[] args)
{
// Create a PowerShell object. Creating this object takes care of
// building all of the other data structures needed to run the
command.
using (PowerShell powershell = PowerShell.Create().AddCommand("get-
process"))
{
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Invoke the command synchronously and display the


// ProcessName and HandleCount properties of the
// objects that are returned.
foreach (PSObject result in powershell.Invoke())
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Ejemplo Runspace02
Artículo • 25/09/2021

En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar los cmdlets Get-Process y
Sort-Object de forma sincrónica. El cmdlet Get-Process devuelve objetos
System.Diagnostics.Process para cada proceso que se ejecuta en el equipo local y
ordena los objetos en función de su Sort-Object propiedad
System.Diagnostics.Process.Id*. Los resultados de estos comandos se muestran
mediante un control System.Windows.Forms.Datagridview.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Powershell para ejecutar


comandos.

Agregar comandos a la canalización del objeto


System.Management.Automation.Powershell.

Ejecutar los comandos de forma sincrónica.

Usar un control System.Windows.Forms.Datagridview para mostrar la salida de los


comandos en una Windows Forms aplicación.

Ejemplo
En este ejemplo se ejecutan los cmdlets Get-Process y Sort-Object de forma sincrónica
en el espacio de ejecución predeterminado proporcionado por Windows PowerShell. La
salida se muestra en un formulario mediante un control
System.Windows.Forms.Datagridview.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Windows.Forms;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace02
{
/// <summary>
/// This method creates the form where the output is displayed.
/// </summary>
private static void CreateForm()
{
Form form = new Form();
DataGridView grid = new DataGridView();
form.Controls.Add(grid);
grid.Dock = DockStyle.Fill;

// Create a PowerShell object. Creating this object takes care of


// building all of the other data structures needed to run the
command.
using (PowerShell powershell = PowerShell.Create())
{
powershell.AddCommand("get-process").AddCommand("sort-
object").AddArgument("ID");
if (Runspace.DefaultRunspace == null)
{
Runspace.DefaultRunspace = powershell.Runspace;
}

Collection<PSObject> results = powershell.Invoke();

// The generic collection needs to be re-wrapped in an ArrayList


// for data-binding to work.
ArrayList objects = new ArrayList();
objects.AddRange(results);

// The DataGridView will use the PSObjectTypeDescriptor type


// to retrieve the properties.
grid.DataSource = objects;
}

form.ShowDialog();
}

/// <summary>
/// This sample uses a PowerShell object to run the Get-Process
/// and Sort-Object cmdlets synchronously. Windows Forms and
/// data binding are then used to display the results in a
/// DataGridView control.
/// </summary>
/// <param name="args">The parameter is not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerShell object.
/// 2. Adding commands and arguments to the pipeline of
/// the PowerShell object.
/// 3. Running the commands synchronously.
/// 4. Using a DataGridView control to display the output
/// of the commands in a Windows Forms application.
/// </remarks>
private static void Main(string[] args)
{
Runspace02.CreateForm();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace03
Artículo • 24/09/2021

En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar un script sincrónicamente y
cómo controlar los errores de no terminación. El script recibe una lista de nombres de
procesos y después los recupera. Los resultados del script, incluidos los errores de no
terminación generados al ejecutarlo, se muestran en una ventana de consola.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Powershell para ejecutar un


script.

Agregar un script a la canalización del objeto


System.Management.Automation.Powershell.

Pasar objetos de entrada al script desde el programa que realiza la llamada.

Ejecutar el script de forma sincrónica.

Usar objetos System.Management.Automation.PSObject para extraer y mostrar


propiedades de los objetos devueltos por el script.

Recuperar y mostrar los registros de error que se generaron cuando se ejecutaba


el script.

Ejemplo
Este ejemplo ejecuta un script sincrónicamente en el espacio de ejecución
predeterminado proporcionado por Windows PowerShell. La salida del script y los
errores de no terminación generados se muestran en una ventana de consola.

C#
namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace03
{
/// <summary>
/// This sample shows how to use the PowerShell class to run a
/// script that retrieves process information for the list of
/// process names passed to the script. It shows how to pass input
/// objects to a script and how to retrieve error objects as well
/// as the output objects.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerSHell object to run a script.
/// 2. Adding a script to the pipeline of the PowerShell object.
/// 3. Passing input objects to the script from the calling program.
/// 4. Running the script synchronously.
/// 5. Using PSObject objects to extract and display properties from
/// the objects returned by the script.
/// 6. Retrieving and displaying error records that were generated
/// when the script was run.
/// </remarks>
private static void Main(string[] args)
{
// Define a list of processes to look for.
string[] processNames = new string[]
{
"lsass", "nosuchprocess", "services", "nosuchprocess2"
};

// The script to run to get these processes. Input passed


// to the script will be available in the $input variable.
string script = "$input | get-process -name {$_}";

// Create a PowerShell object. Creating this object takes care of


// building all of the other data structures needed to run the script.
using (PowerShell powershell = PowerShell.Create())
{
powershell.AddScript(script);

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Invoke the script synchronously and display the


// ProcessName and HandleCount properties of the
// objects that are returned.
foreach (PSObject result in powershell.Invoke(processNames))
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}

// Process any error records that were generated while running


// the script.
Console.WriteLine("\nThe following non-terminating errors
occurred:\n");
PSDataCollection<ErrorRecord> errors = powershell.Streams.Error;
if (errors != null && errors.Count > 0)
{
foreach (ErrorRecord err in errors)
{
System.Console.WriteLine(" error: {0}", err.ToString());
}
}
}

System.Console.WriteLine("\nHit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace04
Artículo • 25/09/2021

En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Powershell para ejecutar comandos y cómo detectar
los errores de terminación que se producen al ejecutar los comandos. Se ejecutan dos
comandos; al último, se le pasa un argumento de parámetro que no es válido. Como
resultado, no se devuelve ningún objeto y se produce un error de terminación.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Powershell.

Agregar comandos a la canalización del objeto


System.Management.Automation.Powershell.

Agregar argumentos de parámetro a la canalización.

Invocar los comandos de forma sincrónica.

Usar objetos System.Management.Automation.PSObject para extraer y mostrar


propiedades de los objetos devueltos por los comandos.

Recuperar y mostrar los registros de error generados durante la ejecución de los


comandos.

Detectar y mostrar las excepciones de terminación producidas por los comandos.

Ejemplo
En este ejemplo se ejecutan comandos sincrónicamente en el espacio de ejecución
predeterminado proporcionado por Windows PowerShell. El último comando produce
un error de terminación porque se pasa al comando un argumento de parámetro que
no es válido. El error de terminación está capturado y se muestra.
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace04
{
/// <summary>
/// This sample shows how to use a PowerShell object to run commands.
/// The commands generate a terminating exception that the caller
/// should catch and process.
/// </summary>
/// <param name="args">The parameter is not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerShell object to run commands.
/// 2. Adding commands to the pipeline of the PowerShell object.
/// 3. Passing input objects to the commands from the calling program.
/// 4. Using PSObject objects to extract and display properties from the
/// objects returned by the commands.
/// 5. Retrieving and displaying error records that were generated
/// while running the commands.
/// 6. Catching and displaying terminating exceptions generated
/// while running the commands.
/// </remarks>
private static void Main(string[] args)
{
// Create a PowerShell object.
using (PowerShell powershell = PowerShell.Create())
{
// Add the commands to the PowerShell object.
powershell.AddCommand("Get-ChildItem").AddCommand("Select-
String").AddArgument("*");

// Run the commands synchronously. Because of the bad regular


expression,
// no objects will be returned. Instead, an exception will be
thrown.
try
{
foreach (PSObject result in powershell.Invoke())
{
Console.WriteLine("'{0}'", result.ToString());
}

// Process any error records that were generated while running the
commands.
Console.WriteLine("\nThe following non-terminating errors
occurred:\n");
PSDataCollection<ErrorRecord> errors = powershell.Streams.Error;
if (errors != null && errors.Count > 0)
{
foreach (ErrorRecord err in errors)
{
System.Console.WriteLine(" error: {0}", err.ToString());
}
}
}
catch (RuntimeException runtimeException)
{
// Trap any exception generated by the commands. These exceptions
// will all be derived from the RuntimeException exception.
System.Console.WriteLine(
"Runtime exception: {0}: {1}\n{2}",

runtimeException.ErrorRecord.InvocationInfo.InvocationName,
runtimeException.Message,

runtimeException.ErrorRecord.InvocationInfo.PositionMessage);
}
}

System.Console.WriteLine("\nHit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace05
Artículo • 24/09/2021

En este ejemplo se muestra cómo agregar un complemento a un objeto


System.Management.Automation.Runspaces.Initialsessionstate para que el cmdlet del
complemento esté disponible cuando se abra el espacio de ejecución. El complemento
proporciona un cmdlet Get-Proc (definido por el ejemplo GetProcessSample01)que se
ejecuta sincrónicamente mediante un objeto
System.Management.Automation.Powershell.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Runspaces.Initialsessionstate.

Agregar el complemento al objeto


System.Management.Automation.Runspaces.Initialsessionstate.

Creación de un objeto System.Management.Automation.Runspaces.Runspace que


usa el objeto System.Management.Automation.Runspaces.Initialsessionstate.

Crear un objeto System.Management.Automation.Powershell que use el espacio de


ejecución.

Agregar el cmdlet get-proc del complemento a la canalización del objeto


System.Management.Automation.Powershell.

Ejecutar el comando de forma sincrónica.

Extracción de propiedades de los objetos


System.Management.Automation.PSObject devueltos por el comando.

Ejemplo
En este ejemplo se crea un espacio de ejecución que usa un objeto
System.Management.Automation.Runspaces.Initialsessionstate para definir los
elementos que están disponibles cuando se abre el espacio de ejecución. En este
ejemplo, se agrega un complemento que define un cmdlet Get-Proc al estado de sesión
inicial.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace05
{
/// <summary>
/// This sample shows how to define an initial session state that is
/// used when creating a runspace. The sample invokes a command from
/// a Windows PowerShell snap-in that is present in the console file.
/// </summary>
/// <param name="args">The parameter is not used.</param>
/// <remarks>
/// This sample assumes that user has coppied the GetProcessSample01.dll
/// that is produced by the GetProcessSample01 sample to the current
/// directory.
/// This sample demonstrates the following:
/// 1. Creating a default initial session state.
/// 2. Adding a snap-in to the initial session state.
/// 3. Creating a runspace that uses the initial session state.
/// 4. Creating a PowerShell object that uses the runspace.
/// 5. Adding the snap-in's get-proc cmdlet to the PowerShell object.
/// 6. Using PSObject objects to extract and display properties from
/// the objects returned by the cmdlet.
/// </remarks>
private static void Main(string[] args)
{
// Create the default initial session state. The default initial
// session state contains all the elements provided by Windows
// PowerShell.
InitialSessionState iss = InitialSessionState.CreateDefault();
PSSnapInException warning;
iss.ImportPSSnapIn("GetProcPSSnapIn01", out warning);

// Create a runspace. Notice that no PSHost object is supplied to the


// CreateRunspace method so the default host is used. See the Host
// samples for more information on creating your own custom host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss))
{
myRunSpace.Open();
// Create a PowerShell object.
using (PowerShell powershell = PowerShell.Create())
{
// Add the snap-in cmdlet and specify the runspace.
powershell.AddCommand("GetProcPSSnapIn01\\get-proc");
powershell.Runspace = myRunSpace;

// Run the cmdlet synchronously.


Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the results.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

// Close the runspace to release any resources.


myRunSpace.Close();
}
System.Console.WriteLine("Hit any key to exit...");
System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace06
Artículo • 25/09/2021

En este ejemplo se muestra cómo agregar un módulo a un objeto


System.Management.Automation.Runspaces.Initialsessionstate para que el módulo se
cargue cuando se abra el espacio de ejecución. El módulo proporciona un cmdlet Get-
Proc (definido por el ejemplo GetProcessSample02) que se ejecuta sincrónicamente
mediante un objeto System.Management.Automation.Powershell.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Runspaces.Initialsessionstate.

Agregar el módulo al objeto


System.Management.Automation.Runspaces.Initialsessionstate.

Crear un objeto System.Management.Automation.Runspaces.Runspace que usa el


objeto System.Management.Automation.Runspaces.Initialsessionstate.

Crear un objeto System.Management.Automation.Powershell que use el espacio de


ejecución.

Agregar el cmdlet get-proc del módulo a la canalización del objeto


System.Management.Automation.Powershell.

Ejecutar el comando de forma sincrónica.

Extracción de propiedades de los objetos


System.Management.Automation.PSObject devueltos por el comando.

Ejemplo
En este ejemplo se crea un espacio de ejecución que usa un objeto
System.Management.Automation.Runspaces.Initialsessionstate para definir los
elementos que están disponibles cuando se abre el espacio de ejecución. En este
ejemplo, se agrega un módulo que define Get-Proc cmdlet al estado de sesión inicial.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace06
{
/// <summary>
/// This sample shows how to define an initial session state that is
/// used when creating a runspace. The sample invokes a command from
/// a binary module that is loaded by the initial session state.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample assumes that user has coppied the GetProcessSample02.dll
/// that is produced by the GetProcessSample02 sample to the current
/// directory.
/// This sample demonstrates the following:
/// 1. Creating a default initial session state.
/// 2. Adding a module to the initial session state.
/// 3. Creating a runspace that uses the initial session state.
/// 4. Creating a PowerShell object that uses the runspace.
/// 5. Adding the module's get-proc cmdlet to the PowerShell object.
/// 6. Running the command synchronously.
/// 7. Using PSObject objects to extract and display properties from
/// the objects returned by the cmdlet.
/// </remarks>
private static void Main(string[] args)
{
// Create the default initial session state and add the module.
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new string[] { @".\GetProcessSample02.dll" });

// Create a runspace. Notice that no PSHost object is supplied to the


// CreateRunspace method so the default host is used. See the Host
// samples for more information on creating your own custom host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss))
{
myRunSpace.Open();

// Create a PowerShell object.


using (PowerShell powershell = PowerShell.Create())
{
// Add the cmdlet and specify the runspace.
powershell.AddCommand(@"GetProcessSample02\get-proc");
powershell.Runspace = myRunSpace;

Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the results.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

// Close the runspace to release any resources.


myRunSpace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace07
Artículo • 24/09/2021

En este ejemplo se muestra cómo crear un espacio de ejecución y, a continuación, usar


ese espacio de ejecución para ejecutar dos cmdlets de forma sincrónica mediante un
objeto System.Management.Automation.Powershell.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Runspaces.Runspace mediante


la clase System.Management.Automation.Runspaces.Runspacefactory.

Crear un objeto System.Management.Automation.Powershell que use el espacio de


ejecución.

Agregar cmdlets a la canalización del objeto


System.Management.Automation.Powershell.

Ejecutar los cmdlets de forma sincrónica.

Extraer propiedades de los objetos System.Management.Automation.PSObject


devueltos por el comando.

Ejemplo
En este ejemplo se crea un espacio de ejecución que usa un objeto
System.Management.Automation.PSObject para ejecutar los cmdlets Get-Process y
Measure-Object.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace07
{
/// <summary>
/// This sample shows how to create a runspace and how to run commands
/// using a PowerShell object. It builds a pipeline that runs the
/// get-process cmdlet, which is piped to the measure-object
/// cmdlet to count the number of processes running on the system.
/// </summary>
/// <param name="args">The parameter is not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a runspace using the RunspaceFactory class.
/// 2. Creating a PowerShell object that uses the runspace.
/// 3. Adding cmdlets to the pipeline of the PowerShell object.
/// 4. Running the cmdlets synchronously.
/// 5. Working with PSObject objects to extract properties
/// from the objects returned by the cmdlets.
/// </remarks>
private static void Main(string[] args)
{
Collection<PSObject> result; // Will hold the result
// of running the cmdlets.

// Create a runspace. We can not use the RunspaceInvoke class


// because we need to get at the underlying runspace to
// explicitly add the commands. Notice that no PSHost object is
// supplied to the CreateRunspace method so the default host is
// used. See the Host samples for more information on creating
// your own custom host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace())
{
myRunSpace.Open();

// Create a PowerShell object and specify the runspace.


PowerShell powershell = PowerShell.Create();
powershell.Runspace = myRunSpace;

// Use the using statement so we dispose of the PowerShell object


// when we're done.
using (powershell)
{
// Add the get-process cmdlet to the PowerShell object. Notice
// we are specify the name of the cmdlet, not a script.
powershell.AddCommand("get-process");

// Add the measure-object cmdlet to count the number


// of objects being returned. Commands are always added to the end
// of the pipeline.
powershell.AddCommand("measure-object");
// Run the cmdlets synchronously and save the objects returned.
result = powershell.Invoke();
}

// Even after disposing of the pipeLine, we still need to set


// the powershell variable to null so that the garbage collector
// can clean it up.
powershell = null;

// Display the results of running the commands (checking that


// everything is ok first.
if (result == null || result.Count != 1)
{
throw new InvalidOperationException(
"pipeline.Invoke() returned the wrong number of
objects");
}

PSMemberInfo count = result[0].Properties["Count"];


if (count == null)
{
throw new InvalidOperationException(
"The object returned doesn't have a 'count' property");
}

Console.WriteLine(
"Runspace07: The Get-Process cmdlet returned {0}
objects",
count.Value);

// Close the runspace to release any resources.


myRunSpace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace08
Artículo • 25/09/2021

En este ejemplo se muestra cómo agregar comandos y argumentos a la canalización de


un objeto System.Management.Automation.Powershell y cómo ejecutar los comandos
sincrónicamente.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Runspaces.Runspace mediante


la clase System.Management.Automation.Runspaces.Runspacefactory.

Crear un objeto System.Management.Automation.Powershell que use el espacio de


ejecución.

Agregar cmdlets a la canalización del objeto


System.Management.Automation.Powershell.

Ejecutar los cmdlets de forma sincrónica.

Extracción de propiedades de los objetos


System.Management.Automation.PSObject devueltos por el comando.

Ejemplo
En este ejemplo se ejecuta los cmdlets Get-Process y Sort-Object mediante un objeto
System.Management.Automation.Powershell.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace08
{
/// <summary>
/// This sample shows how to use a PowerShell object to run commands.
The
/// PowerShell object builds a pipeline that include the get-process
cmdlet,
/// which is then piped to the sort-object cmdlet. Parameters are added
to the
/// sort-object cmdlet to sort the HandleCount property in descending
order.
/// </summary>
/// <param name="args">Parameter is not used.</param>
/// <remarks>
/// This sample demonstrates:
/// 1. Creating a PowerShell object
/// 2. Adding individual commands to the PowerShell object.
/// 3. Adding parameters to the commands.
/// 4. Running the pipeline of the PowerShell object synchronously.
/// 5. Working with PSObject objects to extract properties
/// from the objects returned by the commands.
/// </remarks>
private static void Main(string[] args)
{
Collection<PSObject> results; // Holds the result of the pipeline
execution.

// Create the PowerShell object. Notice that no runspace is specified


so a
// new default runspace is used.
PowerShell powershell = PowerShell.Create();

// Use the using statement so that we can dispose of the PowerShell


object
// when we are done.
using (powershell)
{
// Add the get-process cmdlet to the pipeline of the PowerShell
object.
powershell.AddCommand("get-process");

// Add the sort-object cmdlet and its parameters to the pipeline of


// the PowerShell object so that we can sort the HandleCount
property
// in descending order.
powershell.AddCommand("sort-
object").AddParameter("descending").AddParameter("property", "handlecount");

// Run the commands of the pipeline synchronously.


results = powershell.Invoke();
}

// Even after disposing of the PowerShell object, we still


// need to set the powershell variable to null so that the
// garbage collector can clean it up.
powershell = null;

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the results returned by the commands.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace09
Artículo • 24/09/2021

En este ejemplo se muestra cómo agregar un script a la canalización de un objeto


System.Management.Automation.Powershell y cómo ejecutar el script de forma
asincrónica. Los eventos se usan para controlar la salida del script.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Powershell que use el espacio de


ejecución.

Agregar un script a la canalización del objeto


System.Management.Automation.Powershell.

Uso del método System.Management.Automation.Powershell.Begininvoke* para


ejecutar la canalización de forma asincrónica.

Uso de los eventos del objeto System.Management.Automation.Powershell para


procesar la salida del script.

Uso del método System.Management.Automation.Powershell.Stop* para


interrumpir la invocación de la canalización.

Ejemplo
Este ejemplo se ejecuta para ejecutar un script que genera los números de 1 a 10 con
retrasos entre cada número. El script se ejecuta de forma asincrónica y los eventos se
usan para controlar la salida.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace09
{
/// <summary>
/// This sample shows how to use a PowerShell object to run a
/// script that generates the numbers from 1 to 10 with delays
/// between each number. The pipeline of the PowerShell object
/// is run asynchronously and events are used to handle the output.
/// </summary>
/// <param name="args">The parameter is not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerShell object.
/// 2. Adding a script to the pipeline of the PowerShell object.
/// 3. Using the BeginInvoke method to run the pipeline asynchronously.
/// 4. Using the events of the PowerShell object to process the
/// output of the script.
/// 5. Using the PowerShell.Stop() method to interrupt the invocation of
/// the pipeline.
/// </remarks>
private static void Main(string[] args)
{
Console.WriteLine("Print the numbers from 1 to 10. Hit any key to halt
processing\n");

using (PowerShell powershell = PowerShell.Create())


{
// Add a script to the PowerShell object. The script generates the
// numbers from 1 to 10 in half second intervals.
powershell.AddScript("1..10 | foreach {$_ ; start-sleep -milli
500}");

// Add the event handlers. If we did not care about hooking the
DataAdded
// event, we would let BeginInvoke create the output stream for us.
PSDataCollection<PSObject> output = new PSDataCollection<PSObject>
();
output.DataAdded += new EventHandler<DataAddedEventArgs>
(Output_DataAdded);
powershell.InvocationStateChanged += new
EventHandler<PSInvocationStateChangedEventArgs>
(Powershell_InvocationStateChanged);

// Invoke the pipeline asynchronously.


IAsyncResult asyncResult = powershell.BeginInvoke<PSObject,
PSObject>(null, output);
// Wait for things to happen. If the user hits a key before the
// script has completed, then call the PowerShell Stop() method
// to halt processing.
Console.ReadKey();
if (powershell.InvocationStateInfo.State !=
PSInvocationState.Completed)
{
// Stop the invocation of the pipeline.
Console.WriteLine("\nStopping the pipeline!\n");
powershell.Stop();

// Wait for the Windows PowerShell state change messages to be


displayed.
System.Threading.Thread.Sleep(500);
Console.WriteLine("\nPress a key to exit");
Console.ReadKey();
}
}
}

/// <summary>
/// The output data added event handler. This event is called when
/// data is added to the output pipe. It reads the data that is
/// available and displays it on the console.
/// </summary>
/// <param name="sender">The output pipe this event is associated with.
</param>
/// <param name="e">Parameter is not used.</param>
private static void Output_DataAdded(object sender, DataAddedEventArgs
e)
{
PSDataCollection<PSObject> myp = (PSDataCollection<PSObject>)sender;

Collection<PSObject> results = myp.ReadAll();


foreach (PSObject result in results)
{
Console.WriteLine(result.ToString());
}
}

/// <summary>
/// This event handler is called when the pipeline state is changed.
/// If the state change is to Completed, the handler issues a message
/// asking the user to exit the program.
/// </summary>
/// <param name="sender">This parameter is not used.</param>
/// <param name="e">The PowerShell state information.</param>
private static void Powershell_InvocationStateChanged(object sender,
PSInvocationStateChangedEventArgs e)
{
Console.WriteLine("PowerShell object state changed: state: {0}\n",
e.InvocationStateInfo.State);
if (e.InvocationStateInfo.State == PSInvocationState.Completed)
{
Console.WriteLine("Processing completed, press a key to exit!");
}
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace10
Artículo • 25/09/2021

En este ejemplo se muestra cómo crear un estado de sesión inicial predeterminado,


cómo agregar un cmdlet a
System.Management.Automation.Runspaces.Initialsessionstate,cómo crear un espacio
de ejecución que usa el estado de sesión inicial y cómo ejecutar el comando mediante
un objeto System.Management.Automation.Powershell.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Runspaces.Initialsessionstate.

Agregar un cmdlet (definido por la aplicación host) al objeto


System.Management.Automation.Runspaces.Initialsessionstate.

Crear un objeto System.Management.Automation.Runspaces.Runspace que use el


objeto .

Crear un objeto System.Management.Automation.Powershell que use el objeto


System.Management.Automation.Runspaces.Runspace.

Agregar el comando a la canalización del objeto


System.Management.Automation.Powershell.

Extracción de propiedades de los objetos


System.Management.Automation.PSObject devueltos por el comando.

Ejemplo
En este ejemplo se crea un espacio de ejecución que usa un objeto
System.Management.Automation.Runspaces.Initialsessionstate para definir los
elementos que están disponibles cuando se abre el espacio de ejecución. En este
ejemplo, el cmdlet Get-Proc (definido por la aplicación host) se agrega al estado de
sesión inicial y el cmdlet se ejecuta sincrónicamente mediante un objeto
System.Management.Automation.Powershell.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

#region GetProcCommand

/// <summary>
/// Class that implements the GetProcCommand.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Cmdlet Overrides

/// <summary>
/// For each of the requested process names, retrieve and write
/// the associated processes.
/// </summary>
protected override void ProcessRecord()
{
// Get the current processes.
Process[] processes = Process.GetProcesses();

// Write the processes to the pipeline making them available


// to the next cmdlet. The second argument (true) tells the
// system to enumerate the array, and send one process object
// at a time to the pipeline.
WriteObject(processes, true);
}

#endregion Overrides
} // End GetProcCommand class.

#endregion GetProcCommand

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace10
{
/// <summary>
/// This sample shows how to create a default initial session state, how
to add
/// add a cmdlet to the InitialSessionState object, and then how to
create
/// a Runspace object.
/// </summary>
/// <param name="args">Parameter is not used.</param>
/// This sample demonstrates:
/// 1. Creating an InitialSessionState object.
/// 2. Adding a cmdlet to the InitialSessionState object.
/// 3. Creating a runspace that uses the InitialSessionState object.
/// 4. Creating a PowerShell object that uses the Runspace object.
/// 5. Running the added command synchronously.
/// 6. Working with PSObject objects to extract properties
/// from the objects returned by the pipeline.
private static void Main(string[] args)
{
// Create a default InitialSessionState object. The default
// InitialSessionState object contains all the elements provided
// by Windows PowerShell.
InitialSessionState iss = InitialSessionState.CreateDefault();

// Add the get-proc cmdlet to the InitialSessionState object.


SessionStateCmdletEntry ssce = new SessionStateCmdletEntry("get-proc",
typeof(GetProcCommand), null);
iss.Commands.Add(ssce);

// Create a Runspace object that uses the InitialSessionState object.


// Notice that no PSHost object is specified, so the default host is
used.
// See the Hosting samples for information on creating your own custom
host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss))
{
myRunSpace.Open();

using (PowerShell powershell = PowerShell.Create())


{
powershell.Runspace = myRunSpace;

// Add the get-proc cmdlet to the pipeline of the PowerShell


object.
powershell.AddCommand("get-proc");

Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the output of the pipeline.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

// Close the runspace to release resources.


myRunSpace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplo Runspace11
Artículo • 24/09/2021

En este ejemplo se muestra cómo usar la clase


System.Management.Automation.Proxycommand para crear un comando proxy que
llama a un cmdlet existente, pero restringe el conjunto de parámetros disponibles. El
comando de proxy se agrega entonces a un estado de sesión inicial que se usa para
crear un espacio de ejecución restringido. Esto significa que el usuario puede tener
acceso a la funcionalidad del cmdlet solo mediante el comando de proxy.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
En este ejemplo se muestra lo siguiente.

Crear un objeto System.Management.Automation.Commandmetadata que


describa los metadatos de un cmdlet existente.

Crear un objeto System.Management.Automation.Runspaces.Initialsessionstate.

Modificar los metadatos del cmdlet para quitar un parámetro del cmdlet.

Agregar el cmdlet al objeto


System.Management.Automation.Runspaces.Initialsessionstate y hacer que el
cmdlet se haga privado.

Crear una función de proxy que llame al cmdlet existente, pero expone solo un
conjunto restringido de parámetros.

Agregar la función de proxy al estado de sesión inicial.

Crear un objeto System.Management.Automation.Powershell que use el objeto


System.Management.Automation.Runspaces.Runspace.

Llamar al cmdlet privado y a la función de proxy mediante un objeto


System.Management.Automation.Powershell para mostrar el espacio de ejecución
restringido.
Ejemplo
Esto crea un comando proxy para que un cmdlet privado demuestre un espacio de
ejecución restringido.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet. It has been copied
/// verbatim from the GetProcessSample02.cs sample.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// The names of the processes to act on.
/// </summary>
private string[] processNames;

/// <summary>
/// Gets or sets the list of process names on which
/// the Get-Proc cmdlet will work.
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes specified by the Name
/// parameter. Then, the WriteObject method writes the
/// associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// If no process names are passed to the cmdlet, get all
// processes.
if (this.processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to cmdlet, get and write
// the associated processes.
foreach (string name in this.processNames)
{
WriteObject(Process.GetProcessesByName(name), true);
}
} // if (processNames...
} // ProcessRecord

#endregion Cmdlet Overrides


} // GetProcCommand

#endregion GetProcCommand

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace11
{
/// <summary>
/// This shows how to use the ProxyCommand class to create a proxy
/// command that calls an existing cmdlet, but restricts the set of
/// available parameters. The proxy command is then added to an initial
/// session state that is used to create a constrained runspace. This
/// means that the user can access the cmdlet only through the proxy
/// command.
/// </summary>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a CommandMetadata object that describes the metadata of
an
/// existing cmdlet.
/// 2. Modifying the cmdlet metadata to remove a parameter of the
cmdlet.
/// 3. Adding the cmdlet to an initial session state and making it
private.
/// 4. Creating a proxy function that calls the existing cmdlet, but
exposes
/// only a restricted set of parameters.
/// 6. Adding the proxy function to the initial session state.
/// 7. Calling the private cmdlet and the proxy function to demonstrate
the
/// constrained runspace.
/// </remarks>
private static void Main()
{
// Create a default initial session state. The default initial session
state
// includes all the elements that are provided by Windows PowerShell.
InitialSessionState iss = InitialSessionState.CreateDefault();

// Add the get-proc cmdlet to the initial session state.


SessionStateCmdletEntry cmdletEntry = new
SessionStateCmdletEntry("get-proc", typeof(GetProcCommand), null);
iss.Commands.Add(cmdletEntry);

// Make the cmdlet private so that it is not accessible.


cmdletEntry.Visibility = SessionStateEntryVisibility.Private;

// Set the language mode of the initial session state to NoLanguage to


//prevent users from using language features. Only the invocation of
// public commands is allowed.
iss.LanguageMode = PSLanguageMode.NoLanguage;

// Create the proxy command using cmdlet metadata to expose the


// get-proc cmdlet.
CommandMetadata cmdletMetadata = new
CommandMetadata(typeof(GetProcCommand));

// Remove one of the parameters from the command metadata.


cmdletMetadata.Parameters.Remove("Name");

// Generate the body of a proxy function that calls the original


cmdlet,
// but does not have the removed parameter.
string bodyOfProxyFunction = ProxyCommand.Create(cmdletMetadata);

// Add the proxy function to the initial session state. The name of
the proxy
// function can be the same as the name of the cmdlet, but to clearly
// demonstrate that the original cmdlet is not available a different
name is
// used for the proxy function.
iss.Commands.Add(new SessionStateFunctionEntry("get-procProxy",
bodyOfProxyFunction));

// Create the constrained runspace using the initial session state.


using (Runspace myRunspace = RunspaceFactory.CreateRunspace(iss))
{
myRunspace.Open();

// Call the private cmdlet to demonstrate that it is not available.


try
{
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = myRunspace;
powershell.AddCommand("get-proc").AddParameter("Name",
"*explore*");
powershell.Invoke();
}
}
catch (CommandNotFoundException e)
{
System.Console.WriteLine(
"Invoking 'get-proc' failed as expected: {0}: {1}",
e.GetType().FullName,
e.Message);
}

// Call the proxy function to demonstrate that the -Name parameter


is
// not available.
try
{
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = myRunspace;
powershell.AddCommand("get-procProxy").AddParameter("Name",
"idle");
powershell.Invoke();
}
}
catch (ParameterBindingException e)
{
System.Console.WriteLine(
"\nInvoking 'get-procProxy -Name idle' failed as
expected: {0}: {1}",
e.GetType().FullName,
e.Message);
}

// Call the proxy function to demonstrate that it calls into the


// private cmdlet to retrieve the processes.
using (PowerShell powershell = PowerShell.Create())
{
powershell.Runspace = myRunspace;
powershell.AddCommand("get-procProxy");
List<Process> processes = new List<Process>
(powershell.Invoke<Process>());
System.Console.WriteLine(
"\nInvoking the get-procProxy function called into
the get-proc cmdlet and returned {0} processes",
processes.Count);
}

// Close the runspace to release resources.


myRunspace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Escritura de una aplicación de Host de Windows PowerShell
Ejemplos de espacio de ejecución
remoto
Artículo • 24/09/2021

En esta sección se incluye código de ejemplo que muestra cómo crear espacios de
ejecución que se pueden usar para conectarse a un equipo mediante la comunicación
remota Windows PowerShell WS-Management. Puede usar Microsoft Visual Studio para
crear una aplicación de consola y, a continuación, copiar el código de los temas de esta
sección en la aplicación host.

En esta sección

7 Nota

Para obtener más información sobre cómo ejecutar comandos en un equipo


remoto, vea Windows PowerShell Remoting.

Ejemplo RemoteRunspace01 En este ejemplo se muestra cómo crear un espacio de


ejecución remoto que se usa para establecer una conexión remota.

Ejemplo RemoteRunspacePool01 En este ejemplo se muestra cómo construir un grupo


de espacio de ejecución remoto y cómo ejecutar varios comandos simultáneamente
mediante este grupo.
Ejemplo RemoteRunspace01
Artículo • 25/09/2021

En este ejemplo se muestra cómo crear un espacio de ejecución remoto que se usa para
establecer una conexión remota.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
Crear un objeto
System.Management.Automation.Runspaces.Wsmanconnectioninfo.

Establecer las propiedades


System.Management.Automation.Runspaces.Runspaceconnectioninfo.Operationti
meout* y
System.Management.Automation.Runspaces.Runspaceconnectioninfo.Opentimeou
t* del objeto System.Management.Automation.Runspaces.Wsmanconnectioninfo.

Crear un espacio de ejecución remoto que use el objeto


System.Management.Automation.Runspaces.Wsmanconnectioninfo para
establecer la conexión remota.

Cierre el espacio de ejecución remoto para liberar la conexión remota.

Ejemplo
En este ejemplo se define una conexión remota y, a continuación, se usa esa
información de conexión para establecer una conexión remota.

C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Management.Automation; // Windows PowerShell
namespace.
using System.Management.Automation.Runspaces; // Windows PowerShell
namespace.
/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
internal class RemoteRunspace01
{
/// <summary>
/// This sample shows how to use a WSManConnectionInfo object to set
/// various timeouts and how to establish a remote connection.
/// </summary>
/// <param name="args">This parameter is not used.</param>
public static void Main(string[] args)
{
// Create a WSManConnectionInfo object using the default constructor
// to connect to the "localHost". The WSManConnectionInfo object can
// also specify connections to remote computers.
WSManConnectionInfo connectionInfo = new WSManConnectionInfo();

// Set the OperationTimeout property. The OperationTimeout is used to


tell
// Windows PowerShell how long to wait (in milliseconds) before timing
out
// for any operation. This includes sending input data to the remote
computer,
// receiving output data from the remote computer, and more. The user
can
// change this timeout depending on whether the connection is to a
computer
// in the data center or across a slow WAN.
connectionInfo.OperationTimeout = 4 * 60 * 1000; // 4 minutes.

// Set the OpenTimeout property. OpenTimeout is used to tell Windows


PowerShell
// how long to wait (in milliseconds) before timing out while
establishing a
// remote connection. The user can change this timeout depending on
whether the
// connection is to a computer in the data center or across a slow
WAN.
connectionInfo.OpenTimeout = 1 * 60 * 1000; // 1 minute.

// Create a remote runspace using the connection information.


using (Runspace remoteRunspace =
RunspaceFactory.CreateRunspace(connectionInfo))
{
// Establish the connection by calling the Open() method to open the
runspace.
// The OpenTimeout value set previously will be applied while
establishing
// the connection. Establishing a remote connection involves sending
and
// receiving some data, so the OperationTimeout will also play a
role in this process.
remoteRunspace.Open();

// Add the code to run commands in the remote runspace here. The
// OperationTimeout value set previously will play a role here
because
// running commands involves sending and receiving data.

// Close the connection. Call the Close() method to close the remote
// runspace. The Dispose() method (called by using primitive) will
call
// the Close() method if it is not already called.
remoteRunspace.Close();
}
}
}
}
Ejemplo RemoteRunspacePool01
Artículo • 24/09/2021

En este ejemplo se muestra cómo construir un grupo de espacio de ejecución remoto y


cómo ejecutar varios comandos simultáneamente mediante este grupo.

Requisitos
Este ejemplo requiere Windows PowerShell 2.0.

Muestra
Crear un objeto
System.Management.Automation.Runspaces.Wsmanconnectioninfo.

Establecer las propiedades


System.Management.Automation.Runspaces.Runspaceconnectioninfo.Operationti
meout* y
System.Management.Automation.Runspaces.Runspaceconnectioninfo.Opentimeou
t* del objeto System.Management.Automation.Runspaces.Wsmanconnectioninfo.

Crear un espacio de ejecución remoto que use el objeto


System.Management.Automation.Runspaces.Wsmanconnectioninfo para
establecer la conexión remota.

Ejecutar los cmdlets Get-Process y Get-Service simultáneamente mediante el


grupo de espacios de ejecución remoto.

Cierre el grupo de espacio de ejecución remoto para liberar la conexión remota.

Ejemplo
En este ejemplo se muestra cómo construir un grupo de espacio de ejecución remoto y
cómo ejecutar varios comandos simultáneamente mediante este grupo.

C#

namespace Samples
{
using System;
using System.Management.Automation; // Windows PowerShell
namespace.
using System.Management.Automation.Runspaces; // Windows PowerShell
namespace.

/// <summary>
/// This class contains the Main entry point for the application.
/// </summary>
internal class RemoteRunspacePool01
{
/// <summary>
/// This sample shows how to construct a remote RunspacePool and how to
/// concurrently run the get-process and get-service commands using the
/// runspaces of the pool.
/// </summary>
/// <param name="args">Parameter is not used.</param>
public static void Main(string[] args)
{
// Create a WSManConnectionInfo object using the default constructor
to
// connect to the "localhost". The WSManConnectionInfo object can also
// specify connections to remote computers.
WSManConnectionInfo connectionInfo = new WSManConnectionInfo();

// Create a remote runspace pool that uses the WSManConnectionInfo


object.
// The minimum runspaces value of 1 specifies that Windows PowerShell
will
// keep at least 1 runspace open. The maximum runspaces value of 2
specifies
// that Windows PowerShell will allows 2 runspaces to be opened at the
// same time so that two commands can be run concurrently.
using (RunspacePool remoteRunspacePool =
RunspaceFactory.CreateRunspacePool(1, 2, connectionInfo))
{
// Call the Open() method to open the runspace pool and establish
// the connection.
remoteRunspacePool.Open();

// Call the Create() method to create a pipeline, call the


AddCommand(string)
// method to add the "get-process" command, and then call the
BeginInvoke()
// method to run the command asynchronously using a runspace of the
pool.
PowerShell gpsCommand = PowerShell.Create().AddCommand("get-
process");
gpsCommand.RunspacePool = remoteRunspacePool;
IAsyncResult gpsCommandAsyncResult = gpsCommand.BeginInvoke();

// The previous call does not block the current thread because it is
// running asynchronously. Because the remote runspace pool can open
two
// runspaces, the second command can be run.
PowerShell getServiceCommand = PowerShell.Create().AddCommand("get-
service");
getServiceCommand.RunspacePool = remoteRunspacePool;
IAsyncResult getServiceCommandAsyncResult =
getServiceCommand.BeginInvoke();

// When you are ready to handle the output, wait for the command to
complete
// before extracting results. A call to the EndInvoke() method will
block and return
// the output.
PSDataCollection<PSObject> gpsCommandOutput =
gpsCommand.EndInvoke(gpsCommandAsyncResult);

// Process the output from the first command.


if ((gpsCommandOutput != null) && (gpsCommandOutput.Count > 0))
{
Console.WriteLine("The first output from running get-process
command: ");
Console.WriteLine(
"Process Name: {0} Process Id: {1}",

gpsCommandOutput[0].Properties["ProcessName"].Value,
gpsCommandOutput[0].Properties["Id"].Value);
Console.WriteLine();
}

// Now process the output from the second command. As discussed


previously, wait
// for the command to complete before extracting the results.
PSDataCollection<PSObject> getServiceCommandOutput =
getServiceCommand.EndInvoke(
getServiceCommandAsyncResult);

// Process the output of the second command as needed.


if ((getServiceCommandOutput != null) &&
(getServiceCommandOutput.Count > 0))
{
Console.WriteLine("The first output from running get-service
command: ");
Console.WriteLine(
"Service Name: {0} Description: {1} State: {2}",

getServiceCommandOutput[0].Properties["ServiceName"].Value,

getServiceCommandOutput[0].Properties["DisplayName"].Value,

getServiceCommandOutput[0].Properties["Status"].Value);
}

// Once done with running all the commands, close the remote
runspace pool.
// The Dispose() method (called by using primitive) will call
Close(), if it
// is not already called.
remoteRunspacePool.Close();
} // End Using.
} // End Main.
} // End RemoteRunspacePool01 class
}

Consulte también
Información general del archivo de
formato
Artículo • 24/09/2021

El formato de presentación de los objetos devueltos por comandos (cmdlets, funciones


y scripts) se define mediante archivos de formato (archivos format.ps1xml). PowerShell
proporciona varios de estos archivos para definir el formato de presentación de los
objetos devueltos por los comandos proporcionados por PowerShell, como el objeto
System.Diagnostics.Process devuelto por el Get-Process cmdlet. Sin embargo, también
puede crear sus propios archivos de formato personalizados para sobrescribir los
formatos de presentación predeterminados o puede escribir un archivo de formato
personalizado para definir la presentación de los objetos devueltos por sus propios
comandos.

) Importante

Los archivos de formato no determinan los elementos de un objeto que se


devuelven a la canalización. Cuando se devuelve un objeto a la canalización, todos
los miembros de ese objeto están disponibles incluso si no se muestran algunos.

PowerShell usa los datos de estos archivos de formato para determinar qué se muestra y
cómo se formatearán los datos mostrados. Los datos mostrados pueden incluir las
propiedades de un objeto o el valor de un script. Los scripts se usan si desea mostrar
algún valor que no está disponible directamente desde las propiedades de un objeto,
como agregar el valor de dos propiedades de un objeto y, a continuación, mostrar la
suma como un fragmento de datos. El formato de los datos mostrados se realiza
mediante la definición de vistas para los objetos que desea mostrar. Puede definir una
vista única para cada objeto, puede definir una vista única para varios objetos o puede
definir varias vistas para el mismo objeto. No hay ningún límite en el número de vistas
que se pueden definir.

Características comunes de los archivos de


formato
Cada archivo de formato puede definir los siguientes componentes que se pueden
compartir entre todas las vistas definidas por el archivo:
Valor de configuración predeterminado, por ejemplo, si los datos mostrados en las
filas de tablas se mostrarán en la línea siguiente si los datos son más largos que el
ancho de la columna. Para obtener más información sobre esta configuración, vea
Wrap Element for TableRowEntry.

Conjuntos de objetos que puede mostrar cualquiera de las vistas del archivo de
formato. Para obtener más información sobre estos conjuntos (denominados
conjuntos de selección), vea Definir conjuntos de objetos.

Controles comunes que pueden usar todas las vistas del archivo de formato. Los
controles le dan un control más preciso sobre cómo se muestran los datos. Para
obtener más información sobre los controles, vea Definición de controles
personalizados.

Aplicar formato a las vistas


Las vistas de formato pueden mostrar objetos en formato de tabla, formato de lista,
formato ancho y formato personalizado. En su mayor parte, cada definición de formato
se describe mediante un conjunto de etiquetas XML que describen la vista. Cada vista
contiene el nombre de la vista, los objetos que usan la vista y los elementos de la vista,
como la información de columna y fila de una vista de tabla.

Vista de tabla
Enumera las propiedades de un objeto o un valor de bloque de script en una o varias
columnas. Cada columna representa una sola propiedad del objeto o un valor de script.
Puede definir una vista de tabla que muestre todas las propiedades de un objeto, un
subconjunto de las propiedades de un objeto o una combinación de propiedades y
valores de script. Cada fila de la tabla representa un objeto devuelto. La creación de una
vista de tabla es muy similar a cuando se canalizar un objeto al Format-Table cmdlet .
Para obtener más información sobre esta vista, vea Table View.

Vista de lista
Enumera las propiedades de un objeto o un valor de script en una sola columna. Cada
fila de la lista muestra una etiqueta opcional o el nombre de propiedad seguido del
valor de la propiedad o script. La creación de una vista de lista es muy similar a la
canalización de un objeto al Format-List cmdlet . Para obtener más información sobre
esta vista, vea Vista de lista.
Vista amplia
Enumera una sola propiedad de un objeto o un valor de script en una o varias columnas.
No hay ninguna etiqueta ni encabezado para esta vista. La creación de una vista amplia
es muy similar a la canalización de un objeto al Format-Wide cmdlet . Para obtener más
información sobre esta vista, vea Wide View.

Vista personalizada
Muestra una vista personalizable de propiedades de objeto o valores de script que no
cumplen la estructura rígida de vistas de tabla, vistas de lista o vistas anchas. Puede
definir una vista personalizada independiente, o bien puede definir una vista
personalizada que otra vista usa, como una vista de tabla o una vista de lista. La
creación de una vista personalizada es muy similar a canalización de un objeto al
Format-Custom cmdlet . Para obtener más información sobre esta vista, vea Vista

personalizada.

Componentes de una vista


En los siguientes ejemplos XML se muestran los componentes XML básicos de una vista.
Los elementos XML individuales varían en función de la vista que quiera crear, pero los
componentes básicos de las vistas son todos iguales.

Para empezar, cada vista tiene un elemento que especifica un nombre descriptivo que
se Name usa para hacer referencia a la vista. Elemento que define los objetos .NET que
muestra la vista y un ViewSelectedBy elemento de control que define la vista.

XML

<ViewDefinitions>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<ListControl>...</ListControl>
<View>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<WideControl>...</WideControl>
<View>
<View>
<Name>NameOfView</Name>
<ViewSelectedBy>...</ViewSelectedBy>
<CustomControl>...</CustomControl>
</View>
</ViewDefinitions>

Dentro del elemento de control, puede definir uno o varios elementos de entrada. Si usa
varias definiciones, debe especificar qué objetos .NET usan cada definición.
Normalmente solo se necesita una entrada, con una sola definición, para cada control.

XML

<ListControl>
<ListEntries>
<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
<ListEntry>
<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
<ListEntry>
<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
<ListEntry>
</ListEntries>
</ListControl>

Dentro de cada elemento de entrada de una vista, especifique los elementos de


elemento que definen las propiedades o scripts de .NET que se muestran en esa vista.

XML

<ListItems>
<ListItem>...</ListItem>
<ListItem>...</ListItem>
<ListItem>...</ListItem>
</ListItems>

Como se muestra en los ejemplos anteriores, el archivo de formato puede contener


varias vistas, una vista puede contener varias definiciones y cada definición puede
contener varios elementos.
Ejemplo de una vista de tabla
En el ejemplo siguiente se muestran las etiquetas XML utilizadas para definir una vista
de tabla que contiene dos columnas. El elemento ViewDefinitions es el elemento
contenedor de todas las vistas definidas en el archivo de formato. El elemento View
define la tabla, lista, vista amplia o personalizada específica. Dentro de cada elemento
View, el elemento Name especifica el nombre de la vista, el elemento ViewSelectedBy
define los objetos que usan la vista y los distintos elementos de control (como el
elemento que se muestra en el ejemplo siguiente) definen el tipo de la TableControl
vista.

XML

<ViewDefinitions>
<View>
<Name>Name of View</Name>
<ViewSelectedBy>
<TypeName>Object to display using this view</TypeName>
<TypeName>Object to display using this view</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
<TableColumnHeader>
<Width></Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Header for column 1</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Header for column 2</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>
</ViewDefinitions>

Consulte también
Creación de una vista de lista

Creación de una vista de tabla

Creación de una vista amplia

Creación de controles personalizados

Escribir un archivo de tipos y formato de PowerShell


Conceptos del archivo de formato
Artículo • 24/09/2021

Los temas de esta sección proporcionan información que es posible que necesite saber
al crear sus propios archivos de formato, como los distintos tipos de vistas que puede
definir y los componentes especiales de esas vistas.

En esta sección
Crear una vista de tabla Proporciona un ejemplo de una vista de tabla mostrada y los
elementos XML utilizados para definir la vista.

Crear una vista de lista Proporciona un ejemplo de una vista de lista mostrada y los
elementos XML utilizados para definir la vista.

Creación de una vista ancha Proporciona un ejemplo de una vista ancha mostrada y los
elementos XML utilizados para definir la vista.

Crear controles personalizados Proporciona un ejemplo de un control personalizado.

Definir conjuntos de selección Proporciona información, un ejemplo y describe los


elementos XML usados para crear un conjunto de selección.

Definir condiciones para mostrar datos Al definir qué datos muestra una vista o un
control, puede especificar una condición que debe existir para que se muestren los
datos.

Aplicación de formato a los datos mostrados Puede especificar cómo se muestran los
puntos de datos individuales en la vista Lista, Tabla o Ancho.

Archivos de formato de PowerShell Enumera los archivos de formato disponibles


proporcionados por PowerShell.
Creación de una vista de tabla
Artículo • 21/01/2022

Una vista de tabla muestra los datos en una o varias columnas. Cada fila de la tabla
representa un objeto .NET y cada columna de la tabla representa una propiedad del
objeto o un valor de script. Puede definir una vista de tabla que muestre todas las
propiedades de un objeto o un subconjunto de las propiedades de un objeto.

Visualización de una vista de tabla


En el ejemplo siguiente se muestra Windows PowerShell muestra el objeto
System.Serviceprocess.Servicecontroller devuelto por el cmdlet Get-Service. Para este
objeto, Windows PowerShell ha definido una vista de tabla que muestra la propiedad , la
propiedad (esta propiedad es una propiedad de alias para la propiedad Status ) y la
propiedad Name ServiceName DisplayName . Cada fila de la tabla representa un objeto
devuelto por el cmdlet .

Resultados

Status Name DisplayName


------ ---- -----------
Stopped AJRouter AllJoyn Router Service
Stopped ALG Application Layer Gateway Service
Stopped AppIDSvc Application Identity
Running Appinfo Application Information

Definición de la vista tabla


El xml siguiente muestra el esquema de la vista de tabla para mostrar
System.Serviceprocess.Servicecontroller? Objeto Displayproperty=Fullname. Debe
especificar cada propiedad que desee que se muestre en la vista de tabla.

XML

<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>
<TableColumnHeader>
<Width>8</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>18</Width>
</TableColumnHeader>
<TableColumnHeader>
<Width>38</Width>
</TableColumnHeader>
</TableHeaders>
<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Status</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>DisplayName</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>
</TableControl>
</View>

Los siguientes elementos XML se usan para definir una vista de lista:

El elemento View es el elemento primario de la vista de tabla. (Se trata del mismo
elemento primario para las vistas de control personalizadas, anchas y de lista).

El elemento Name especifica el nombre de la vista. Este elemento es necesario


para todas las vistas.

El elemento ViewSelectedBy define los objetos que usan la vista. Este elemento es
obligatorio.

El elemento GroupBy (no se muestra en este ejemplo) define cuándo se muestra


un nuevo grupo de objetos. Se inicia un nuevo grupo cada vez que cambia el valor
de una propiedad o script específicos. Este elemento es opcional.

El elemento Controls (no se muestra en este ejemplo) define los controles


personalizados definidos por la vista de tabla. Los controles le dan una manera de
especificar aún más cómo se muestran los datos. Este elemento es opcional. Una
vista puede definir sus propios controles personalizados o puede usar controles
comunes que puede usar cualquier vista del archivo de formato. Para obtener más
información sobre los controles personalizados, vea Crear controles
personalizados.
El elemento HideTableHeaders (no se muestra en este ejemplo) especifica que la
tabla no mostrará ninguna etiqueta en la parte superior de la tabla. Este elemento
es opcional.

Elemento TableControl que define la información de encabezado y fila de la tabla.


De forma similar a todas las demás vistas, una vista de tabla puede mostrar los
valores de propiedades de objeto o valores generados por scripts.

Definir encabezados de columna


1. El elemento TableHeaders y sus elementos secundarios definen lo que se muestra
en la parte superior de la tabla.

2. El elemento TableColumnHeader define lo que se muestra en la parte superior de


una columna de la tabla. Especifique estos elementos en el orden en que desea
que se muestren los encabezados.

No hay ningún límite en el número de estos elementos que puede usar, pero el
número de elementos TableColumnHeader de la vista de tabla debe ser igual al
número de elementos TableRowEntry que se usan.

3. El elemento Label especifica el texto que se muestra. Este elemento es opcional.

4. El elemento Width especifica el ancho (en caracteres) de la columna. Este elemento


es opcional.

5. El elemento Alignment especifica cómo se muestra la etiqueta. La etiqueta se


puede alinear a la izquierda, a la derecha o centrar. Este elemento es opcional.

Definir las filas de la tabla


Las vistas de tabla pueden proporcionar una o varias definiciones que especifican qué
datos se muestran en las filas de la tabla mediante los elementos secundarios del
elemento TableRowEntries. Tenga en cuenta que puede especificar varias definiciones
para las filas de la tabla, pero los encabezados de las filas siguen siendo los mismos,
independientemente de la definición de fila que se utilice. Normalmente, una tabla solo
tendrá una definición.

En el ejemplo siguiente, la vista proporciona una única definición que muestra los
valores de varias propiedades de System.Diagnostics.Process? Objeto
Displayproperty=Fullname. Una vista de tabla puede mostrar el valor de una propiedad
o el valor de un script (no se muestra en el ejemplo) en sus filas.
XML

<TableRowEntries>
<TableRowEntry>
<TableColumnItems>
<TableColumnItem>
<PropertyName>Status</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>DisplayName</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>

Los siguientes elementos XML se pueden usar para proporcionar definiciones para una
fila:

El elemento TableRowEntries y sus elementos secundarios definen lo que se


muestra en las filas de la tabla.

El elemento TableRowEntry proporciona una definición de la fila. Se requiere al


menos un TableRowEntry; sin embargo, no hay ningún límite máximo para el
número de elementos que puede agregar. En la mayoría de los casos, una vista
solo tendrá una definición.

El elemento EntrySelectedBy especifica los objetos que se muestran mediante una


definición específica. Este elemento es opcional y solo es necesario cuando se
definen varios elementos TableRowEntry que muestran objetos diferentes.

El elemento Wrap especifica que el texto que supera el ancho de columna se


muestra en la línea siguiente. De forma predeterminada, el texto que supera el
ancho de columna se trunca.

El elemento TableColumnItems define las propiedades o scripts cuyos valores se


muestran en la fila.

El elemento TableColumnItem define la propiedad o script cuyo valor se muestra


en la columna de la fila. Se requiere un elemento TableColumnItem para cada
columna de la fila. La primera entrada se muestra en la primera columna, la
segunda entrada en la segunda columna, y así sucesivamente.
El elemento PropertyName especifica la propiedad cuyo valor se muestra en la fila.
Debe especificar una propiedad o un script, pero no puede especificar ambos.

El elemento ScriptBlock especifica el script cuyo valor se muestra en la fila. Debe


especificar un script o una propiedad, pero no puede especificar ambos.

El elemento FormatString especifica un patrón de formato que define cómo se


muestra la propiedad o el valor del script. Este elemento es opcional.

El elemento Alignment especifica cómo se muestra el valor de la propiedad o


script. El valor se puede alinear a la izquierda, a la derecha o centrar. Este elemento
es opcional.

Definir los objetos que usan la vista tabla


Hay dos maneras de definir qué objetos de .NET usan la vista de tabla. Puede usar el
elemento ViewSelectedBy para definir los objetos que pueden mostrar todas las
definiciones de la vista, o puede usar el elemento EntrySelectedBy para definir qué
objetos se muestran mediante una definición específica de la vista. En la mayoría de los
casos, una vista solo tiene una definición, por lo que los objetos normalmente se
definen mediante el elemento ViewSelectedBy.

En el ejemplo siguiente se muestra cómo definir los objetos mostrados por la vista de
tabla mediante los elementos ViewSelectedBy y TypeName. No hay ningún límite en el
número de elementos TypeName que puede especificar y su orden no es significativo.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
la vista de tabla:

El elemento ViewSelectedBy define qué objetos se muestran en la vista de lista.

El elemento TypeName especifica el objeto .NET que muestra la vista. Se requiere


el nombre de tipo completo de .NET. Debe especificar al menos un tipo o conjunto
de selección para la vista, pero no hay ningún número máximo de elementos que
se puedan especificar.

En el ejemplo siguiente se usan los elementos ViewSelectedBy y SelectionSetName. Use


conjuntos de selección donde tenga un conjunto relacionado de objetos que se
muestran mediante varias vistas, como al definir una vista de lista y una vista de tabla
para los mismos objetos. Para obtener más información sobre cómo crear un conjunto
de selección, vea Definición de conjuntos de selección.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<SelectionSetName>.NET Type Set</SelectionSetName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
la vista de lista:

El elemento ViewSelectedBy define qué objetos se muestran en la vista de lista.

El elemento SelectionSetName especifica un conjunto de objetos que la vista


puede mostrar. Debe especificar al menos un conjunto o tipo de selección para la
vista, pero no hay ningún número máximo de elementos que se puedan
especificar.

En el ejemplo siguiente se muestra cómo definir los objetos mostrados por una
definición específica de la vista de tabla mediante el elemento EntrySelectedBy . Con
este elemento, puede especificar el nombre de tipo .NET del objeto, un conjunto de
selección de objetos o una condición de selección que especifique cuándo se usa la
definición. Para obtener más información sobre cómo crear condiciones de selección,
vea Definir condiciones para mostrar datos.

7 Nota

Al crear varias definiciones de la vista de tabla, no se pueden especificar


encabezados de columna diferentes. Solo puede especificar lo que se muestra en
las filas de la tabla, como los objetos que se muestran.

XML
<TableRowEntry>
<EntrySelectedBy>
<TypeName>.NET Type</TypeName>
</EntrySelectedBy>
</TableRowEntry>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
una definición específica de la vista de lista:

El elemento EntrySelectedBy define qué objetos se muestran mediante la


definición.

El elemento TypeName especifica el objeto .NET que se muestra mediante la


definición. Cuando se usa este elemento, se requiere el nombre de tipo completo
de .NET. Debe especificar al menos un tipo, conjunto de selección o condición de
selección para la definición, pero no hay ningún número máximo de elementos
que se puedan especificar.

El elemento SelectionSetName (no mostrado) especifica un conjunto de objetos


que esta definición puede mostrar. Debe especificar al menos un tipo, conjunto de
selección o condición de selección para la definición, pero no hay ningún número
máximo de elementos que se puedan especificar.

El elemento SelectionCondition (no se muestra) especifica una condición que debe


existir para que se utilice esta definición. Debe especificar al menos un tipo,
conjunto de selección o condición de selección para la definición, pero no hay
ningún número máximo de elementos que se puedan especificar. Para obtener
más información sobre cómo definir condiciones de selección, vea Definir
condiciones para mostrar datos.

Usar cadenas de formato


Las cadenas de formato se pueden agregar a una vista para definir aún más cómo se
muestran los datos. En el ejemplo siguiente se muestra cómo definir una cadena de
formato para el valor de la StartTime propiedad .

XML

<TableColumnItem>
<PropertyName>StartTime</PropertyName>
<FormatString>{0:MMM} {0:DD} {0:HH}:{0:MM}</FormatString>
</TableColumnItem>
Los siguientes elementos XML se pueden usar para especificar un patrón de formato:

El elemento TableColumnItem define la propiedad o script cuyo valor se muestra


en la columna de la fila. Se requiere un elemento TableColumnItem para cada
columna de la fila. La primera entrada se muestra en la primera columna, la
segunda en la segunda columna, y así sucesivamente.

El elemento PropertyName especifica la propiedad cuyo valor se muestra en la fila.


Debe especificar una propiedad o un script, pero no puede especificar ambos.

El elemento FormatString especifica un patrón de formato que define cómo se


muestra la propiedad o el valor del script.

En el ejemplo siguiente, se ToString llama al método para dar formato al valor del
script. Los scripts pueden llamar a cualquier método de un objeto . Por lo tanto, si un
objeto tiene un método, como , que tiene parámetros de formato, el script puede llamar
a ese método para dar formato al valor ToString de salida del script.

XML

<ListItem>
<ScriptBlock>
[String]::Format("{0,-10} {1,-8}", $_.LastWriteTime.ToString("d"),
$_.LastWriteTime.ToString("t"))
</ScriptBlock>
</ListItem>

El siguiente elemento XML se puede usar para llamar al ToString método :

El elemento TableColumnItem define la propiedad o script cuyo valor se muestra


en la columna de la fila. Se requiere un elemento TableColumnItem para cada
columna de la fila. La primera entrada se muestra en la primera columna, la
segunda en la segunda columna, y así sucesivamente.

El elemento ScriptBlock especifica el script cuyo valor se muestra en la fila. Debe


especificar un script o una propiedad, pero no puede especificar ambos.

Consulte también
Escritura de un archivo de formato de PowerShell
Creación de una vista de lista
Artículo • 21/01/2022

Una vista de lista muestra los datos en una sola columna (en orden secuencial). Los
datos mostrados en la lista pueden ser el valor de una propiedad .NET o el valor de un
script.

Visualización de una vista de lista


En la salida siguiente se muestra Windows PowerShell muestra las propiedades de
System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname devueltos
por el cmdlet Get-Service. En este ejemplo, se devolvieron tres objetos, con cada objeto
separado del objeto anterior por una línea en blanco.

PowerShell

Get-Service | format-list

Resultados

Name : AEADIFilters
DisplayName : Andrea ADI Filters Service
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess

Name : AeLookupSvc
DisplayName : Application Experience
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32ShareProcess

Name : AgereModemAudio
DisplayName : Agere Modem Call Progress Audio
Status : Running
DependentServices : {}
ServicesDependedOn : {}
CanPauseAndContinue : False
CanShutdown : False
CanStop : True
ServiceType : Win32OwnProcess
...

Definir la vista de lista


El siguiente XML muestra el esquema de vista de lista para mostrar varias propiedades
de System.Serviceprocess.Servicecontroller? Objeto Displayproperty=Fullname. Debe
especificar cada propiedad que desee que se muestre en la vista de lista.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>

Los siguientes elementos XML se usan para definir una vista de lista:

El elemento View es el elemento primario de la vista de lista. (Este es el mismo


elemento primario para las vistas de tabla, ancho y control personalizado).

El elemento Name especifica el nombre de la vista. Este elemento es necesario


para todas las vistas.
El elemento ViewSelectedBy define los objetos que usan la vista. Este elemento es
obligatorio.

El elemento GroupBy define cuándo se muestra un nuevo grupo de objetos. Se


inicia un nuevo grupo cada vez que cambia el valor de una propiedad o script
específicos. Este elemento es opcional.

El elemento Controls define los controles personalizados definidos por la vista de


lista. Los controles le dan una manera de especificar aún más cómo se muestran
los datos. Este elemento es opcional. Una vista puede definir sus propios controles
personalizados o puede usar controles comunes que puede usar cualquier vista del
archivo de formato. Para obtener más información sobre los controles
personalizados, vea Crear controles personalizados.

El elemento ListControl define lo que se muestra en la vista y cómo se le formatee.


De forma similar a todas las demás vistas, una vista de lista puede mostrar los
valores de las propiedades de objeto o los valores generados por el script.

Para obtener un ejemplo de un archivo de formato completo que define una vista de
lista simple, vea Vista de lista (básico).

Proporcionar definiciones para la vista de lista


Las vistas de lista pueden proporcionar una o varias definiciones mediante los
elementos secundarios del elemento ListControl. Normalmente, una vista solo tendrá
una definición. En el ejemplo siguiente, la vista proporciona una única definición que
muestra varias propiedades de System.Diagnostics.Process? Objeto
Displayproperty=Fullname. Una vista de lista puede mostrar el valor de una propiedad o
el valor de un script (no se muestra en el ejemplo).

XML

<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>

Los siguientes elementos XML se pueden usar para proporcionar definiciones para una
vista de lista:

El elemento ListControl y sus elementos secundarios definen lo que se muestra en


la vista.

El elemento ListEntries proporciona las definiciones de la vista. En la mayoría de los


casos, una vista solo tendrá una definición. Este elemento es obligatorio.

El elemento ListEntry proporciona una definición de la vista. Se requiere al menos


un ListEntry; sin embargo, no hay ningún límite máximo para el número de
elementos que puede agregar. En la mayoría de los casos, una vista solo tendrá
una definición.

El elemento EntrySelectedBy especifica los objetos que se muestran mediante una


definición específica. Este elemento es opcional y solo es necesario cuando se
definen varios elementos ListEntry que muestran objetos diferentes.

El elemento ListItems especifica las propiedades y scripts cuyos valores se


muestran en las filas de la vista de lista.

El elemento ListItem especifica una propiedad o script cuyo valor se muestra en


una fila de la vista de lista. Una vista de lista debe especificar al menos una
propiedad o script. No hay ningún límite máximo para el número de filas que se
pueden especificar.

El elemento PropertyName especifica la propiedad cuyo valor se muestra en la fila.


Debe especificar una propiedad o un script, pero no puede especificar ambos.

El elemento ScriptBlock especifica el script cuyo valor se muestra en la fila. Debe


especificar un script o una propiedad, pero no puede especificar ambos.

El elemento Label especifica la etiqueta que se muestra a la izquierda de la


propiedad o el valor de script de la fila. Este elemento es opcional. Si no se
especifica una etiqueta, se muestra el nombre de la propiedad o el script. Para
obtener un ejemplo completo, vea Vista de lista (etiquetas).
El elemento ItemSelectionCondition especifica una condición que debe existir para
que se muestre la fila. Para obtener más información sobre cómo agregar
condiciones a la vista de lista, vea Definir condiciones para mostrar datos. Este
elemento es opcional.

El elemento FormatString especifica un patrón que se usa para mostrar el valor de


la propiedad o el script. Este elemento es opcional.

Para obtener un ejemplo de un archivo de formato completo que define una vista de
lista simple, vea Vista de lista (básico).

Definir los objetos que usan la vista de lista


Hay dos maneras de definir qué objetos de .NET usan la vista de lista. Puede usar el
elemento ViewSelectedBy para definir los objetos que se pueden mostrar en todas las
definiciones de la vista, o puede usar el elemento EntrySelectedBy para definir qué
objetos se muestran mediante una definición específica de la vista. En la mayoría de los
casos, una vista solo tiene una definición, por lo que los objetos se definen
normalmente mediante el elemento ViewSelectedBy.

En el ejemplo siguiente se muestra cómo definir los objetos mostrados por la vista de
lista mediante los elementos ViewSelectedBy y TypeName. No hay ningún límite en el
número de elementos TypeName que puede especificar y su orden no es significativo.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
la vista de lista:

El elemento ViewSelectedBy define qué objetos muestra la vista de lista.

El elemento TypeName especifica el objeto .NET que muestra la vista. Se requiere


el nombre de tipo completo de .NET. Debe especificar al menos un tipo o conjunto
de selección para la vista, pero no hay ningún número máximo de elementos que
se puedan especificar.
Para obtener un ejemplo de un archivo de formato completo, vea Vista de lista (básico).

En el ejemplo siguiente se usan los elementos ViewSelectedBy y SelectionSetName. Use


conjuntos de selección donde tenga un conjunto relacionado de objetos que se
muestran mediante varias vistas, como al definir una vista de lista y una vista de tabla
para los mismos objetos. Para obtener más información sobre cómo crear un conjunto
de selección, vea Definir conjuntos de selección.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<SelectionSetName>.NET Type Set</SelectionSetName>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
la vista de lista:

El elemento ViewSelectedBy define qué objetos muestra la vista de lista.

El elemento SelectionSetName especifica un conjunto de objetos que la vista


puede mostrar. Debe especificar al menos un conjunto o tipo de selección para la
vista, pero no hay ningún número máximo de elementos que se puedan
especificar.

En el ejemplo siguiente se muestra cómo definir los objetos mostrados por una
definición específica de la vista de lista mediante el elemento EntrySelectedBy . Con este
elemento, puede especificar el nombre de tipo .NET del objeto, un conjunto de
selección de objetos o una condición de selección que especifique cuándo se usa la
definición. Para obtener más información sobre cómo crear condiciones de selección,
vea Definir condiciones para mostrar datos.

XML

<ListEntry>
<EntrySelectedBy>
<TypeName>.NET Type</TypeName>
</EntrySelectedBy>
</ListEntry>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
una definición específica de la vista de lista:
El elemento EntrySelectedBy define qué objetos se muestran mediante la
definición.

El elemento TypeName especifica el objeto .NET que se muestra en la definición.


Cuando se usa este elemento, se requiere el nombre de tipo completo de .NET.
Debe especificar al menos un tipo, conjunto de selección o condición de selección
para la definición, pero no hay ningún número máximo de elementos que se
puedan especificar.

El elemento SelectionSetName (no mostrado) especifica un conjunto de objetos


que esta definición puede mostrar. Debe especificar al menos un tipo, conjunto de
selección o condición de selección para la definición, pero no hay ningún número
máximo de elementos que se puedan especificar.

El elemento SelectionCondition (no se muestra) especifica una condición que debe


existir para que se utilice esta definición. Debe especificar al menos un tipo,
conjunto de selección o condición de selección para la definición, pero no hay
ningún número máximo de elementos que se puedan especificar. Para obtener
más información sobre cómo definir condiciones de selección, vea Definir
condiciones para mostrar datos.

Mostrar grupos de objetos en una vista de lista


Puede separar los objetos mostrados por la vista de lista en grupos. Esto no significa
que defina un grupo, solo que Windows PowerShell inicia un nuevo grupo cada vez que
cambia el valor de una propiedad o script específicos. En el ejemplo siguiente, se inicia
un nuevo grupo cada vez que cambia el valor de la propiedad
System.Serviceprocess.Servicecontroller.Servicetype.

XML

<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>

Los siguientes elementos XML se usan para definir cuándo se inicia un grupo:

El elemento GroupBy define la propiedad o el script que inicia el nuevo grupo y


define cómo se muestra el grupo.
El elemento PropertyName especifica la propiedad que inicia un nuevo grupo cada
vez que cambia su valor. Debe especificar una propiedad o un script para iniciar el
grupo, pero no puede especificar ambos.

El elemento ScriptBlock especifica el script que inicia un nuevo grupo cada vez que
cambia su valor. Debe especificar un script o una propiedad para iniciar el grupo,
pero no puede especificar ambos.

El elemento Label define una etiqueta que se muestra al principio de cada grupo.
Además del texto especificado por este elemento, Windows PowerShell muestra el
valor que desencadenó el nuevo grupo y agrega una línea en blanco antes y
después de la etiqueta. Este elemento es opcional.

El elemento CustomControl define un control que se usa para mostrar los datos.
Este elemento es opcional.

El elemento CustomControlName especifica un control común o de vista que se


usa para mostrar los datos. Este elemento es opcional.

Para obtener un ejemplo de un archivo de formato completo que define grupos, vea
Vista de lista (GroupBy).

Usar cadenas de formato


Las cadenas de formato se pueden agregar a una vista para definir aún más cómo se
muestran los datos. En el ejemplo siguiente se muestra cómo definir una cadena de
formato para el valor de la StartTime propiedad .

XML

<ListItem>
<PropertyName>StartTime</PropertyName>
<FormatString>{0:MMM} {0:DD} {0:HH}:{0:MM}</FormatString>
</ListItem>

Los siguientes elementos XML se pueden usar para especificar un patrón de formato:

El elemento ListItem especifica los datos que muestra la vista.

El elemento PropertyName especifica la propiedad cuyo valor muestra la vista.


Debe especificar una propiedad o un script, pero no puede especificar ambos.

El elemento FormatString especifica un patrón de formato que define cómo se


muestra la propiedad o el valor del script en la vista.
El elemento ScriptBlock (no mostrado) especifica el script cuyo valor muestra la
vista. Debe especificar un script o una propiedad, pero no puede especificar
ambos.

En el ejemplo siguiente, se ToString llama al método para dar formato al valor del
script. Los scripts pueden llamar a cualquier método de un objeto . Por lo tanto, si un
objeto tiene un método, como , que tiene parámetros de formato, el script puede llamar
a ese método para dar formato al valor ToString de salida del script.

XML

<ListItem>
<ScriptBlock>
[String]::Format("{0,-10} {1,-8}", $_.LastWriteTime.ToString("d"),
$_.LastWriteTime.ToString("t"))
</ScriptBlock>
</ListItem>

El siguiente elemento XML se puede usar para llamar al ToString método :

El elemento ListItem especifica los datos que muestra la vista.

El elemento ScriptBlock (no mostrado) especifica el script cuyo valor muestra la


vista. Debe especificar un script o una propiedad, pero no puede especificar
ambos.

Vea también
Escribir un cmdlet de Windows PowerShell
Creación de una vista amplia
Artículo • 21/01/2022

Una vista ancha muestra un valor único para cada objeto que se muestra. El valor
mostrado puede ser el valor de una propiedad de objeto .NET o el valor de un script. De
forma predeterminada, no hay ninguna etiqueta ni encabezado para esta vista.

Una pantalla de vista ancha


En el ejemplo siguiente se muestra Windows PowerShell muestra el objeto
System.Diagnostics.Process devuelto por el cmdlet Get-Process cuando su salida se
canalizará al cmdlet Format-Wide. (De forma predeterminada, el cmdlet Get-Process
devuelve una vista de tabla). En este ejemplo, las dos columnas se usan para mostrar el
nombre del proceso para cada objeto devuelto. No se muestra el nombre de la
propiedad del objeto, solo el valor de la propiedad .

Get-Process | format-wide
AEADISRV agrsmsvc
Ati2evxx Ati2evxx
audiodg CCC
CcmExec communicator
Crypserv csrss
csrss DevDtct2
DM1Service dpupdchk
dwm DxStudio
EXCEL explorer
GoogleToolbarNotifier GrooveMonitor
hpqwmiex hpservice
Idle InoRpc
InoRT InoTask
ipoint lsass
lsm MOM
MSASCui notepad
... ...

Definición de la vista ancha


En el xml siguiente se muestra el esquema de vista ancha para el objeto
System.Diagnostics.Process.

XML
View>
<Name>process</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<GroupBy>...</GroupBy>
<Controls>...</Controls>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>

Los siguientes elementos XML se usan para definir una vista amplia:

El elemento View es el elemento primario de la vista ancha. (Se trata del mismo
elemento primario para las vistas de tabla, lista y control personalizado).

El elemento Name especifica el nombre de la vista. Este elemento es necesario


para todas las vistas.

El elemento ViewSelectedBy define los objetos que usan la vista. Este elemento es
obligatorio.

El elemento GroupBy define cuándo se muestra un nuevo grupo de objetos. Se


inicia un nuevo grupo cada vez que cambia el valor de una propiedad o script
específicos. Este elemento es opcional.

Los elementos Controls definen los controles personalizados definidos por la vista
ancha. Los controles le dan una manera de especificar aún más cómo se muestran
los datos. Este elemento es opcional. Una vista puede definir sus propios controles
personalizados o puede usar controles comunes que puede usar cualquier vista del
archivo de formato. Para obtener más información sobre los controles
personalizados, vea Crear controles personalizados.

El elemento WideControl y sus elementos secundarios definen lo que se muestra


en la vista. En el ejemplo anterior, la vista está diseñada para mostrar la propiedad
System.Diagnostics.Process.Processname.

Para obtener un ejemplo de un archivo de formato completo que define una vista ancha
simple, vea Wide View (Basic).
Proporcionar definiciones para la vista ancha
Las vistas anchas pueden proporcionar una o varias definiciones mediante los elementos
secundarios del elemento WideControl. Normalmente, una vista solo tendrá una
definición. En el ejemplo siguiente, la vista proporciona una definición única que
muestra el valor de la propiedad System.Diagnostics.Process.Processname. Una vista
amplia puede mostrar el valor de una propiedad o el valor de un script (no se muestra
en el ejemplo).

XML

<WideControl>
<AutoSize/>
<ColumnNumber></ColumnNumber>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>

Los siguientes elementos XML se pueden usar para proporcionar definiciones para una
vista amplia:

El elemento WideControl y sus elementos secundarios definen lo que se muestra


en la vista.

El elemento AutoSize especifica si el tamaño de columna y el número de columnas


se ajustan en función del tamaño de los datos. Este elemento es opcional.

El elemento ColumnNumber especifica el número de columnas que se muestran


en la vista ancha. Este elemento es opcional.

El elemento WideEntries proporciona las definiciones de la vista. En la mayoría de


los casos, una vista solo tendrá una definición. Este elemento es obligatorio.

El elemento WideEntry proporciona una definición de la vista. Se requiere al menos


un WideEntry; sin embargo, no hay ningún límite máximo para el número de
elementos que puede agregar. En la mayoría de los casos, una vista solo tendrá
una definición.

El elemento EntrySelectedBy especifica los objetos que se muestran mediante una


definición específica. Este elemento es opcional y solo es necesario cuando se
definen varios elementos WideEntry que muestran objetos diferentes.
El elemento WideItem especifica los datos que muestra la vista. A diferencia de
otros tipos de vistas, un control ancho solo puede mostrar un elemento.

El elemento PropertyName especifica la propiedad cuyo valor muestra la vista.


Debe especificar una propiedad o un script, pero no puede especificar ambos.

El elemento ScriptBlock especifica el script cuyo valor muestra la vista. Debe


especificar un script o una propiedad, pero no puede especificar ambos.

El elemento FormatString especifica un patrón que se usa para mostrar los datos.
Este elemento es opcional.

Para obtener un ejemplo de un archivo de formato completo que define una definición
de vista amplia, vea Wide View (Basic).

Definir los objetos que usan la vista ancha


Hay dos maneras de definir qué objetos de .NET usan la vista ancha. Puede usar el
elemento ViewSelectedBy para definir los objetos que pueden mostrar todas las
definiciones de la vista, o puede usar el elemento EntrySelectedBy para definir qué
objetos se muestran mediante una definición específica de la vista. En la mayoría de los
casos, una vista solo tiene una definición, por lo que los objetos normalmente se
definen mediante el elemento ViewSelectedBy.

En el ejemplo siguiente se muestra cómo definir los objetos mostrados por la vista
ancha mediante los elementos ViewSelectedBy y TypeName. No hay ningún límite en el
número de elementos TypeName que puede especificar y su orden no es significativo.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<WideControl>...</WideControl>
</View>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
la vista ancha:

El elemento ViewSelectedBy define qué objetos muestra la vista ancha.

El elemento TypeName especifica el .NET que muestra la vista. Se requiere el


nombre de tipo completo de .NET. Debe especificar al menos un tipo o conjunto
de selección para la vista, pero no hay ningún número máximo de elementos que
se puedan especificar.

Para obtener un ejemplo de un archivo de formato completo, vea Wide View (Básico).

En el ejemplo siguiente se usan los elementos ViewSelectedBy y SelectionSetName. Use


conjuntos de selección donde tenga un conjunto relacionado de objetos que se
muestran mediante varias vistas, como cuando se define una vista ancha y una vista de
tabla para los mismos objetos. Para obtener más información sobre cómo crear un
conjunto de selección, vea Definición de conjuntos de selección.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<SelectionSetName>.NET Type Set</SelectionSetName>
</ViewSelectedBy>
<WideControl>...</WideControl>
</View>

Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
la vista ancha:

El elemento ViewSelectedBy define qué objetos muestra la vista ancha.

El elemento SelectionSetName especifica un conjunto de objetos que la vista


puede mostrar. Debe especificar al menos un conjunto o tipo de selección para la
vista, pero no hay ningún número máximo de elementos que se puedan
especificar.

En el ejemplo siguiente se muestra cómo definir los objetos mostrados por una
definición específica de la vista ancha mediante el elemento EntrySelectedBy . Con este
elemento, puede especificar el nombre de tipo .NET del objeto, un conjunto de
selección de objetos o una condición de selección que especifique cuándo se usa la
definición. Para obtener más información sobre cómo crear condiciones de selección,
vea Definir condiciones para mostrar datos.

XML

<WideEntry>
<EntrySelectedBy>
<TypeName>.NET Type</TypeName>
</EntrySelectedBy>
</WideEntry>
Los siguientes elementos XML se pueden usar para especificar los objetos utilizados por
una definición específica de la vista ancha:

El elemento EntrySelectedBy define qué objetos se muestran mediante la


definición.

El elemento TypeName especifica el .NET que muestra la definición. Cuando se usa


este elemento, se requiere el nombre de tipo completo de .NET. Debe especificar
al menos un tipo, conjunto de selección o condición de selección para la
definición, pero no hay ningún número máximo de elementos que se puedan
especificar.

El elemento SelectionSetName (no se muestra) especifica un conjunto de objetos


que esta definición puede mostrar. Debe especificar al menos un tipo, conjunto de
selección o condición de selección para la definición, pero no hay ningún número
máximo de elementos que se puedan especificar.

El elemento SelectionCondition (no se muestra) especifica una condición que debe


existir para que se utilice esta definición. Debe especificar al menos un tipo,
conjunto de selección o condición de selección para la definición, pero no hay
ningún número máximo de elementos que se puedan especificar. Para obtener
más información sobre cómo definir condiciones de selección, vea Definir
condiciones para mostrar datos.

Mostrar grupos de objetos en una vista ancha


Puede separar los objetos mostrados por la vista ancha en grupos. Esto no significa que
defina un grupo, solo que Windows PowerShell inicia un nuevo grupo cada vez que
cambia el valor de una propiedad o script específicos. En el ejemplo siguiente, se inicia
un nuevo grupo cada vez que cambia el valor de la propiedad
System.Serviceprocess.Servicecontroller.Servicetype.

XML

<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>

Los siguientes elementos XML se usan para definir cuándo se inicia un grupo:
El elemento GroupBy define la propiedad o el script que inicia el nuevo grupo y
define cómo se muestra el grupo.

El elemento PropertyName especifica la propiedad que inicia un nuevo grupo cada


vez que cambia su valor. Debe especificar una propiedad o un script para iniciar el
grupo, pero no puede especificar ambos.

El elemento ScriptBlock especifica el script que inicia un nuevo grupo cada vez que
cambia su valor. Debe especificar un script o una propiedad para iniciar el grupo,
pero no puede especificar ambos.

El elemento Label define una etiqueta que se muestra al principio de cada grupo.
Además del texto especificado por este elemento, Windows PowerShell muestra el
valor que desencadenó el nuevo grupo y agrega una línea en blanco antes y
después de la etiqueta. Este elemento es opcional.

El elemento CustomControl define un control que se usa para mostrar los datos.
Este elemento es opcional.

El elemento CustomControlName especifica un control común o de vista que se


usa para mostrar los datos. Este elemento es opcional.

Para obtener un ejemplo de un archivo de formato completo que define grupos, vea
Wide View (GroupBy).

Usar cadenas de formato


Las cadenas de formato se pueden agregar a una vista amplia para definir aún más
cómo se muestran los datos. En el ejemplo siguiente se muestra cómo definir una
cadena de formato para el valor de la StartTime propiedad .

XML

<WideItem>
<PropertyName>StartTime</PropertyName>
<FormatString>{0:MMM} {0:DD} {0:HH}:{0:MM}</FormatString>
</WideItem>

Los siguientes elementos XML se pueden usar para especificar un patrón de formato:

El elemento WideItem especifica los datos que muestra la vista.

El elemento PropertyName especifica la propiedad cuyo valor muestra la vista.


Debe especificar una propiedad o un script, pero no puede especificar ambos.
El elemento FormatString especifica un patrón de formato que define cómo se
muestra la propiedad o el valor del script en la vista.

El elemento ScriptBlock (no mostrado) especifica el script cuyo valor muestra la


vista. Debe especificar un script o una propiedad, pero no puede especificar
ambos.

En el ejemplo siguiente, se ToString llama al método para dar formato al valor del
script. Los scripts pueden llamar a cualquier método de un objeto . Por lo tanto, si un
objeto tiene un método, como , que tiene parámetros de formato, el script puede llamar
a ese método para dar formato al valor ToString de salida del script.

XML

<WideItem>
<ScriptBlock>
[String]::Format("{0,-10} {1,-8}", $_.LastWriteTime.ToString("d"),
$_.LastWriteTime.ToString("t"))
</ScriptBlock>
</WideItem>

El siguiente elemento XML se puede usar para llamar al ToString método :

El elemento WideItem especifica los datos que muestra la vista.

El elemento ScriptBlock (no mostrado) especifica el script cuyo valor muestra la


vista. Debe especificar un script o una propiedad, pero no puede especificar
ambos.

Consulte también
Vista amplia (Basic)

Vista amplia (GroupBy)

Escritura de un archivo de formato de PowerShell


Creación de controles personalizados
Artículo • 24/09/2021

Los controles personalizados son los componentes más flexibles de un archivo de


formato. A diferencia de las vistas de tabla, lista y ancho que definen una estructura
formal de datos, como una tabla de datos, los controles personalizados permiten definir
cómo se muestra un fragmento de datos individual. Puede definir un conjunto común
de controles personalizados que están disponibles para todas las vistas del archivo de
formato, puede definir controles personalizados que están disponibles para una vista
específica o puede definir un conjunto de controles que están disponibles para un
grupo de objetos.

Ejemplo de control personalizado


En el ejemplo siguiente se muestra un control personalizado que se define en el archivo
Certificates.Format.ps1xml. Este control personalizado se usa para separar los objetos
System.Management.Automation.Signature que se muestran en una vista de tabla.

XML

<Controls>
<Control>
<Name>SignatureTypes-GroupingFormat</Name>
<CustomControl>
<CustomEntries>
<CustomEntry>
<CustomItem>
<Frame>
<LeftIndent>4</LeftIndent>
<CustomItem>
<Text AssemblyName="System.Management.Automation"
BaseName="FileSystemProviderStrings"
ResourceId="DirectoryDisplayGrouping"/>
<ExpressionBinding>
<ScriptBlock>split-path $_.Path</ScriptBlock>
</ExpressionBinding>
<NewLine/>
</CustomItem>
</Frame>
</CustomItem>
</CustomEntry>
</CustomEntries>
</CustomControl>
</Control>
</Controls>
Consulte también
Escritura de un archivo de formato de PowerShell
Carga y exportación de datos de
formato
Artículo • 27/09/2021

Una vez que haya creado el archivo de formato, debe actualizar los datos de formato de
la sesión cargando los archivos en la sesión actual. (Los archivos de formato
proporcionados por Windows PowerShell cargan los complementos que se registran
cuando se abre la sesión actual). Una vez actualizados los datos de formato de la sesión
actual, Windows PowerShell los datos para mostrar los objetos .NET asociados a las
vistas definidas en los archivos de formato cargados. No hay ningún límite en el número
de archivos de formato que se pueden cargar en la sesión actual. Además de actualizar
los datos de formato, puede volver a exportar los datos de formato de la sesión actual a
un archivo de formato.

Carga de datos de formato


Los archivos de formato se pueden cargar en la sesión actual mediante los métodos
siguientes:

Puede importar el archivo de formato en la sesión actual desde la línea de


comandos. Use el cmdlet Update-FormatData como se describe en el
procedimiento siguiente.

Puede crear un manifiesto de módulo que haga referencia al archivo de formato.


Los módulos permiten empaquetar los archivos de formato para su distribución.
Use el cmdlet New-ModuleManifest para crear el manifiesto y el cmdlet Import-
Module para cargar el módulo en la sesión actual. Para obtener más información
sobre los módulos, vea Writing a Windows PowerShell Module.

Puede crear un complemento que haga referencia al archivo de formato. Use


System.Management.Automation.PSSnapIn.Formats para hacer referencia a los
archivos de formato. Se recomienda encarecidamente usar módulos para
empaquetar cmdlets y los archivos de formato y tipos asociados para la
distribución. Para obtener más información sobre los módulos, vea Writing a
Windows PowerShell Module.

Si invoca comandos mediante programación, puede agregar una entrada de


archivo de formato al estado de sesión inicial del espacio de ejecución donde se
ejecutan los comandos. Para obtener más información sobre el tipo de .NET que se
usa para agregar el archivo de formato, vea
System.Management.Automation.Runspaces.Sessionstateformatentry?
Displayproperty=Fullname (clase).

Cuando se carga un archivo de formato, se agrega a una lista interna que Windows
PowerShell usa para determinar qué vista usar al mostrar objetos en la línea de
comandos. Puede anteponer el archivo de formato al principio de la lista, o bien puede
anexarlo al final de la lista. Saber dónde se agrega el archivo de formato a esta lista es
importante si está cargando un archivo de formato que define una vista para un objeto
que tiene definida una vista existente, como cuando desea cambiar cómo se muestra un
objeto devuelto por un cmdlet de Windows PowerShell Core. Si va a cargar un archivo
de formato que define la única vista para un objeto, puede usar cualquiera de los
métodos descritos anteriormente. Si va a cargar un archivo de formato que define otra
vista para un objeto , debe usar el cmdlet Update-FormatData y anteponer el archivo al
principio de la lista.

Almacenamiento del archivo de formato


No es necesario que los archivos de formato se almacenen en el disco. Sin embargo, se
recomienda encarecidamente almacenarlos en la carpeta siguiente:
user\documents\windowspowershell\

Carga de un archivo de formato mediante Import-FormatData


1. Almacene el archivo de formato en el disco.

2. Ejecute el cmdlet Update-FormatData con uno de los siguientes comandos.

Para agregar el archivo de formato al frente de la lista, use este comando. Use este
comando si va a cambiar cómo se muestra un objeto.

PowerShell

Update-FormatData -PrependPath PathToFormattingFile

Para agregar el archivo de formato al final de la lista, use este comando.

PowerShell

Update-FormatData -AppendPath PathToFormattingFile

Una vez que haya agregado un archivo mediante el cmdlet Update-FormatData,


no podrá quitar el archivo de la lista mientras la sesión esté abierta. Debe cerrar la
sesión para quitar el archivo de formato de la lista.

Exportación de datos de formato


Inserte el cuerpo de la sección aquí.
Definición de conjuntos de selección
Artículo • 24/09/2021

Al crear varias vistas y controles, puede definir conjuntos de objetos a los que se hace
referencia como conjuntos de selección. Un conjunto de selección permite definir los
objetos una vez, sin tener que definirlos repetidamente para cada vista o control.
Normalmente, los conjuntos de selección se usan cuando se tiene un conjunto de
objetos .NET relacionados. Por ejemplo, el archivo de formato
(FileSystem.format.ps1xml) define un conjunto de selección de los tipos de sistema de
archivos que FileSystem usan varias vistas.

Dónde se definen y hacen referencia a los


conjuntos de selección
Los conjuntos de selección se definen como parte de los datos comunes que pueden
usar todas las vistas y controles definidos en el archivo de formato. En el ejemplo
siguiente se muestra cómo definir tres conjuntos de selección.

XML

<Configuration>
<SelectionSets>
<SelectionSet>...</SelectionSet>
<SelectionSet>...</SelectionSet>
<SelectionSet>...</SelectionSet>
</SelectionSets>
</Configuration>

Puede hacer referencia a conjuntos de selección de las maneras siguientes:

Cada vista tiene un ViewSelectedBy elemento que define qué objetos se muestran
mediante la vista . El ViewSelectedBy elemento tiene un elemento secundario que
especifica el conjunto de selección que usan todas las SelectionSetName
definiciones de la vista. No hay ninguna restricción en el número de conjuntos de
selección a los que puede hacer referencia desde una vista.

En cada definición de una vista o control, el elemento define qué EntrySelectedBy


objetos se muestran mediante esa definición. Normalmente, una vista o un control
solo tiene una definición, por lo que el elemento define los ViewSelectedBy
objetos. El EntrySelectedBy elemento de la definición tiene un elemento
secundario que especifica el conjunto de SelectionSetName selección. Si especifica
el conjunto de selección para una definición, no puede especificar ninguno de los
demás elementos secundarios del EntrySelectedBy elemento.

En cada definición de una vista o control, el elemento se puede usar para


especificar SelectionCondition una condición para cuando se usa la definición. El
SelectionCondition elemento tiene un elemento secundario que especifica el

conjunto de selección que desencadena la SelectionSetName condición. La


condición se desencadena cuando se muestra cualquiera de los objetos definidos
en el conjunto de selección. Para obtener más información sobre cómo establecer
estas condiciones, vea Definir condiciones para cuando se muestran los datos.

Ejemplo de conjunto de selección


En el ejemplo siguiente se muestra un conjunto de selección que se toma directamente
del FileSystem archivo de formato proporcionado por Windows PowerShell. Para
obtener más información sobre otros archivos Windows PowerShell formato, vea
Windows PowerShell Formatting Files.

XML

<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>

Se hace referencia al conjunto de selección anterior en el ViewSelectedBy elemento de


una vista de tabla.

XML

<ViewDefinitions>
<View>
<Name>Files</Name>
<ViewSelectedBy>
<SelectionSetName>FileSystemTypes</SelectionSetName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
</ViewDefinitions>

Elementos XML
No hay ningún límite en el número de conjuntos de selección que puede definir. Los
siguientes elementos XML se usan para crear un conjunto de selección.

El elemento SelectionSets define los conjuntos de objetos .NET a los que hacen
referencia las vistas y los controles del archivo de formato.

El elemento SelectionSet define un único conjunto de objetos .NET.

El elemento Name especifica el nombre que se usa para hacer referencia al


conjunto de selección.

El elemento Types especifica los tipos .NET de los objetos del conjunto de
selección. (Dentro de los archivos de formato, los objetos se especifican por su
tipo de .NET).

Los siguientes elementos XML se usan para especificar un conjunto de selección.

El elemento siguiente especifica el conjunto de selección que se usará en todas las


definiciones de la vista:

Elemento SelectionSetName para ViewSelectedBy (formato)

Elemento SelectionSetName para EntrySelectedBy for GroupBy (formato)

Los elementos siguientes especifican el conjunto de selección utilizado por una


definición de vista única:

Elemento SelectionSetName para EntrySelectedBy for ListControl (formato)

Elemento SelectionSetName para EntrySelectedBy for TableControl (formato)

Elemento SelectionSetName para EntrySelectedBy for WideControl (formato)

Elemento SelectionSetName para EntrySelectedBy for CustomControl for View


(formato)

Los elementos siguientes especifican el conjunto de selección utilizado por las


definiciones de controles comunes y de vista:

Elemento SelectionSetName para EntrySelectedBy for Controls for View


(formato)
Elemento SelectionSetName para EntrySelectedBy for Controls for Configuration
(formato)

Los elementos siguientes especifican el conjunto de selección utilizado al definir el


objeto que se va a expandir:
Elemento SelectionSetName para EntrySelectedBy for EnumerableExpansion
(formato)

Los siguientes elementos especifican el conjunto de selección utilizado por las


condiciones de selección.

Elemento SelectionSetName para SelectionCondition for Controls for


Configuration (formato)

Elemento SelectionSetName para SelectionCondition for Controls for View


(formato)

Elemento SelectionSetName para SelectionCondition for CustomControl for


View (formato)

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


EnumerableExpansion (formato)

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


ListEntry (formato)

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


TableControl (formato)

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


WideEntry (formato)

Elemento SelectionSetName para SelectionCondition for GroupBy (formato)

Consulte también
SelectionSets

SelectionSet

Nombre

Tipos

Archivos de formato de PowerShell


Definir condiciones para cuando se muestran los datos

Escribir un archivo de formato y tipos de PowerShell


Definición de condiciones para mostrar
datos
Artículo • 25/09/2021

Al definir qué datos muestran una vista o un control, puede especificar una condición
que debe existir para que se muestren los datos. Una propiedad específica puede
desencadenar la condición o cuando un script o un valor de propiedad se evalúa como
true . Cuando se cumple la condición de selección, se usa la definición de la vista o el
control.

Especificar una condición de selección para una


definición
Al crear una definición para una vista o un control, el elemento se usa para especificar
qué objetos usarán la definición o qué condición debe existir para que se
EntrySelectedBy use la definición. El elemento especifica la SelectionCondition

condición.

En el ejemplo siguiente, se especifica una condición de selección para una definición de


una vista de tabla. En este ejemplo, la definición solo se usa cuando el script
especificado se evalúa como true .

XML

<TableRowEntry>
<EntrySelectedBy>
<SelectionCondition>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>
</EntrySelectedBy>
<TableColumnItems>
</TableColumnItems>
</TableRowEntry>

No hay ningún límite en el número de condiciones de selección que puede especificar


para una definición de una vista o control. Los únicos requisitos son los siguientes:

La condición de selección debe especificar un nombre de propiedad o script para


desencadenar la condición, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.

Especificar una condición de selección para un


elemento
También puede especificar cuándo se usa un elemento de una vista de lista o un control
incluyendo ItemSelectionCondition el elemento en la definición del elemento. En el
ejemplo siguiente, se especifica una condición de selección para un elemento de una
vista de lista. En este ejemplo, el elemento solo se usa cuando el script se evalúa como
true .

XML

<ListItem>
<ItemSelectionCondition>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>
</ListItem>

Solo puede especificar una condición de selección para un elemento. Y la condición


debe especificar un nombre de propiedad o script para desencadenar la condición, pero
no puede especificar ambos.

Elementos XML
Los siguientes elementos XML se usan para crear una condición de selección.

Los elementos siguientes especifican las condiciones de selección para las


definiciones de vista:

Elemento SelectionCondition para EntrySelectedBy for TableControl (formato)

Elemento SelectionCondition para EntrySelectedBy for ListControl (formato)

Elemento SelectionCondition para EntrySelectedBy for WideControl (formato)

Elemento SelectionCondition para EntrySelectedBy for CustomControl (formato)

Los elementos siguientes especifican las condiciones de selección para las


definiciones de controles comunes y de vista:
Elemento SelectionCondition para EntrySelectedBy for Controls for
Configuration (formato)

Elemento SelectionCondition para EntrySelectedBy for Controls for View


(formato)

El elemento siguiente especifica la condición de selección para expandir objetos de


colección:
Elemento SelectionCondition para EntrySelectedBy for EnumerableExpansion
(formato)

El elemento siguiente especifica la condición de selección para mostrar un nuevo


grupo de datos:
Elemento SelectionCondition para EntrySelectedBy for GroupBy (formato)

El elemento siguiente especifica una condición de selección de elemento para una


vista de lista:
Elemento ItemSelectionCondition para ListItem for ListControl (formato)

Los elementos siguientes especifican una condición de selección de elementos


para los controles:

Elemento ItemSelectionCondition para ExpressionBinding for Controls for


Configuration (formato)

Elemento ItemSelectionCondition para ExpressionBinding for Controls for View


(formato)

Elemento ItemSelectionCondition para ExpressionBinding for CustomControl


(formato)

Consulte también
Escritura de un archivo de formato de PowerShell
Datos de formato mostrados
Artículo • 24/09/2021

Puede especificar cómo se muestran los puntos de datos individuales en la vista Lista,
Tabla o Ancho. Puede usar el elemento al definir los elementos de la vista o puede usar
el elemento para llamar FormatString al método en los ScriptBlock FormatString
datos.

Usar el elemento FormatString


En el ejemplo siguiente, el valor de la propiedad del objeto TotalProcessorTime
System.Diagnostics.Process tiene el formato mediante el elemento FormatString. la
TotalProcessorTime propiedad

<TableColumnItem>
<PropertyName>TotalProcessorTime</PropertyName>
<FormatString>{0:MMM}{0:dd}{0:HH}:{0:mm}</FormatString>
</TableColumnItem>
Archivos de formato de Windows
PowerShell
Artículo • 27/09/2021

Windows PowerShell proporciona varios archivos de formato (.format.ps1xml) que se


encuentran en el directorio de instalación ( $pshome ). Cada uno de estos archivos define
la presentación predeterminada para un conjunto específico de objetos .NET. Estos
archivos nunca se deben cambiar. Sin embargo, puede usarlos como referencia para
crear sus propios archivos de formato personalizados.

Certificate.Format.ps1xml Define la presentación de objetos en el almacén de


certificados, como certificados x.509 y almacenes de certificados.

DotNetTypes.Format.ps1xml Define la presentación de varios objetos .NET, como

CultureInfo, FileVersionInfo y EventLogEntry.

FileSystem.Format.ps1xml Define la presentación de objetos del sistema de archivos,

como objetos de archivo y directorio.

Help.Format.ps1xml Define las distintas vistas que usa el cmdlet Get-Help, como las

vistas detalladas, completa, parámetros y vistas de ejemplo.

PowerShellCore.Format.ps1xml Define la presentación de los objetos generados por


Windows PowerShell cmdlets principales, como los objetos devueltos por los cmdlets
Get-Member y Get-History.

PowerShellTrace.Format.ps1xml Define la presentación de objetos de seguimiento, como

los generados por el cmdlet Trace-Command.

Registry.Format.ps1xml Define la presentación de objetos del Registro, como los


objetos de clave y entrada.

Vea también
Escribir un cmdlet de Windows PowerShell
Cómo crear un archivo de formato (.
format.ps1xml)
Artículo • 24/09/2021

En este tema se describe cómo crear un archivo de formato (.format.ps1xml).

7 Nota

También puede crear un archivo de formato realizando una copia de uno de los
archivos proporcionados por Windows PowerShell. Si realiza una copia de un
archivo existente, elimine la firma digital existente y agregue su propia firma al
nuevo archivo.

Cree un archivo .format.ps1xml.


1. Cree un archivo de texto (.txt) mediante un editor de texto como Bloc de notas.

2. Copie las líneas siguientes en el archivo de formato.

XML

<?xml version="1.0" encoding="utf-8" ?>


<Configuration>
<ViewDefinitions>
</ViewDefinitions>
</Configuration>

Las <Configuration></Configuration> etiquetas definen el nodo


Configuration raíz. Todas las etiquetas XML adicionales se incluyen dentro de
este nodo.

Las <ViewDefinitions></ViewDefinitions> etiquetas definen el


ViewDefinitions nodo. Todas las vistas se definen dentro de este nodo.

3. Guarde el archivo en Windows PowerShell carpeta de instalación, en la carpeta del


módulo o en una subcarpeta de la carpeta del módulo. Use el siguiente formato
de nombre al guardar el archivo: MyFile.format.ps1xml . Los archivos de formato
deben usar la .format.ps1xml extensión .
Ya está listo para agregar vistas al archivo de formato. No hay ningún límite en el
número de vistas que se pueden definir en un archivo de formato. Puede agregar
una vista única para cada objeto, varias vistas para el mismo objeto o una sola
vista que usan varios objetos.

Consulte también
Escribir un archivo Windows PowerShell de tipos y formato
Vista amplia (Basic)
Artículo • 24/09/2021

En este ejemplo se muestra cómo implementar una vista ancha básica que muestra
System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname devueltos
por el Get-Service cmdlet . Para obtener más información sobre los componentes de
una vista ancha, vea Creating a Wide View.

Cargar este archivo de formato


1. Copie el XML de la sección Ejemplo de este tema en un archivo de texto.

2. Guarde el archivo de texto. Asegúrese de agregar la format.ps1xml extensión al


archivo para identificarla como un archivo de formato.

3. Abra Windows PowerShell y ejecute el siguiente comando para cargar el archivo


de formato en la sesión actual: Update-FormatData -PrependPath
<PathToFormattingFile> .

2 Advertencia

Este archivo de formato define la presentación de un objeto que ya está


definido por un Windows PowerShell de formato. Debe usar el parámetro
PrependPath al ejecutar el cmdlet y no puede cargar este archivo de formato
como módulo.

Muestra
Este archivo de formato muestra los siguientes elementos XML:

Elemento Name de la vista.

Elemento ViewSelectedBy que define qué objetos muestra la vista.

Elemento WideItem que define qué propiedad muestra la vista.

Ejemplo
El xml siguiente define una vista ancha que muestra el valor de la propiedad
System.Serviceprocess.Servicecontroller.Servicename.

XML

<?xml version="1.0" encoding="utf-8" ?>

<Configuration>
<ViewDefinitions>
<View>
<Name>ServiceWideView</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ServiceName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
</ViewDefinitions>
</Configuration>

En el ejemplo siguiente se muestra Windows PowerShell muestra


System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname después de
cargar este archivo de formato.

PowerShell

Get-Service f*

Resultados

Fax FCSAM
fdPHost FDResPub
FontCache FontCache3.0.0.0
FSysAgent FwcAgent

Consulte también
Ejemplos de archivos de formato

Escritura de un archivo de formato de PowerShell


Vista amplia (GroupBy)
Artículo • 27/09/2021

En este ejemplo se muestra cómo implementar una vista amplia que muestra los grupos
de System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname
devueltos por el Get-Service cmdlet . Para obtener más información sobre los
componentes de una vista ancha, vea Creating a Wide View.

Cargar este archivo de formato


1. Copie el XML de la sección Ejemplo de este tema en un archivo de texto.

2. Guarde el archivo de texto. Asegúrese de agregar la format.ps1xml extensión al


archivo para identificarla como un archivo de formato.

3. Abra Windows PowerShell y ejecute el siguiente comando para cargar el archivo


de formato en la sesión actual: Update-FormatData -PrependPath <Path to file> .

2 Advertencia

Este archivo de formato define la presentación de un objeto que ya está


definido por un Windows PowerShell archivos de formato. Debe usar el
parámetro PrependPath al ejecutar el cmdlet y no puede cargar este archivo
de formato como módulo.

Muestra
Este archivo de formato muestra los siguientes elementos XML:

Elemento Name de la vista.

Elemento ViewSelectedBy que define qué objetos muestra la vista.

Elemento GroupBy que define cuándo se muestra un nuevo grupo.

Elemento WideItem que define qué propiedad muestra la vista.

Ejemplo
El siguiente XML define una vista amplia que muestra grupos de objetos. Cada nuevo
grupo se inicia cuando cambia el valor de la propiedad
System.Serviceprocess.Servicecontroller.Servicetype.

XML

<?xml version="1.0" encoding="utf-8" ?>

<Configuration>
<ViewDefinitions>
<View>
<Name>ServiceWideView</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ServiceName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>
</ViewDefinitions>
</Configuration>

En el ejemplo siguiente se muestra Windows PowerShell muestra


System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname después de
cargar este archivo de formato.

PowerShell

Get-Service f*

Resultados

Service Type: Win32OwnProcess

Fax FCSAM

Service Type: Win32ShareProcess

fdPHost FDResPub
FontCache
Service Type: Win32OwnProcess

FontCache3.0.0.0 FSysAgent
FwcAgent

Consulte también
Ejemplos de archivos de formato

Escritura de un archivo de formato de PowerShell


Vista de lista (Basic)
Artículo • 24/09/2021

En este ejemplo se muestra cómo implementar una vista de lista básica que muestra
System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname devueltos
por el cmdlet Get-Service. Para obtener más información sobre los componentes de una
vista de lista, vea Crear una vista de lista.

Cargar este archivo de formato


1. Copie el XML de la sección Ejemplo de este tema en un archivo de texto.

2. Guarde el archivo de texto. Asegúrese de agregar la format.ps1xml extensión al


archivo para identificarla como un archivo de formato.

3. Abra Windows PowerShell y ejecute el siguiente comando para cargar el archivo


de formato en la sesión actual: Update-formatdata -prependpath
PathToFormattingFile .

2 Advertencia

Este archivo de formato define la presentación de un objeto que ya está definido


por un Windows PowerShell de formato. Debe usar el parámetro al ejecutar el
cmdlet y no puede cargar este archivo prependPath de formato como un módulo.

Muestra
Este archivo de formato muestra los siguientes elementos XML:

Elemento Name de la vista.

Elemento ViewSelectedBy que define qué objetos muestra la vista.

Elemento ListControl que define qué propiedad muestra la vista.

Elemento ListItem que define lo que se muestra en una fila de la vista de lista.

Elemento PropertyName que define qué propiedad se muestra.

Ejemplo
El xml siguiente define una vista de lista que muestra cuatro propiedades de
System.Serviceprocess.Servicecontroller? Objeto Displayproperty=Fullname. En cada fila,
se muestra el nombre de la propiedad seguido del valor de la propiedad .

XML

<Configuration>
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
</Configuration>

En el ejemplo siguiente se muestra Windows PowerShell muestra


System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname después de
cargar este archivo de formato.

PowerShell

Get-Service f*

Resultados

Name : Fax
DisplayName : Fax
Status : Stopped
ServiceType : Win32OwnProcess
Name : FCSAM
DisplayName : Microsoft Antimalware Service
Status : Running
ServiceType : Win32OwnProcess

Name : fdPHost
DisplayName : Function Discovery Provider Host
Status : Stopped
ServiceType : Win32ShareProcess

Name : FDResPub
DisplayName : Function Discovery Resource Publication
Status : Running
ServiceType : Win32ShareProcess

Name : FontCache
DisplayName : Windows Font Cache Service
Status : Running
ServiceType : Win32ShareProcess

Name : FontCache3.0.0.0
DisplayName : Windows Presentation Foundation Font Cache 3.0.0.0
Status : Stopped
ServiceType : Win32OwnProcess

Name : FSysAgent
DisplayName : Microsoft Forefront System Agent
Status : Running
ServiceType : Win32OwnProcess

Name : FwcAgent
DisplayName : Firewall Client Agent
Status : Running
ServiceType : Win32OwnProcess

Consulte también
Ejemplos de archivos de formato

Escritura de un archivo de formato de PowerShell


Vista de lista (Labels)
Artículo • 24/09/2021

En este ejemplo se muestra cómo implementar una vista de lista que muestra una
etiqueta personalizada para cada fila de la lista. Esta vista de lista muestra las
propiedades de System.Serviceprocess.Servicecontroller? Objeto
Displayproperty=Fullname devuelto por el cmdlet Get-Service. Para obtener más
información sobre los componentes de una vista de lista, vea Crear una vista de lista.

Cargar este archivo de formato


1. Copie el XML de la sección Ejemplo de este tema en un archivo de texto.

2. Guarde el archivo de texto. Asegúrese de agregar la format.ps1xml extensión al


archivo para identificarla como un archivo de formato.

3. Abra Windows PowerShell y ejecute el siguiente comando para cargar el archivo


de formato en la sesión actual: Update-formatdata -prependpath
PathToFormattingFile .

2 Advertencia

Este archivo de formato define la presentación de un objeto que ya está definido


por un Windows PowerShell de formato. Debe usar el parámetro al ejecutar el
cmdlet y no puede cargar este prependPath archivo de formato como un módulo.

Muestra
Este archivo de formato muestra los siguientes elementos XML:

Elemento Name de la vista.

Elemento ViewSelectedBy que define qué objetos muestra la vista.

Elemento ListControl que define qué propiedad muestra la vista.

Elemento ListItem que define lo que se muestra en una fila de la vista de lista.

Elemento Label que define lo que se muestra en una fila de la vista de lista.

Elemento PropertyName que define qué propiedad se muestra.


Ejemplo
El xml siguiente define una vista de lista que muestra una etiqueta personalizada en
cada fila. En este caso, la etiqueta incluye el nombre de propiedad con cada letra en
mayúsculas y la palabra "property". En cada fila, se muestra el nombre de la propiedad
seguido del valor de la propiedad .

XML

<Configuration>
<ViewDefinitions>
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<Label>NAME property</Label>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<Label>DISPLAYNAME property</Label>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<Label>STATUS property</Label>
<PropertyName>Status</PropertyName>
</ListItem>
<ListItem>
<Label>SERVICETYPE property</Label>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>

</ViewDefinitions>
</Configuration>

En el ejemplo siguiente se muestra Windows PowerShell muestra


System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname después de
cargar este archivo de formato.

PowerShell
Get-Service f*

Resultados

NAME property : Fax


DISPLAYNAME property : Fax
STATUS property : Stopped
SERVICETYPE property : Win32OwnProcess

NAME property : FCSAM


DISPLAYNAME property : Microsoft Antimalware Service
STATUS property : Running
SERVICETYPE property : Win32OwnProcess

NAME property : fdPHost


DISPLAYNAME property : Function Discovery Provider Host
STATUS property : Stopped
SERVICETYPE property : Win32ShareProcess

NAME property : FDResPub


DISPLAYNAME property : Function Discovery Resource Publication
STATUS property : Running
SERVICETYPE property : Win32ShareProcess

NAME property : FontCache


DISPLAYNAME property : Windows Font Cache Service
STATUS property : Running
SERVICETYPE property : Win32ShareProcess

NAME property : FontCache3.0.0.0


DISPLAYNAME property : Windows Presentation Foundation Font Cache 3.0.0.0
STATUS property : Stopped
SERVICETYPE property : Win32OwnProcess

NAME property : FSysAgent


DISPLAYNAME property : Microsoft Forefront System Agent
STATUS property : Running
SERVICETYPE property : Win32OwnProcess

NAME property : FwcAgent


DISPLAYNAME property : Firewall Client Agent
STATUS property : Running
SERVICETYPE property : Win32OwnProcess

Consulte también
Ejemplos de archivos de formato

Escritura de un archivo de formato de PowerShell


Vista de lista (GroupBy)
Artículo • 27/09/2021

En este ejemplo se muestra cómo implementar una vista de lista que separa las filas de
la lista en grupos. Esta vista de lista muestra las propiedades de
System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname devueltos
por el cmdlet Get-Service. Para obtener más información sobre los componentes de una
vista de lista, vea Crear una vista de lista.

Cargar este archivo de formato


1. Copie el XML de la sección Ejemplo de este tema en un archivo de texto.

2. Guarde el archivo de texto. Asegúrese de agregar la format.ps1xml extensión al


archivo para identificarla como un archivo de formato.

3. Abra Windows PowerShell y ejecute el siguiente comando para cargar el archivo


de formato en la sesión actual: Update-formatdata -prependpath
PathToFormattingFile .

2 Advertencia

Este archivo de formato define la presentación de un objeto que ya está definido


por un Windows PowerShell de formato. Debe usar el parámetro al ejecutar el
cmdlet y no puede cargar este archivo prependPath de formato como un módulo.

Muestra
Este archivo de formato muestra los siguientes elementos XML:

Elemento Name de la vista.

Elemento ViewSelectedBy que define qué objetos muestra la vista.

Elemento GroupBy que define cómo se muestra un nuevo grupo de objetos.

Elemento ListControl que define qué propiedad muestra la vista.

Elemento ListItem que define lo que se muestra en una fila de la vista de lista.

Elemento PropertyName que define qué propiedad se muestra.


Ejemplo
El código XML siguiente define una vista de lista que inicia un nuevo grupo cada vez
que cambia el valor de la propiedad System.Serviceprocess.Servicecontroller.Status.
Cuando se inicia cada grupo, se muestra una etiqueta personalizada que incluye el
nuevo valor de la propiedad .

XML

<Configuration>
<ViewDefinitions>
<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<GroupBy>
<PropertyName>Status</PropertyName>
<Label>New Service Status</Label>
</GroupBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>
<ListItem>
<PropertyName>Name</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DisplayName</PropertyName>
</ListItem>
<ListItem>
<PropertyName>ServiceType</PropertyName>
</ListItem>
</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>
</ViewDefinitions>
</Configuration>

En el ejemplo siguiente se muestra Windows PowerShell muestra


System.Serviceprocess.Servicecontroller? Objetos Displayproperty=Fullname después de
cargar este archivo de formato. Las líneas en blanco agregadas antes y después de la
etiqueta de grupo se agregan automáticamente mediante Windows PowerShell.

PowerShell

Get-Service f*
Resultados

New Service Status: Stopped

Name : Fax
DisplayName : Fax
ServiceType : Win32OwnProcess

New Service Status: Running

Name : FCSAM
DisplayName : Microsoft Antimalware Service
ServiceType : Win32OwnProcess

New Service Status: Stopped

Name : fdPHost
DisplayName : Function Discovery Provider Host
ServiceType : Win32ShareProcess

New Service Status: Running

Name : FDResPub
DisplayName : Function Discovery Resource Publication
ServiceType : Win32ShareProcess

Name : FontCache
DisplayName : Windows Font Cache Service
ServiceType : Win32ShareProcess

New Service Status: Stopped

Name : FontCache3.0.0.0
DisplayName : Windows Presentation Foundation Font Cache 3.0.0.0
ServiceType : Win32OwnProcess

New Service Status: Running

Name : FSysAgent
DisplayName : Microsoft Forefront System Agent
ServiceType : Win32OwnProcess

Name : FwcAgent
DisplayName : Firewall Client Agent
ServiceType : Win32OwnProcess

Consulte también
Ejemplos de archivos de formato

Escritura de un archivo de formato de PowerShell


Referencia XML del esquema de
formato
Artículo • 24/09/2021

En los temas de esta sección se describen los elementos XML que se usan al dar formato
a los archivos (archivos Format.ps1xml). Los archivos de formato definen cómo se
muestra el objeto .NET; no cambian el propio objeto.

En esta sección
Elemento Alignment para TableColumnHeader for TableControl (formato) Define cómo
se muestran los datos de un encabezado de columna.

Elemento Alignment para TableColumnItem for TableControl (formato) Define cómo se


muestran los datos de la fila.

Elemento AutoSize para TableControl (formato) Especifica si el tamaño de columna y el


número de columnas se ajustan en función del tamaño de los datos.

Elemento Autosize para WideControl (formato) Especifica si el tamaño de columna y el


número de columnas se ajustan en función del tamaño de los datos.

Elemento ColumnNumber para WideControl (formato) Especifica el número de


columnas que se muestran en la vista ancha.

Elemento Configuration (formato) Representa el elemento de nivel superior del archivo


de formato.

Elemento Control para Controls for Configuration (formato) Define un control común
que pueden usar todas las vistas del archivo de formato y el nombre que se usa para
hacer referencia al control.

Elemento Control para Controls for View (formato) Define un control que puede usar la
vista y el nombre que se usa para hacer referencia al control.

Elemento Controls para Configuration (formato) Define los controles comunes que
pueden usar todas las vistas del archivo de formato.

Elemento Controls para View (formato) Define los controles de vista que puede usar una
vista específica.
Elemento CustomControl para Control for Configuration (formato) Define un control .
Este elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Elemento CustomControl para Control for Controls for View (formato) Define un control
utilizado por la vista.

Elemento CustomControl para GroupBy (formato) Define el control personalizado que


muestra el nuevo grupo.

Elemento CustomControl (formato) Define un formato de control personalizado para la


vista.

Elemento CustomControlName para ExpressionBinding for Controls for Configuration


(formato) Especifica el nombre de un control común. Este elemento se usa al definir un
control común que pueden usar todas las vistas del archivo de formato.

Elemento CustomControlName para ExpressionBindine for Controls for View (formato)


Especifica el nombre de un control común o un control de vista. Este elemento se usa al
definir controles que una vista puede usar.

Elemento CustomControlName de GroupBy (formato) Especifica el nombre de un


control personalizado que se usa para mostrar el nuevo grupo. Este elemento se usa al
definir una tabla, una lista, una vista de control amplia o personalizada.

Elemento CustomEntry para CustomControl for Controls for Configuration (formato)


Proporciona una definición del control común. Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Elemento CustomEntry para CustomEntries for Controls for View (formato) Proporciona
una definición del control . Este elemento se usa al definir controles que una vista puede
usar.

Elemento CustomEntry para CustomEntries for View (formato) Proporciona una


definición de la vista de control personalizada.

Elemento CustomEntry para CustomControl for GroupBy (formato) Proporciona una


definición del control . Este elemento se usa al definir cómo se muestra un nuevo grupo
de objetos.

Elemento CustomEntries para CustomControl for Configuration (formato) Proporciona


las definiciones de un control común. Este elemento se usa al definir un control común
que pueden usar todas las vistas del archivo de formato.
Elemento CustomEntries para CustomControl for Controls for View (formato)
Proporciona las definiciones del control. Este elemento se usa al definir controles que
una vista puede usar.

Elemento CustomEntries para CustomControl for GroupBy (formato) Proporciona las


definiciones del control. Este elemento se usa al definir cómo se muestra un nuevo
grupo de objetos.

Elemento CustomEntries para CustomControl for View (formato) Proporciona las


definiciones de la vista de control personalizada. La vista de control personalizada debe
especificar una o varias definiciones.

Elemento CustomItem para CustomEntry for Controls for Configuration Define qué
datos muestra el control y cómo se muestran. Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Elemento CustomItem para CustomEntry for Controls for View (formato) Define qué
datos muestra el control y cómo se muestran. Este elemento se usa al definir controles
que una vista puede usar.

Elemento CustomItem para CustomEntry for View (formato) Define qué datos muestra la
vista de control personalizada y cómo se muestran. Este elemento se usa al definir una
vista de control personalizada.

Elemento CustomItem para CustomEntry for GroupBy (formato) Define qué datos
muestra la vista de control personalizada y cómo se muestran. Este elemento se usa al
definir cómo se muestra un nuevo grupo de objetos.

Elemento DefaultSettings (formato) Define la configuración común que se aplica a todas


las vistas del archivo de formato. La configuración común incluye mostrar errores,
encapsular texto en tablas, definir cómo se expanden las colecciones, etc.

Elemento DisplayError (formato) Especifica que la cadena #ERR se muestra cuando se


produce un error que muestra un fragmento de datos.

Elemento EntrySelectedBy para CustomEntry for Controls for Configuration (formato)


Define los tipos de .NET que usan la definición del control común o la condición que
debe existir para que se use este control. Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Elemento EntrySelectedBy para CustomEntry for Controls for View (formato) Define los
tipos de .NET que usan esta definición de control o la condición que debe existir para
que se use esta definición. Este elemento se usa al definir controles que una vista puede
usar.
Elemento EntrySelectedBy para CustomEntry for View (formato) Define los tipos de .NET
que usan esta entrada personalizada o la condición que debe existir para que se use
esta entrada.

Elemento EntrySelectedBy para EnumerableExpansion (formato) Define los tipos de .NET


que usan esta definición o la condición que debe existir para que se use esta definición.

Elemento EntrySelectedBy para CustomEntry for GroupBy (formato) Define los tipos de
.NET que usan esta definición de control o la condición que debe existir para que se use
esta definición. Este elemento se usa al definir cómo se muestra un nuevo grupo de
objetos.

Elemento EntrySelectedBy para ListEntry for ListControl (formato) Define los tipos de
.NET que usan esta definición de vista de lista o la condición que debe existir para que
se use esta definición. En la mayoría de los casos, solo se necesita una definición para
una vista de lista. Sin embargo, puede proporcionar varias definiciones para la vista de
lista si desea usar la misma vista de lista para mostrar datos diferentes para distintos
objetos.

Elemento EntrySelectedBy para TableRowEntry (formato) Define los tipos de .NET cuyos
valores de propiedad se muestran en la fila.

Elemento EntrySelectedBy para WideEntry (formato) Define los tipos de .NET que usan
esta definición de la vista ancha o la condición que debe existir para que se use esta
definición.

Elemento EnumerableExpansion (formato) Define cómo se expanden objetos de


colección de .NET específicos cuando se muestran en una vista.

Elemento EnumerableExpansions (formato) Define cómo se expanden los objetos de


colección de .NET cuando se muestran en una vista.

Elemento EnumerateCollection para ExpressionBinding for Controls for Configuration


(formato) Se especifica que el control muestra los elementos de las colecciones. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Elemento EnumerateCollection para ExpressionBinding for Controls for View (formato)


Se especifica que se muestran los elementos de las colecciones. Este elemento se usa al
definir controles que una vista puede usar.

Elemento EnumerateCollection para el enlace de expresiones para CustomControl for


View (formato) Especifica que se muestran los elementos de las colecciones. Este
elemento se usa al definir una vista de control personalizada.
Elemento EnumerateCollection para ExpressionBinding for GroupBy (formato) Especifica
que se muestran los elementos de las colecciones. Este elemento se usa al definir cómo
se muestra un nuevo grupo de objetos.

Elemento Expand (formato) Especifica cómo se expande el objeto de colección para esta
definición.

Elemento ExpressionBinding para CustomItem for Controls for Configuration (formato)


Define los datos que muestra el control . Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Elemento ExpressionBinding para CustomItem for Controls for View (formato) Define los
datos que muestra el control . Este elemento se usa al definir controles que una vista
puede usar.

Elemento ExpressionBinding para CustomItem for CustomControl for View (formato)


Define los datos que muestra el control . Este elemento se usa al definir una vista de
control personalizada.

Elemento ExpressionBinding para CustomItem for GroupBy (formato) Define los datos
que muestra el control . Este elemento se usa al definir cómo se muestra un nuevo
grupo de objetos.

Elemento FirstLineHanging para Frame for Controls for Configuration (formato)


Especifica cuántos caracteres se desplaza la primera línea de datos a la izquierda. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Elemento FirstLineHanging del marco de controles de vista (formato) Especifica cuántos


caracteres se desplaza la primera línea de datos a la izquierda. Este elemento se usa al
definir controles que una vista puede usar.

Elemento FirstLineHanging para Frame for CustomControl for View (formato) Especifica
cuántos caracteres se desplaza la primera línea de datos a la izquierda. Este elemento se
usa al definir una vista de control personalizada.

Elemento FirstLineHanging para Frame for GroupBy (formato) Especifica cuántos


caracteres se desplaza la primera línea de datos a la izquierda. Este elemento se usa al
definir cómo se muestra un nuevo grupo de objetos.

Elemento FirstLineIndent para Frame for Controls for Configuration (formato) Especifica
cuántos caracteres se desplaza la primera línea de datos a la derecha. Este elemento se
usa al definir un control común que pueden usar todas las vistas del archivo de formato.
Elemento FirstLineIndent del marco de controles de vista (formato) Especifica cuántos
caracteres se desplaza la primera línea de datos a la derecha. Este elemento se usa al
definir controles que una vista puede usar.

Elemento FirstLineIndent Especifica cuántos caracteres se desplaza la primera línea de


datos a la derecha. Este elemento se usa al definir una vista de control personalizada.

Elemento FirstLineIndent para Frame for GroupBy (formato) Especifica cuántos


caracteres se desplaza la primera línea de datos a la derecha. Este elemento se usa al
definir cómo se muestra un nuevo grupo de objetos.

Elemento FormatString para ListItem (formato) Especifica un patrón de formato que


define cómo se muestra la propiedad o el valor del script.

Elemento FormatString para TableColumnItem (formato) Especifica un patrón de


formato que define cómo se muestra la propiedad o el valor de script de la tabla.

Elemento FormatString para WideItem for WideControl (formato) Especifica un patrón


de formato que define cómo se muestra la propiedad o el valor del script en la vista.

Elemento Frame para CustomItem for Controls for Configuration (formato) Define cómo
se muestran los datos, como desplazar los datos a la izquierda o a la derecha. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Elemento Frame para CustomItem for Controls for View (formato) Define cómo se
muestran los datos, como desplazar los datos a la izquierda o a la derecha. Este
elemento se usa al definir controles que una vista puede usar.

Elemento Frame para CustomItem for CustomControl for View (formato) Define cómo se
muestran los datos, como desplazar los datos a la izquierda o a la derecha. Este
elemento se usa al definir una vista de control personalizada.

Elemento Frame para CustomItem for GroupBy (formato) Define cómo se muestran los
datos, como desplazar los datos a la izquierda o a la derecha. Este elemento se usa al
definir cómo se muestra un nuevo grupo de objetos.

Elemento GroupBy para View (formato) Define cómo Windows PowerShell muestra un
nuevo grupo de objetos.

Elemento HideTableHeaders (formato) Especifica que no se muestran los encabezados


de la tabla.

Elemento ItemSelectionCondition para ExpressionBinding for Controls for Configuration


(formato) Define la condición que debe existir para que se utilice este control. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Elemento ItemSelectionCondition de ExpressionBinding for Controls for View (formato)


Define la condición que debe existir para que se utilice este control. Este elemento se
usa al definir controles que una vista puede usar.

Elemento ItemSelectionCondition para el enlace de expresiones para CustomControl for


View (formato) Define la condición que debe existir para que se utilice este control. No
hay ningún límite en el número de condiciones de selección que se pueden especificar
para un elemento de control. Este elemento se usa al definir una vista de control
personalizada.

Elemento ItemSelectionCondition para ExpressionBinding for GroupBy (formato) Define


la condición que debe existir para que se utilice este control. No hay ningún límite en el
número de condiciones de selección que se pueden especificar para un elemento de
control. Este elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Elemento ItemSelectionCondition para ListItem (formato) Define la condición que debe


existir para que se utilice este elemento de lista.

Elemento Label para ListItem for ListControl(Format) Especifica la etiqueta para la


propiedad o el valor de script de la fila.

Elemento Label para GroupBy (formato) Especifica una etiqueta que se muestra cuando
se encuentra un nuevo grupo.

Elemento Label para TableColumnHeader (formato) Define la etiqueta que se muestra


en la parte superior de una columna.

Elemento LeftIndent para Frame for Controls for Configuration (formato) Especifica
cuántos caracteres se desplazan los datos del margen izquierdo. Este elemento se usa al
definir un control común que pueden usar todas las vistas del archivo de formato.

Elemento LeftIndent del marco de controles de vista (formato) Especifica cuántos


caracteres se desplazan los datos del margen izquierdo. Este elemento se usa al definir
controles que una vista puede usar.

Elemento LeftIndent para Frame for CustomControl for View (formato) Especifica
cuántos caracteres se desplazan los datos del margen izquierdo. Este elemento se usa al
definir una vista de control personalizada.

Elemento LeftIndent para Frame for GroupBy (formato) Especifica cuántos caracteres se
desplazan los datos del margen izquierdo. Este elemento se usa al definir cómo se
muestra un nuevo grupo de objetos.
Elemento ListControl (formato) Define un formato de lista para la vista.

Elemento ListEntry (formato) Proporciona una definición de la vista de lista.

Elemento ListEntries (formato) Define cómo se muestran las filas de la vista de lista.

Elemento ListItem (formato) Define la propiedad o script cuyo valor se muestra en una
fila de la vista de lista.

Elemento ListItems (formato) Define las propiedades y los scripts que se muestran en la
vista de lista.

Elemento Name para Control for Controls for Configuration (formato) Especifica el
nombre del control. Este elemento se usa al definir un control común que pueden usar
todas las vistas del archivo de formato.

Elemento Name para SelectionSet (formato) Especifica el nombre utilizado para hacer
referencia al conjunto de selección.

Elemento Name para View (formato) Especifica el nombre que se usa para identificar la
vista.

Elemento NewLine para CustomItem for Controls for Configuration (formato) Agrega
una línea en blanco a la presentación del control. Este elemento se usa al definir un
control común que pueden usar todas las vistas del archivo de formato.

Elemento NewLine para CustomItem for Controls for View (formato) Agrega una línea
en blanco a la presentación del control. Este elemento se usa al definir controles que
una vista puede usar.

Elemento NewLine para CustomItem for CustomControl for View (formato) Agrega una
línea en blanco a la presentación del control. Este elemento se usa al definir una vista de
control personalizada.

Elemento NewLine para CustomItem for GroupBy (formato) Agrega una línea en blanco
a la presentación del control. Este elemento se usa al definir cómo se muestra un nuevo
grupo de objetos.

Elemento PropertyName para ExpressionBinding for Controls for Configuration


(formato) Especifica la propiedad .NET cuyo valor muestra el control común. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Elemento PropertyName para ExpressionBinding for Controls for View (formato)


Especifica la propiedad .NET cuyo valor muestra el control . Este elemento se usa al
definir controles que una vista puede usar.

Elemento PropertyName para ExpressionBinding for CustomControl for View (formato)


Especifica la propiedad .NET cuyo valor muestra el control . Este elemento se usa al
definir una vista de control personalizada

Elemento PropertyName para ExpressionBinding para GroupBy (formato) Especifica la


propiedad .NET cuyo valor muestra el control . Este elemento se usa al definir cómo se
muestra un nuevo grupo de objetos.

Elemento PropertyName para GroupBy (formato) Especifica la propiedad .NET que inicia
un nuevo grupo cada vez que cambia su valor.

Elemento PropertyName para ItemSelectionCondition for Controls for Configuration


(formato) Especifica la propiedad de .NET que desencadena la condición. Cuando esta
propiedad está presente o cuando se evalúa como true , se cumple la condición y se
usa el control . Este elemento se usa al definir un control común que pueden usar todas
las vistas del archivo de formato.

Elemento PropertyName para ItemSelectionCondition for Controls for View (formato)


Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad
está presente o cuando se evalúa como true , se cumple la condición y se usa el control
. Este elemento se usa al definir controles que una vista puede usar.

Elemento PropertyName para ItemSelectionCondition for CustomControl for View


(Formato Especifica la propiedad .NET que desencadena la condición. Cuando esta
propiedad está presente o cuando se evalúa como true , se cumple la condición y se
usa el control . Este elemento se usa al definir una vista de control personalizada.

Elemento PropertyName para ItemSelectionCondition for GroupBy (formato) Especifica


la propiedad de .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa el control .
Este elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Elemento PropertyName para ItemSelectionCondition for ListItem (formato) Especifica la


propiedad de .NET que desencadena la condición. Cuando esta propiedad está presente
o cuando se evalúa como true , se cumple la condición y se usa la vista. Este elemento
se usa al definir una vista de lista.

Elemento PropertyName para ListItem for ListControl (formato) Especifica la propiedad


.NET cuyo valor se muestra en la lista.

Elemento PropertyName para SelectionCondition for EntrySelectedBy for ListEntry


(formato) Especifica la propiedad de .NET que desencadena la condición. Cuando esta
propiedad está presente o cuando se evalúa como true , se cumple la condición y se
usa la entrada . Este elemento se usa al definir un control común que pueden usar todas
las vistas del archivo de formato.

Elemento PropertyName para SelectionCondition for Controls for View (formato)


Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad
está presente o cuando se evalúa como true , se cumple la condición y se usa la
entrada . Este elemento se usa al definir controles que una vista puede usar.

Elemento PropertyName para SelectionCondition for CustomControl for View (formato)


Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad
está presente o cuando se evalúa como true , se cumple la condición y se usa la
definición. Este elemento se usa al definir una vista de control personalizada.

Elemento PropertyName para SelectionCondition for EntrySelectedBy for


EnumerableExpansion (formato) Especifica la propiedad de .NET que desencadena la
condición. Cuando esta propiedad está presente o cuando se evalúa como true , se
cumple la condición y se usa la definición.

Elemento PropertyName para SelectionCondition for GroupBy (formato) Especifica la


propiedad de .NET que desencadena la condición. Cuando esta propiedad está presente
o cuando se evalúa como true , se cumple la condición y se usa la definición. Este
elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Elemento PropertyName para SelectionCondition for EntrySelectedBy for ListEntry


(formato) Especifica la propiedad de .NET que desencadena la condición. Cuando esta
propiedad está presente o cuando se evalúa como , se cumple la condición y se usa la
entrada true de lista.

Elemento PropertyName para SelectionCondition for EntrySelectedBy for TableRowEntry


(formato) Especifica la propiedad de .NET que desencadena la condición. Cuando esta
propiedad está presente o cuando se evalúa como , se cumple la condición y true se
usa la entrada de tabla.

Elemento PropertyName para SelectionCondition for EntrySelectedBy for WideEntry


(formato) Especifica la propiedad de .NET que desencadena la condición. Cuando esta
propiedad está presente o cuando se evalúa como true , se cumple la condición y se
usa la definición.

Elemento PropertyName para TableColumnItem (formato) Especifica la propiedad cuyo


valor se muestra en la columna de la fila.
Elemento PropertyName para WideItem (formato) Especifica la propiedad del objeto
cuyo valor se muestra en la vista ancha.

Elemento RightIndent para Frame for Controls for Configuration (formato) Especifica
cuántos caracteres se desplazan los datos del margen derecho. Este elemento se usa al
definir un control común que pueden usar todas las vistas del archivo de formato.

Elemento RightIndent del marco de controles de vista (formato) Especifica cuántos


caracteres se desplazan los datos del margen derecho. Este elemento se usa al definir
controles que una vista puede usar.

Elemento RightIndent Especifica cuántos caracteres se desplazan los datos del margen
derecho. Este elemento se usa al definir una vista de control personalizada.

Elemento RightIndent para Frame for GroupBy (formato) Especifica cuántos caracteres
se desplazan los datos del margen derecho. Este elemento se usa al definir cómo se
muestra un nuevo grupo de objetos.

Elemento ScriptBlock para ExpressionBinding for Controls for Configuration (formato)


Especifica el script cuyo valor muestra el control común. Este elemento se usa al definir
un control común que pueden usar todas las vistas del archivo de formato.

Elemento ScriptBlock para ExpressionBinding for Controls for View (formato) Especifica
el script cuyo valor muestra el control . Este elemento se usa al definir controles que una
vista puede usar.

Elemento ScriptBlock para ExpressionBinding for CustomCustomControl for View


(formato) Especifica el script cuyo valor muestra el control . Este elemento se usa al
definir una vista de control personalizada.

Elemento ScriptBlock para ExpressionBinding for GroupBy (formato) Especifica el script


cuyo valor muestra el control . Este elemento se usa al definir cómo se muestra un
nuevo grupo de objetos.

Elemento ScriptBlock para GroupBy (formato) Especifica el script que inicia un nuevo
grupo cada vez que cambia su valor.

Elemento ScriptBlock para ItemSelectionCondition for Controls for Configuration


(formato) Especifica el script que desencadena la condición. Cuando este script se
evalúa como true , se cumple la condición y se usa el control . Este elemento se usa al
definir un control común que pueden usar todas las vistas del archivo de formato.

Elemento ScriptBlock para ItemSelectionCondition for Controls for View (formato)


Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa el control . Este elemento se usa al definir

controles que una vista puede usar.

Elemento ScriptBlock para ItemSelectionCondition for CustomControl for View (formato)


Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa el control . Este elemento se usa al definir una

vista de control personalizada.

Elemento ScriptBlock para ItemSelectionCondition for GroupBy (formato) Especifica el


script que desencadena la condición. Cuando este script se evalúa como true , se
cumple la condición y se usa el control . Este elemento se usa al definir cómo se muestra
un nuevo grupo de objetos.

Elemento ScriptBlock para ItemSelectionCondition for ListControl (formato) Especifica el


script que desencadena la condición. Cuando este script se evalúa como true , se
cumple la condición y se usa el elemento de lista. Este elemento se usa al definir una
vista de lista.

Elemento ScriptBlock para ListItem (formato) Especifica el script cuyo valor se muestra
en la fila de la lista.

Elemento ScriptBlock para SelectionCondition for Controls for Configuration (formato)


Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la definición. Este elemento se usa al definir un
control común que pueden usar todas las vistas del archivo de formato.

Elemento ScriptBlock para SelectionCondition for Controls for View (formato) Especifica
el script que desencadena la condición. Cuando este script se evalúa como true , se
cumple la condición y se usa la definición. Este elemento se usa al definir controles que
una vista puede usar.

Elemento ScriptBlock para SelectionCondition for CustomControl for View (formato)


Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la definición. Este elemento se usa al definir una

vista de control personalizada.

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for


EnumerableExpansion (formato) Especifica el script que desencadena la condición.

Elemento ScriptBlock para SelectionCondition for GroupBy (formato) Especifica el script


que desencadena la condición. Cuando este script se evalúa como true , se cumple la
condición y se usa la definición. Este elemento se usa al definir cómo se muestra un
nuevo grupo de objetos.
Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for ListEntry (formato)
Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la entrada de lista.

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for TableRowEntry


(formato) Especifica el bloque de script que desencadena la condición. Cuando este
script se evalúa como true , se cumple la condición y se usa la entrada de tabla.

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for WideEntry


(formato) Especifica el script que desencadena la condición. Cuando este script se
evalúa como true , se cumple la condición y se usa la definición de entrada ancha.

Elemento ScriptBlock para TableColumnItem (formato) Especifica el script cuyo valor se


muestra en la columna de la fila.

Elemento ScriptBlock para WideItem (formato) Especifica el script cuyo valor se muestra
en la vista ancha.

Elemento SelectionCondition para EntrySelectedBy for CustomEntry for Configuration


(formato) Define una condición que debe existir para que se utilice una definición de
control común. Este elemento se usa al definir un control común que pueden usar todas
las vistas del archivo de formato.

Elemento SelectionCondition para EntrySelectedBy for Controls for View (formato)


Define una condición que debe existir para que se utilice la definición de control. Este
elemento se usa al definir controles que una vista puede usar.

Elemento SelectionCondition para EntrySelectedBy for CustomControl for View


(formato) Define una condición que debe existir para que se utilice una definición de
control. Este elemento se usa al definir una vista de control personalizada.

Elemento SelectionCondition para EntrySelectedBy for EnumerableExpansion (formato)


Define la condición que debe existir para expandir los objetos de colección de esta
definición.

Elemento SelectionCondition para EntrySelectedBy for GroupBy (formato) Define una


condición que debe existir para que se utilice una definición de control. Este elemento
se usa al definir cómo se muestra un nuevo grupo de objetos.

Elemento SelectionCondition para EntrySelectedBy for ListEntry (formato) Define la


condición que debe existir para usar esta definición de la vista de lista. No hay ningún
límite en el número de condiciones de selección que se pueden especificar para una
definición de lista.
Elemento SelectionCondition para EntrySelectedBy for TableRowEntry (formato) Define
la condición que debe existir para usar para esta definición de la vista de tabla. No hay
ningún límite en el número de condiciones de selección que se pueden especificar para
una definición de tabla.

Elemento SelectionCondition para EntrySelectedBy for WideEntry (formato) Define la


condición que debe existir para que se utilice esta definición. No hay ningún límite en el
número de condiciones de selección que se pueden especificar para una definición de
entrada amplia.

Elemento SelectionSet (formato) Define un conjunto de objetos .NET a los que se puede
hacer referencia mediante el nombre del conjunto.

Elemento SelectionSetName para EntrySelectedBy for Controls for Configuration


(formato) Especifica un conjunto de tipos de .NET que usan esta definición del control.
Este elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Elemento SelectionSetName para EntrySelectedBy for Controls for View (formato)


Especifica un conjunto de tipos de .NET que usan esta definición del control. Este
elemento se usa al definir controles que una vista puede usar.

Elemento SelectionSetName para EntrySelectedBy for CustomEntry (formato) Especifica


un conjunto de objetos .NET para la entrada de lista. No hay ningún límite en el número
de conjuntos de selección que se pueden especificar para una entrada.

Elemento SelectionSetName para EntrySelectedBy for EnumerableExpansion (formato)


Especifica el conjunto de tipos de .NET que se expanden mediante esta definición.

Elemento SelectionSetName para EntrySelectedBy for GroupBy (formato) Especifica un


conjunto de objetos .NET para la entrada de lista. No hay ningún límite en el número de
conjuntos de selección que se pueden especificar para una entrada. Este elemento se
usa al definir cómo se muestra un nuevo grupo de objetos.

Elemento SelectionSetName para EntrySelectedBy for ListEntry (formato) Especifica un


conjunto de objetos .NET para la entrada de lista. No hay ningún límite en el número de
conjuntos de selección que se pueden especificar para una entrada.

Elemento SelectionSetName para EntrySelectedBy for TableRowEntry (formato)


Especifica un conjunto de tipos de .NET que usan esta entrada de la vista de tabla. No
hay ningún límite en el número de conjuntos de selección que se pueden especificar
para una entrada.
Elemento SelectionSetName para EntrySelectedBy for WideEntry (formato) Especifica un
conjunto de objetos .NET para la definición. La definición se usa siempre que se muestra
uno de estos objetos.

Elemento SelectionSetName para SelectionCondition for Controls for Configuration


(formato) Especifica el conjunto de tipos de .NET que desencadenan la condición.
Cuando alguno de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante este control. Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Elemento SelectionSetName para SelectionCondition for Controls for View (formato)


Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando
cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante este control. Este elemento se usa al definir controles que
una vista puede usar.

Elemento EntrySelectedBy para CustomEntry for View (formato) Especifica el conjunto


de tipos de .NET que desencadenan la condición. Cuando cualquiera de los tipos de este
conjunto está presente, se cumple la condición y el objeto se muestra mediante este
control. Este elemento se usa al definir una vista de control personalizada.

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


EnumerableExpansion (formato) Especifica el conjunto de tipos de .NET que
desencadenan la condición. Cuando cualquiera de los tipos de este conjunto está
presente, se cumple la condición.

Elemento SelectionSetName para SelectionCondition for GroupBy (formato) Especifica el


conjunto de tipos de .NET que desencadenan la condición. Cuando alguno de los tipos
de este conjunto está presente, se cumple la condición y el objeto se muestra mediante
este control. Este elemento se usa al definir cómo se muestra un nuevo grupo de
objetos.

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for ListEntry


(formato) Especifica el conjunto de tipos de .NET que desencadenan la condición.
Cuando cualquiera de los tipos de este conjunto está presente, se cumple la condición y
el objeto se muestra mediante esta definición de la vista de lista.

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


TableRowEntry (formato) Especifica el conjunto de tipos de .NET que desencadenan la
condición. Cuando cualquiera de los tipos de este conjunto está presente, se cumple la
condición y el objeto se muestra mediante esta definición de la vista de tabla.
Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for WideEntry
(formato) Especifica el conjunto de tipos de .NET que desencadenan la condición.
Cuando cualquiera de los tipos de este conjunto está presente, se cumple la condición y
el objeto se muestra mediante esta definición de la vista ancha.

Elemento SelectionSetName para ViewSelectedBy (formato) Especifica un conjunto de


objetos .NET que la vista muestra.

Elemento SelectionSets (formato) Define los conjuntos de objetos .NET que pueden usar
las vistas de formato individuales.

Elemento ShowError (formato) Especifica que se muestra el registro de errores completo


cuando se produce un error al mostrar un fragmento de datos.

Elemento TableColumnHeader para TableHeaders for TableControl (formato) Define la


etiqueta, el ancho de la columna y la alineación de la etiqueta para una columna de la
tabla.

Elemento TableColumnItem (formato) Define la propiedad o script cuyo valor se muestra


en la columna de la fila.

Elemento TableColumnItems (formato) Define las propiedades o scripts cuyos valores se


muestran en la fila.

Elemento TableControl (formato) Define un formato de tabla para una vista.

Elemento TableHeaders (formato) Define los encabezados de las columnas de una tabla.

Elemento TableRowEntries (formato) Define las filas de la tabla.

Elemento TableRowEntry (formato) Define los datos que se muestran en una fila de la
tabla.

Elemento Text para CustomItem for Controls for Configuration (formato) Especifica el
texto que se agrega a los datos que muestra el control, como una etiqueta, corchetes
para incluir los datos y espacios para aplicar sangría a los datos. Este elemento se usa al
definir un control común que pueden usar todas las vistas del archivo de formato.

Elemento Text para CustomItem for Controls for View (formato) Especifica el texto que
se agrega a los datos que muestra el control, como una etiqueta, corchetes para incluir
los datos y espacios para aplicar sangría a los datos. Este elemento se usa al definir
controles que una vista puede usar.

Elemento Text para CustomItem (formato) Especifica el texto que se agrega a los datos
que muestra el control, como una etiqueta, corchetes para incluir los datos y espacios
para aplicar sangría a los datos. Este elemento se usa al definir una vista de control
personalizada.

Elemento Text para CustomItem for GroupBy (formato) Especifica el texto que se agrega
a los datos que muestra el control, como una etiqueta, corchetes para incluir los datos y
espacios para aplicar sangría a los datos. Este elemento se usa al definir cómo se
muestra un nuevo grupo de objetos.

Elemento TypeName para EntrySelectedBy for Controls for Configuration (formato)


Especifica un tipo de .NET que usa esta definición del control. Este elemento se usa al
definir un control común que pueden usar todas las vistas del archivo de formato.

Elemento TypeName para EntrySelectedBy for Controls for View (formato) Especifica un
tipo de .NET que usa esta definición del control. Este elemento se usa al definir
controles que una vista puede usar.

Elemento TypeName para EntrySelectedBy for CustomEntry for View (formato) Especifica
un tipo de .NET que usa esta definición de la vista de control personalizada. No hay
ningún límite en el número de tipos que se pueden especificar para una definición.

Elemento TypeName para EntrySelectedBy for EnumerableExpansion (formato)


Especifica un tipo de .NET que se expande mediante esta definición. Este elemento se
usa al definir una configuración predeterminada.

Elemento TypeName para EntrySelectedBy for GroupBy (formato) Especifica un tipo de


.NET que usa esta definición del control personalizado. Este elemento se usa al definir
cómo se muestra un nuevo grupo de objetos.

Elemento TypeName para EntrySelectedBy for ListControl (formato) Especifica un tipo de


.NET que usa esta entrada de la vista de lista. No hay ningún límite en el número de
tipos que se pueden especificar para una entrada de lista.

Elemento TypeName para EntrySelectedBy for TableRowEntry (formato) Especifica un


tipo de .NET que usa esta entrada de la vista de tabla. No hay ningún límite en el
número de tipos que se pueden especificar para una entrada de tabla.

Elemento TypeName para EntrySelectedBy for WideEntry (formato) Especifica un tipo de


.NET para la definición. La definición se usa siempre que se muestra este objeto.

Elemento TypeName para SelectionCondition for Controls for Configuration (formato)


Especifica un tipo de .NET que desencadena la condición. Este elemento se usa al definir
un control común que pueden usar todas las vistas del archivo de formato.

Elemento TypeName para SelectionCondition for Controls for View (formato) Especifica
un tipo de .NET que desencadena la condición. Este elemento se usa al definir controles
que una vista puede usar.

Elemento TypeName para SelectionCondition for CustomControl for View (formato)


Especifica un tipo de .NET que desencadena la condición. Este elemento se usa al definir
una vista de control personalizada.

Elemento TypeName para SelectionCondition for EntrySelectedBy for


EnumerableExpansion (formato) Especifica un tipo de .NET que desencadena la
condición.

Elemento TypeName para SelectionCondition for GroupBy (formato) Especifica un tipo


de .NET que desencadena la condición. Este elemento se usa al definir cómo se muestra
un nuevo grupo de objetos.

Elemento TypeName para SelectionCondition for EntrySelectedBy for ListControl


(formato) Especifica un tipo de .NET que desencadena la condición. Cuando este tipo
está presente, se usa la entrada de lista.

Elemento TypeName para SelectionCondition for EntrySelectedBy for TableRowEntry


(formato) Especifica un tipo de .NET que desencadena la condición. Cuando este tipo
está presente, se cumple la condición y se usa la fila de tabla.

Elemento TypeName para SelectionCondition for EntrySelectedBy for WideEntry


(formato) Especifica un tipo de .NET que desencadena la condición. Cuando este tipo
está presente, se usa la definición.

Elemento TypeName para tipos (formato) Especifica el tipo de .NET de un objeto que
pertenece al conjunto de selección.

Elemento TypeName para ViewSelectedBy (formato) Especifica un objeto .NET que se


muestra en la vista.

Elemento Types (formato) Define los objetos .NET que se encuentran en el conjunto de
selección.

Elemento View (formato) Define una vista que se usa para mostrar uno o varios objetos
.NET.

Elemento ViewDefinitions (formato) Define las vistas utilizadas para mostrar objetos.

Elemento ViewSelectedBy (formato) Define los objetos .NET que se muestran en la vista.

Elemento WideControl (formato) Define un formato de lista ancho (valor único) para la
vista. Esta vista muestra un valor de propiedad única o un valor de script para cada
objeto.
Elemento WideEntries (formato) Proporciona las definiciones de la vista ancha. La vista
ancha debe especificar una o varias definiciones.

Elemento WideEntry (formato) Proporciona una definición de la vista ancha.

Elemento WideItem (formato) Define la propiedad o script cuyo valor se muestra.

Elemento Width (formato) Define el ancho (en caracteres) de una columna.

Elemento Wrap (formato) Especifica que el texto que supera el ancho de columna se
muestra en la línea siguiente.

Elemento WrapTables (formato) Especifica que los datos de una celda de tabla se
mueven a la línea siguiente si los datos son más largos que el ancho de la columna.

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento de configuración
Artículo • 24/09/2021

Representa el elemento de nivel superior de un archivo de formato.

Schema
Elemento de configuración

Sintaxis
XML

<Configuration>
<DefaultSettings>...</DefaultSettings>
<SelectionSets>...</SelectionSets>
<Controls>...</Controls>
<ViewDefinitions>...</ViewDefinitions>
</Configuration>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Configuration elemento . Este elemento debe ser el elemento
raíz de cada archivo de formato y este elemento debe contener al menos un elemento
secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento Controls para Elemento opcional.


Configuration
Define los controles comunes que pueden usar todas las vistas del
archivo de formato.
Elemento Descripción

Elemento Elemento opcional.


DefaultSettings
Define la configuración común que se aplica a todas las vistas del
archivo de formato.

Formato de elemento Elemento opcional.


SelectionSets
Define los conjuntos comunes de objetos .NET que pueden usar todas
las vistas del archivo de formato.

Elemento Elemento opcional.


ViewDefinitions
Define las vistas utilizadas para mostrar objetos.

Elementos primarios
Ninguno.

Comentarios
Los archivos de formato definen cómo se muestran los objetos. En la mayoría de los
casos, este elemento raíz contiene un elemento ViewDefinitions que define la tabla, la
lista y las vistas anchas del archivo de formato. Además de las definiciones de vista, el
archivo de formato puede definir conjuntos de selección comunes, configuraciones y
controles que esas vistas pueden usar.

Consulte también
Elemento Controls para Configuration

Elemento DefaultSettings

Elemento SelectionSets

Elemento ViewDefinitions

Escritura de un archivo de formato de PowerShell


Elemento Controls para Configuration
Artículo • 24/09/2021

Define los controles comunes que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls

Sintaxis
XML

<Controls>
<Control>...</Control>
</Controls>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Controls elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento Control para Controls for Elemento necesario.


Configuration
Define un control común que pueden usar todas las vistas
del archivo de formato.

Elementos primarios
Elemento Descripción

Elemento Configuration Representa el elemento de nivel superior de un archivo de formato.

Comentarios
Puede crear cualquier número de controles comunes. Para cada control, debe
especificar el nombre que se usa para hacer referencia al control y a los componentes
del control.

Consulte también
Elemento de configuración

Elemento Control para Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento Control para Controls for
Configuration
Artículo • 24/09/2021

Define un control común que pueden usar todas las vistas del archivo de formato y el
nombre que se usa para hacer referencia al control.

Schema
Elemento de configuración
Elemento Controls
Elemento Control

Sintaxis
XML

<Control>
<Name>NameOfControl</Name>
<CustomControl>...</CustomControl>
</Control>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Control elemento. Debe especificar solo uno de cada elemento
secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento CustomControl para Control for Elemento necesario.


Controls for Configuration
Define el control .

Elemento Name para Control for Configuration Elemento necesario.

Especifica el nombre utilizado para hacer


referencia al control.

Elementos primarios

Elemento Descripción

Elemento Controls de Define los controles comunes que pueden usar todas las vistas del
Configuration archivo de formato o de otros controles.

Comentarios
Se puede hacer referencia al nombre dado a este control en los elementos siguientes:

Elemento ExpressionBinding para CustomItem

Elemento GroupBy para View

Consulte también
Elemento Controls de Configuration

Elemento CustomControl para Control for Configuration

Elemento ExpressionBinding para CustomItem

Elemento GroupBy para View(Format)

Elemento Name para Control for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento CustomControl para Control
for Controls for Configuration
Artículo • 24/09/2021

Define un control . Este elemento se usa al definir un control común que pueden usar
todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl

Sintaxis
XML

<CustomControl>
<CustomEntries>...</CustomEntries>
</CustomControl>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControl elemento . Este elemento debe tener al menos un
elemento secundario. No hay ningún límite máximo para el número de elementos
secundarios que se pueden especificar.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento CustomEntries para CustomControl for Elemento necesario.


Configuration
Proporciona las definiciones de un
control .

Elementos primarios

Elemento Descripción

Elemento Control para Define un control común que pueden usar todas las vistas del archivo
Controls for de formato y el nombre que se usa para hacer referencia al control.
Configuration

Comentarios

Consulte también
Elemento Control para Controls for Configuration

Elemento CustomEntries para CustomControl for Configuration

Escritura de un archivo de formato de PowerShell


Elemento CustomEntries para
CustomControl for Controls for
Configuration
Artículo • 24/09/2021

Proporciona las definiciones de un control común. Este elemento se usa al definir un


control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries

Sintaxis
XML

<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomEntries elemento . Debe especificar uno o varios
elementos secundarios.

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento CustomEntry para CustomControl for Controls Proporciona una definición del
for Configuration control común.

Elementos primarios

Elemento Descripción

Elemento CustomControl para Control for Configuration Define un control común.

Comentarios
En la mayoría de los casos, un control solo tiene una definición, que se define en un
único CustomEntry elemento. Sin embargo, es posible tener varias definiciones si desea
usar el mismo control para mostrar diferentes objetos .NET. En esos casos, puede definir
un CustomEntry elemento para cada objeto o conjunto de objetos.

Consulte también
Elemento CustomControl para Control for Configuration

Elemento CustomEntry para CustomControl for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento CustomEntry para
CustomControl for Controls for
Configuration
Artículo • 24/09/2021

Proporciona una definición del control común. Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry

Sintaxis
XML

<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomEntry elemento . Debe especificar los elementos
mostrados por la definición.

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento EntrySelectedBy para Elemento opcional.


CustomEntry for Controls for
Configuration Define los tipos de .NET que usan la definición del control
común o la condición que debe existir para que se use este
control.

Elemento CustomItem para Elemento necesario.


CustomEntry for Controls for
Configuration Define qué datos muestra el control y cómo se muestran.

Elementos primarios

Elemento Descripción

Elemento CustomEntries para CustomControl for Proporciona las definiciones del control
Configuration común.

Comentarios
En la mayoría de los casos, solo se requiere una definición para cada control
personalizado común, pero es posible tener varias definiciones si desea usar el mismo
control para mostrar diferentes objetos .NET. En esos casos, puede proporcionar una
definición independiente para cada objeto o conjunto de objetos.

Consulte también
Elemento CustomEntries para CustomControl for Configuration

Elemento CustomItem para CustomEntry for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento CustomItem para
CustomEntry for Controls for
Configuration
Artículo • 24/09/2021

Define qué datos muestra el control y cómo se muestran. Este elemento se usa al definir
un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem

Sintaxis
XML

<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<NewLine/>
<Text>TextToDisplay</Text>
<Frame>...</Frame>
</CustomItem>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomItem elemento . Para obtener más información, vea la
sección Comentarios.

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento ExpressionBinding para Elemento opcional.


CustomItem for Controls for Configuration
Define los datos que muestra el control .

Elemento Frame para CustomItem for Elemento opcional.


Controls for Configuration
Define cómo se muestran los datos, como desplazar
los datos a la izquierda o a la derecha.

Elemento NewLine para CustomItem for Elemento opcional.


Controls for Configuration
Agrega una línea en blanco a la presentación del
control.

Elemento Text para CustomItem for Elemento opcional.


Controls for Configuration
Agrega texto, como paréntesis o corchetes, a la
presentación del control.

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomControl for Controls for Proporciona una definición del
Configuration control .

Comentarios
Al especificar los elementos secundarios del elemento , tenga en cuenta CustomItem lo
siguiente:

Los elementos secundarios deben agregarse en la secuencia siguiente:


ExpressionBinding , NewLine , y Text Frame .

No hay ningún límite máximo en el número de secuencias que puede especificar.


En cada secuencia, no hay ningún límite máximo en el número de
ExpressionBinding elementos que puede usar.

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for Configuration
Elemento Frame para CustomItem for Controls for Configuration

Elemento NewLine para CustomItem for Controls for Configuration

Elemento Text para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento ExpressionBinding para
CustomItem for Controls for
Configuration
Artículo • 24/09/2021

Define los datos que muestra el control . Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding

Sintaxis
XML

<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate></ScriptBlock>
</ExpressionBinding>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ExpressionBinding elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

CustomControl Element Elemento opcional.

Define un control utilizado por este control.

Elemento CustomControlName para Elemento opcional.


ExpressionBinding for Controls for Configuration
Especifica el nombre de un control común o
un control de vista.

Elemento EnumerateCollection para Elemento opcional.


ExpressionBinding for Controls for Configuration
Se especifica que el control muestra los
elementos de las colecciones.

Elemento ItemSelectionCondition para Elemento opcional.


ExpressionBinding for Controls for Configuration
Define la condición que debe existir para
que se utilice este control común.

Elemento PropertyName para ExpressionBinding Elemento opcional.


for Controls for Configuration
Especifica la propiedad .NET cuyo valor
muestra el control común.

Elemento ScriptBlock para ExpressionBinding for Elemento opcional.


Controls for Configuration
Especifica el script cuyo valor muestra el
control común.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra la vista de control
Controls for Configuration personalizada y cómo se muestran.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento CustomControlName para
ExpressionBinding for Controls for
Configuration
Artículo • 25/09/2021

Especifica el nombre de un control común. Este elemento se usa al definir un control


común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento CustomControlName

Sintaxis
XML

<CustomControlName>NameofCustomControl</CustomControlName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControlName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls for Define los datos que muestra el
Configuration control .

Valor de texto
Especifique el nombre del control.

Comentarios
Puede crear controles comunes que puedan usar todas las vistas de un archivo de
formato, y puede crear controles de vista que pueda usar una vista específica. Los
elementos siguientes especifican los nombres de estos controles:

Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Consulte también
Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Elemento ExpressionBinding para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento EnumerateCollection para
ExpressionBinding for Controls for
Configuration
Artículo • 24/09/2021

Se especifica que el control muestra los elementos de las colecciones. Este elemento se
usa al definir un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento EnumerateCollection

Sintaxis
XML

<EnumerateCollection/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EnumerateCollection elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls for Define los datos que muestra el
Configuration control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento ItemSelectionCondition para
ExpressionBinding for Controls for
Configuration
Artículo • 24/09/2021

Define la condición que debe existir para que se utilice este control. Este elemento se
usa al definir un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition

Sintaxis
XML

<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ItemSelectionCondition elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para ItemSelectionCondition Elemento opcional.


for Controls for Configuration
Especifica la propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para ItemSelectionCondition for Elemento opcional.


Controls for Configuration
Especifica el script que desencadena la
condición.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls for Define los datos que muestra el
Configuration control .

Comentarios
Puede especificar un nombre de propiedad o un script para esta condición, pero no
puede especificar ambos.

Consulte también
Elemento PropertyName para ItemSelectionCondition for Controls for Configuration

Elemento ScriptBlock para ItemSelectionCondition for Controls for Configuration

Elemento ExpressionBinding para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
ItemSelectionCondition for Controls for
Configuration
Artículo • 01/03/2022

Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad


está presente o cuando se evalúa como true , se cumple la condición y se usa el control
. Este elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para Define la condición que debe existir para


ExpressionBinding for Controls for Configuration que se utilice este control.

Valor de texto
Especifique el nombre de la propiedad de .NET que desencadena la condición.

Comentarios
Si se usa este elemento, no se puede especificar el elemento ScriptBlock al definir la
condición de selección.

Consulte también
Elemento ScriptBlock para ItemSelectionCondition for Controls for Configuration

Elemento ItemSelectionCondition para ExpressionBinding for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ItemSelectionCondition for Controls for
Configuration
Artículo • 01/03/2022

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa el control . Este elemento se usa al definir un
control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para Define la condición que debe existir para


ExpressionBinding for Controls for Configuration que se utilice este control.

Valor de texto
Especifique el script que se evalúa.

Comentarios
Si se usa este elemento, no se puede especificar el elemento PropertyName al definir la
condición de selección.

Consulte también
Elemento PropertyName para ItemSelectionCondition for Controls for Configuration

Elemento ItemSelectionCondition para ExpressionBinding for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
ExpressionBinding for Controls for
Configuration
Artículo • 27/09/2021

Especifica la propiedad .NET cuyo valor muestra el control común. Este elemento se usa
al definir un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
ExpressionBinding
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls for Define los datos que muestra el
Configuration control .

Valor de texto
Especifique el nombre de la propiedad .NET cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ExpressionBinding for Controls for
Configuration
Artículo • 27/09/2021

Especifica el script cuyo valor muestra el control común. Este elemento se usa al definir
un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls Define los datos que muestra el
for Configuration control común.

Valor de texto
Especifique el script cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento Frame para CustomItem for
Controls for Configuration
Artículo • 24/09/2021

Define cómo se muestran los datos, como desplazar los datos a la izquierda o a la
derecha. Este elemento se usa al definir un control común que pueden usar todas las
vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame

Sintaxis
XML

<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Frame elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

CustomItem Element Elemento Required

Elemento FirstLineHanging para Frame for Elemento opcional.


Controls for Configuration
Especifica cuántos caracteres se desplaza la primera
línea de datos a la izquierda.

Elemento FirstLineIndent para Frame for Elemento opcional.


Controls for Configuration
Especifica cuántos caracteres se desplaza la primera
línea de datos a la derecha.

Elemento LeftIndent para Frame for Elemento opcional.


Controls for Configuration
Especifica cuántos caracteres se desplazan los
datos del margen izquierdo.

Elemento RightIndent para Frame for Elemento opcional.


Controls for Configuration
Especifica cuántos caracteres se desplazan los
datos del margen derecho.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra el control y
Controls for Configuration cómo se muestran.

Comentarios
No se pueden especificar los elementos FirstLineHanging y FirstLineIndent en el mismo
Frame elemento.

Consulte también
Elemento FirstLineHanging para Frame for Controls for Configuration

Elemento FirstLineIndent para Frame for Controls for Configuration

Elemento LeftIndent para Frame for Controls for Configuration


Elemento RightIndent para Frame for Controls for Configuration

Elemento CustomItem para CustomEntry for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento FirstLineHanging para Frame
for Controls for Configuration
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la izquierda. Este


elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineHanging

Sintaxis
XML

<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineHanging elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem for Define cómo se muestran los datos, como desplazar los
Controls for Configuration datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el FirstLineIndent elemento .

Consulte también
Elemento Frame para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento FirstLineIndent para Frame for
Controls for Configuration
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la derecha. Este


elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineIndent

Sintaxis
XML

<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem for Define cómo se muestran los datos, como desplazar los
Controls for Configuration datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el elemento FirstLineHanging.

Consulte también
Elemento FirstLineHanging para Frame for Controls for Configuration

Elemento Frame para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento LeftIndent para Frame for
Controls for Configuration
Artículo • 24/09/2021

Especifica cuántos caracteres se desplazan los datos del margen izquierdo. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento LeftIndent

Sintaxis
XML

<LeftIndent>CharactersToShift</LeftIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del LeftIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem for Define cómo se muestran los datos, como desplazar los
Controls for Configuration datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la izquierda.

Comentarios

Consulte también
Elemento Frame para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento RightIndent para Frame for
Controls for Configuration
Artículo • 27/09/2021

Especifica cuántos caracteres se desplazan los datos del margen derecho. Este elemento
se usa al definir un control común que pueden usar todas las vistas del archivo de
formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento RightIndent

Sintaxis
XML

<RightIndent>CharactersToShift</RightIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del RightIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem for Define cómo se muestran los datos, como desplazar los
Controls for Configuration datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la derecha.

Comentarios

Consulte también
Elemento Frame para CustomItem for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento NewLine para CustomItem for
Controls for Configuration
Artículo • 24/09/2021

Agrega una línea en blanco a la presentación del control. Este elemento se usa al definir
un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento NewLine

Sintaxis
XML

<NewLine/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del NewLine elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Controls Define un control para la vista de control
for Configuration personalizada.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento Text para CustomItem for
Controls for Configuration
Artículo • 24/09/2021

Especifica el texto que se agrega a los datos que muestra el control, como una etiqueta,
corchetes para incluir los datos y espacios para aplicar sangría a los datos. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Text

Sintaxis
XML

<Text>TextToDisplay</Text>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Text elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra el control y
Controls for Configuration cómo se muestran.

Valor de texto
Especifique el texto de un control para los datos que desea mostrar.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento EntrySelectedBy para
CustomEntry for Controls
Artículo • 24/09/2021

Define los tipos de .NET que usan la definición del control común o la condición que
debe existir para que se use este control. Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>SelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento .

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy for Controls for
Configuration Define la condición que debe existir para que se
utilice la definición de control común.

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy for Controls for
Configuration Especifica un conjunto de tipos de .NET que usan
esta definición del control común.

Elemento TypeName para EntrySelectedBy for Elemento opcional.


Controls for Configuration
Especifica un tipo de .NET que usa esta definición
del control común.

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomControl for Controls Proporciona una definición del
for Configuration control común.

Comentarios
Como mínimo, cada definición debe tener al menos un tipo de .NET, un conjunto de
selección o una condición de selección especificados. No hay ningún límite máximo en
el número de tipos, conjuntos de selección o condiciones de selección que puede
especificar.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for Configuration

Elemento SelectionSetName para EntrySelectedBy for Controls for Configuration

Elemento CustomEntry para CustomControl for Controls for Configuration

Elemento TypeName para EntrySelectedBy for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy for Controls for
Configuration
Artículo • 24/09/2021

Define una condición que debe existir para que se utilice una definición de control
común. Este elemento se usa al definir un control común que pueden usar todas las
vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionCondition elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento PropertyName para SelectionCondition Elemento opcional.


for Controls for Configuration
Especifica una propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition for Elemento opcional.


Controls for Configuration
Especifica el script que desencadena la
condición.

Elemento SelectionSetName para Elemento opcional.


SelectionCondition for Controls for Configuration
Especifica el conjunto de tipos de .NET que
desencadena la condición.

Elemento TypeName para SelectionCondition for Elemento opcional.


Controls for Configuration
Especifica un tipo de .NET que
desencadena la condición.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para CustomEntry Define los tipos de .NET que usan esta entrada de
for Controls for Configuration la definición de control común.

Comentarios
Se deben seguir las instrucciones siguientes al definir una condición de selección:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.

Para obtener más información sobre cómo se pueden usar las condiciones de selección,
vea Definición de condiciones para cuando se muestran datos.
Consulte también
Elemento PropertyName para SelectionCondition for Controls for Configuration

Elemento ScriptBlock para SelectionCondition for Controls for Configuration

Elemento SelectionSetName para SelectionCondition for Controls for Configuration

Elemento TypeName para SelectionCondition for Controls for Configuration

Elemento EntrySelectedBy para CustomEntry for Controls for Configuration

Escribir un archivo Windows PowerShell de tipos y formato


Elemento PropertyName para
SelectionCondition for Controls for
Configuration
Artículo • 24/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa la entrada .
Este elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy for Controls for utilice una definición de control común.
Configuration

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
script, pero no puede especificar ambos. Para obtener más información sobre cómo se
pueden usar las condiciones de selección, vea Definir condiciones para mostrar datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for Controls for
Configuration
Artículo • 24/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la definición . Este elemento se usa al definir un
control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy for Controls for utilice la definición de control común.
Configuration

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de script o propiedad
para evaluar, pero no puede especificar ambos. Para obtener más información sobre
cómo se pueden usar las condiciones de selección, vea Definir condiciones para mostrar
datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
SelectionCondition for Controls for
Configuration
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante este control. Este elemento se usa al definir un control
común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que
EntrySelectedBy for Controls for Configuration se utilice la definición de control.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
objetos.

La condición de selección puede especificar un conjunto de selección o un tipo de .NET,


pero no puede especificar ambos. Para obtener más información sobre cómo usar
condiciones de selección, vea Definir condiciones para mostrar datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for Configuration

Definir condiciones para cuando se muestran los datos

Definición de conjuntos de selección

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for Controls for
Configuration
Artículo • 24/09/2021

Especifica un tipo de .NET que desencadena la condición. Este elemento se usa al definir
un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para
EntrySelectedBy for CustomEntry for que se utilice la definición de control.
Configuration

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios

Consulte también
Elemento SelectionCondition para EntrySelectedBy for CustomEntry for Configuration

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy for Controls for
Configuration
Artículo • 24/09/2021

Especifica un conjunto de tipos de .NET que usan esta definición del control. Este
elemento se usa al definir un control común que pueden usar todas las vistas del
archivo de formato.

Schema
Elemento de configuración
Elemento Controls de Configuration
Elemento Control para Controls for Configuration
Elemento CustomControl para Control for Configuration
Elemento CustomEntries para CustomControl for Configuration
Elemento CustomEntry para CustomControl for Controls for Configuration
Elemento EntrySelectedBy para CustomEntry for Controls for Configuration
Elemento SelectionSetName para EntrySelectedBy for Controls for Configuration

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
None
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para Define los tipos de .NET que usan esta definición de control
CustomEntry for Controls for o la condición que debe existir para que se use esta
Configuration definición.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Cada definición de control debe tener al menos un nombre de tipo, un conjunto de
selección o una condición de selección definidos.

Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de


objetos que se usan en varias vistas. Para obtener más información sobre cómo definir
conjuntos de selección, vea Definir conjuntos de selección.

Consulte también
Elemento EntrySelectedBy para CustomEntry for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy for Controls for
Configuration
Artículo • 24/09/2021

Especifica un tipo de .NET que usa esta definición del control. Este elemento se usa al
definir un control común que pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para Define los tipos de .NET que usan esta definición de control
CustomEntry for Controls for o la condición que debe existir para que se use esta
Configuration definición.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios

Consulte también
Elemento EntrySelectedBy para CustomEntry for Controls for Configuration

Escritura de un archivo de formato de PowerShell


Elemento Name para Control for
Controls for Configuration
Artículo • 27/09/2021

Especifica el nombre del control. Este elemento se usa al definir un control común que
pueden usar todas las vistas del archivo de formato.

Schema
Elemento de configuración
Elemento Controls
Elemento Control
Elemento Name

Sintaxis
XML

<Name>NameOfControl</Name>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Name elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción
Elemento Descripción

Elemento Control para Define un control común que pueden usar todas las vistas del archivo
Controls for de formato y el nombre que se usa para hacer referencia al control.
Configuration

Valor de texto
Especifique el nombre que se usa para hacer referencia a este control.

Comentarios
El nombre especificado aquí se puede usar en los siguientes elementos para hacer
referencia a este control.

Al crear una tabla, una lista, una vista de control amplia o personalizada, el control
se puede especificar mediante el siguiente elemento: Elemento GroupBy para
View.

Al crear otro control común, este control se puede especificar mediante el


siguiente elemento: Elemento ExpressionBinding para CustomItem for Controls for
Configuration

Al crear un control que una vista puede usar, este control se puede especificar
mediante el siguiente elemento: Elemento ExpressionBinding para CustomItem for
Controls for View

Consulte también
Elemento Control para Controls for Configuration

Elemento ExpressionBinding para CustomItem for Controls for Configuration

Elemento ExpressionBinding para CustomItem for Controls for View

Elemento GroupBy para View

Escritura de un archivo de formato de PowerShell


Elemento DefaultSettings
Artículo • 24/09/2021

Define la configuración común que se aplica a todas las vistas del archivo de formato. La
configuración común incluye mostrar errores, encapsular texto en tablas, definir cómo
se expanden las colecciones, etc.

Schema
Elemento de configuración
Elemento DefaultSettings

Sintaxis
XML

<DefaultSettings>
<ShowError/>
<DisplayError/>
<PropertyCountForTable>NumberOfProperties</PropertyCountFortable>
<WrapTables/>
<EnumerableExpansions>...</EnumerableExpansions>
</DefaultSettings>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del DefaultSettings elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento DisplayError Elemento opcional.

Especifica que la cadena #ERR se muestra cuando se produce un error al


mostrar un fragmento de datos.

Elemento Elemento opcional.


EnumerableExpansions
Define las distintas formas en que los objetos .NET se expanden cuando
se muestran en una vista.

PropertyCountForTable Elemento opcional.

Especifica el número mínimo de propiedades que un objeto debe tener


para mostrar el objeto en una vista de tabla.

Elemento ShowError Elemento opcional.

Especifica que se muestra el registro de error completo cuando se


produce un error al mostrar un fragmento de datos.

Elemento WrapTables Elemento opcional.

Especifica que los datos de una tabla se mueven a la línea siguiente si


no caben en el ancho de la columna.

Elementos primarios

Elemento Descripción

Elemento Configuration Representa el elemento de nivel superior de un archivo de formato.

Comentarios

Consulte también
Elemento de configuración

Elemento DisplayError

Elemento EnumerableExpansions

PropertyCountForTable

Elemento ShowError
Elemento WrapTables

Escritura de un archivo de formato de PowerShell


Elemento DisplayError
Artículo • 25/09/2021

Especifica que la cadena #ERR se muestra cuando se produce un error que muestra un
fragmento de datos.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento DisplayError

Sintaxis
XML

<DisplayError/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del DisplayError elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define la configuración común que se aplica a todas las vistas del archivo
DefaultSettings de formato.
Comentarios
De forma predeterminada, cuando se produce un error al intentar mostrar un fragmento
de datos, la ubicación de los datos se deja en blanco. Cuando este elemento se
establece en true, se mostrará #ERR cadena.

Consulte también
Elemento DefaultSettings

Escritura de un archivo de formato de PowerShell


Elemento EnumerableExpansions
Artículo • 24/09/2021

Define cómo se expanden los objetos de colección de .NET cuando se muestran en una
vista.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions

Sintaxis
XML

<EnumerableExpansions>
<EnumerableExpansion>...</EnumerableExpansion>
</EnumerableExpansions>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EnumerableExpansions elemento . No hay ningún límite en el
número de elementos secundarios que puede usar.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento Elemento opcional.


EnumerableExpansion
Define los objetos de colección de .NET específicos que se expanden
cuando se muestran en una vista.
Elementos primarios

Elemento Descripción

Elemento Define la configuración común que se aplica a todas las vistas del archivo
DefaultSettings de formato.

Comentarios
Este elemento se usa para definir cómo se muestran los objetos de colección y los
objetos de la colección. En este caso, un objeto de colección hace referencia a cualquier
objeto que admita la interfaz System.Collections.ICollection.

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento EnumerableExpansion
Artículo • 24/09/2021

Define cómo se expanden objetos de colección de .NET específicos cuando se muestran


en una vista.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion

Sintaxis
XML

<EnumerableExpansion>
<EntrySelectedBy>...</EntrySelectedBy>
<Expand>EnumOnly, CoreOnly, Both</Expand>
</EnumerableExpansion>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EnumerableExpansion elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento EntrySelectedBy para Elemento opcional.


EnumerableExpansion
Define qué objetos de colección de .NET se expanden
mediante esta definición.
Elemento Descripción

Elemento Expand Especifica cómo se expande el objeto de colección para


esta definición.

Elementos primarios

Elemento Descripción

Elemento Define las distintas formas en que los objetos de colección de .NET se
EnumerableExpansions expanden cuando se muestran en una vista.

Comentarios
Este elemento se usa para definir cómo se muestran los objetos de colección y los
objetos de la colección. En este caso, un objeto de colección hace referencia a cualquier
objeto que admita la interfaz System.Collections.ICollection.

El comportamiento predeterminado es mostrar solo las propiedades de los objetos de la


colección.

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento EntrySelectedBy para
EnumerableExpansion
Artículo • 24/09/2021

Define los tipos de .NET que usan esta definición o la condición que debe existir para
que se use esta definición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion
Elemento EntrySelectedBy para EnumerableExpansion

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy for
EnumerableExpansion Define la condición que debe existir para expandir los
objetos de colección de esta definición.

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy for
EnumerableExpansion Especifica un conjunto de tipos de .NET que usan esta
definición de cómo se expanden los objetos de
colección.

Elemento TypeName para Elemento opcional.


EntrySelectedBy for
EnumerableExpansion Especifica un tipo de .NET que usa esta definición de
cómo se expanden los objetos de colección.

Elementos primarios

Elemento Descripción

Elemento Define cómo se expanden objetos de colección de .NET específicos


EnumerableExpansion cuando se muestran en una vista.

Comentarios
Debe especificar al menos un tipo, conjunto de selección o condición de selección para
una entrada de definición. No hay ningún límite máximo en el número de elementos
secundarios que puede usar.

Las condiciones de selección se usan para definir una condición que debe existir para la
definición que se va a usar, como cuando un objeto tiene una propiedad específica o
cuando un valor de propiedad o script específico se evalúa como true . Para obtener
más información sobre las condiciones de selección, vea Definir condiciones para
mostrar datos.

Consulte también
Definición de condiciones para mostrar datos

Elemento EnumerableExpansion

Elemento SelectionCondition para EntrySelectedBy for EnumerableExpansion


Elemento SelectionSetName para EntrySelectedBy for EnumerableExpansion

Elemento TypeName para EntrySelectedBy for EnumerableExpansion

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy for
EnumerableExpansion
Artículo • 24/09/2021

Define la condición que debe existir para expandir los objetos de colección de esta
definición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionCondition elemento . Debe especificar un único
PropertyName elemento ScriptBlock o . Los SelectionSetName elementos y son

TypeName opcionales. Puede especificar uno de los dos elementos.

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para SelectionCondition for Elemento opcional.


EntrySelectedBy for EnumerableExpansion
Especifica la propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition for Elemento opcional.


EntrySelectedBy for EnumerableExpansion
Especifica el script que desencadena la
condición.

Elemento SelectionSetName para SelectionCondition Elemento opcional.


for EntrySelectedBy for EnumerableExpansion
Especifica el conjunto de tipos de .NET
que desencadena la condición.

Elemento TypeName para SelectionCondition for Elemento opcional.


EntrySelectedBy for EnumerableExpansion
Especifica un tipo de .NET que
desencadena la condición.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para Define qué objetos de colección de .NET se expanden


EnumerableExpansion mediante esta definición.

Comentarios
Cada definición debe tener al menos un nombre de tipo, un conjunto de selección o una
condición de selección definidos.

Al definir una condición de selección, se aplican los siguientes requisitos:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.

Para obtener más información sobre cómo usar condiciones de selección, vea Definición
de condiciones para la colocación de datos.
Para obtener más información sobre otros componentes de una vista amplia, vea Wide
View.

Consulte también
Definir condiciones para cuando se muestran los datos

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
SelectionCondition for Controls for View
Artículo • 24/09/2021

Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad


está presente o cuando se evalúa como , se cumple la true condición y se usa la
entrada . Este elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control para Controls for View
Elemento CustomControl para Control for Controls for View
Elemento CustomEntries para CustomControl for Controls for View
Elemento CustomEntry para CustomEntries for Controls for View
Elemento EntrySelectedBy para CustomEntry for Controls for View
Elemento SelectionCondition para EntrySelectedBy for Controls for View
Elemento PropertyName para SelectionCondition for Controls for View

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy for Controls for View utilice la definición de control.

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
script, pero no puede especificar ambos. Para obtener más información sobre cómo se
pueden usar las condiciones de selección, vea Definir condiciones para mostrar datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for Controls for View
Artículo • 24/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la definición. Este elemento se usa al definir

controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy for Controls for View utilice la definición de control.

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de script o propiedad
para evaluar, pero no puede especificar ambos. Para obtener más información sobre
cómo se pueden usar las condiciones de selección, vea Definir condiciones para mostrar
datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
SelectionCondition for EntrySelectedBy
for EnumerableExpansion
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansions
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para expandir
EntrySelectedBy for EnumerableExpansion los objetos de colección de esta definición.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
La condición de selección puede especificar un conjunto de selección o un tipo de .NET,
pero no puede especificar ambos. Para obtener más información sobre cómo usar las
condiciones de selección, vea Definir condiciones para mostrar datos.

Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
selección.

Consulte también
Definición de conjuntos de selección

Elemento SelectionCondition para EntrySelectedBy for EnumerableExpansion

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for EntrySelectedBy
for EnumerableExpansion
Artículo • 24/09/2021

Especifica un tipo de .NET que desencadena la condición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansions
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para expandir
EntrySelectedBy for EnumerableExpansion los objetos de colección de esta definición.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios

Consulte también
Elemento SelectionCondition para EntrySelectedBy for EnumerableExpansion

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy for
EnumerableExpansion
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que se expanden mediante esta definición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion
Elemento EntrySelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para Define los objetos de colección de .NET que se expanden
EnumerableExpansion mediante esta definición.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Cada definición debe especificar uno o varios nombres de tipo, un conjunto de
selección o una condición de selección.

Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de


objetos que se usan en varias vistas. Por ejemplo, puede que desee crear una vista de
tabla y una vista de lista para el mismo conjunto de objetos. Para obtener más
información sobre cómo definir conjuntos de selección, vea Definir conjuntos de objetos
para una vista.

Consulte también
Definición de conjuntos de selección

Elemento EntrySelectedBy para EnumerableExpansion

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy for
EnumerableExpansion
Artículo • 24/09/2021

Especifica un tipo de .NET que se expande mediante esta definición. Este elemento se
usa al definir una configuración predeterminada.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion
Elemento EntrySelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy Define los tipos de .NET que usan esta definición o la condición
para EnumerableExpansion que debe existir para que se use esta definición.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios

Consulte también
Elemento EntrySelectedBy para EnumerableExpansion

Escritura de un archivo de formato de PowerShell


Elemento Expand
Artículo • 24/09/2021

Especifica cómo se expande el objeto de colección para esta definición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion
Elemento Expand

Sintaxis
XML

<Expand>EnumOnly, CoreOnly, Both</Expand>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Expand elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define cómo se expanden objetos de colección de .NET específicos


EnumerableExpansion cuando se muestran en una vista.
Valor de texto
Especifique uno de los valores siguientes:

EnumOnly: muestra solo las propiedades de los objetos de la colección.

CoreOnly: muestra solo las propiedades del objeto de colección.

Ambos: muestra las propiedades de los objetos de la colección y las propiedades


del objeto de colección.

Comentarios
Este elemento se usa para definir cómo se muestran los objetos de colección y los
objetos de la colección. En este caso, un objeto de colección hace referencia a cualquier
objeto que admita la interfaz System.Collections.ICollection.

El comportamiento predeterminado es mostrar solo las propiedades de los objetos de la


colección.

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento PropertyCountForTable
Artículo • 24/09/2021

Elemento opcional. Especifica el número mínimo de propiedades que un objeto debe


tener para mostrar el objeto en una vista de tabla.

Schema
Elemento DefaultSettings
Elemento PropertyCountForTable

Sintaxis
XML

<PropertyCountForTable>NumberOfProperties</PropertyCountFortable>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyCountForTable elemento . El valor predeterminado de
este elemento es 4 .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define la configuración común que se aplica a todas las vistas del archivo
DefaultSettings de formato.
Comentarios

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento ShowError
Artículo • 24/09/2021

Especifica que se muestra el registro de error completo cuando se produce un error al


mostrar un fragmento de datos.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento ShowError

Sintaxis
scr

<ShowError/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ShowError elemento . El valor predeterminado de este elemento
es false .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define la configuración común que se aplica a todas las vistas del archivo
DefaultSettings de formato.
Comentarios

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento WrapTables
Artículo • 24/09/2021

Especifica que los datos de una celda de tabla se mueven a la línea siguiente si los datos
son más largos que el ancho de la columna.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento WrapTables

Sintaxis
XML

<WrapTables/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del WrapTables elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define la configuración común que se aplica a todas las vistas del archivo
DefaultSettings de formato.
Comentarios

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento SelectionSets
Artículo • 24/09/2021

Define los conjuntos comunes de objetos .NET que pueden usar todas las vistas del
archivo de formato. Las vistas y los controles del archivo de formato pueden hacer
referencia al conjunto completo de objetos utilizando solo el nombre del conjunto de
selección.

Schema
Elemento de configuración
Elemento SelectionSets

Sintaxis
XML

<SelectionSets>
<SelectionSet>...</SelectionSet>
</SelectionSets>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSets elemento . Cada elemento secundario define un
conjunto de objetos a los que se puede hacer referencia mediante el nombre del
conjunto. El orden de los elementos secundarios no es significativo.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento Elemento necesario.


SelectionSet
Define un único conjunto de objetos .NET a los que se puede hacer referencia
mediante el nombre del conjunto.

Elementos primarios

Elemento Descripción

Elemento Configuration Representa el elemento de nivel superior de un archivo de formato.

Comentarios
Puede usar conjuntos de selección si tiene un conjunto de objetos relacionados a los
que desea hacer referencia mediante un nombre único, como un conjunto de objetos
relacionados a través de la herencia. Al definir las vistas, puede especificar el conjunto
de objetos mediante el nombre del conjunto de selección en lugar de enumerar todos
los objetos de cada vista.

Los conjuntos de selección comunes se especifican por su nombre al definir las vistas
del archivo de formato o las definiciones de las vistas. En estos casos, SelectionSetName
el elemento secundario de los elementos y especifica el conjunto que se va a
ViewSelectedBy EntrySelectedBy utilizar. Para obtener más información sobre los
conjuntos de selección, vea Definir conjuntos de objetos.

Consulte también
Elemento de configuración

Definición de conjuntos de selección

Elemento SelectionSet

Escritura de un archivo de formato de PowerShell


Elemento SelectionSet
Artículo • 24/09/2021

Define un conjunto de objetos .NET a los que se puede hacer referencia mediante el
nombre del conjunto.

Schema
Elemento de configuración
Elemento SelectionSets
Elemento SelectionSet

Sintaxis
XML

<SelectionSet>
<Name>SelectionSetName</Name>
<Types>...</Types>
</SelectionSet>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSet elemento . Cada conjunto de selección debe tener
un nombre y debe especificar los objetos .NET del conjunto.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento Name para Elemento necesario.


SelectionSet
Especifica el nombre utilizado para hacer referencia al conjunto de
selección.
Elemento Descripción

Elemento Types Elemento necesario.

Define los objetos .NET que se encuentran en el conjunto de


selección.

Elementos primarios

Elemento Descripción

Formato de elemento Define los conjuntos comunes de objetos .NET que pueden usar todas
SelectionSets las vistas del archivo de formato.

Comentarios
Puede usar conjuntos de selección cuando tenga un conjunto de objetos relacionados a
los que desea hacer referencia mediante un solo nombre, como un conjunto de objetos
relacionados a través de la herencia. Al definir las vistas, puede especificar el conjunto
de objetos mediante el nombre del conjunto de selección en lugar de enumerar todos
los objetos de cada vista.

Los conjuntos de selección comunes se especifican por su nombre al definir las vistas
del archivo de formato o las definiciones de las vistas. En estos casos, SelectionSetName
el elemento secundario de los elementos y especifica el conjunto que se va a
ViewSelectedBy EntrySelectedBy usar. Para obtener más información sobre los

conjuntos de selección, vea Definir conjuntos de objetos.

Ejemplo
En el ejemplo siguiente se muestra SelectionSet un elemento que define cuatro tipos
de .NET.

XML

<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>

Consulte también
Definición de conjuntos de selección

Elemento Name de SelectionSet

Elemento SelectionSets

Elemento Types

Escritura de un archivo de formato de PowerShell


Elemento Name para SelectionSet
Artículo • 27/09/2021

Especifica el nombre utilizado para hacer referencia al conjunto de selección.

Schema
Elemento de configuración
Elemento SelectionSets
Elemento SelectionSet
Elemento Name

Sintaxis
XML

<Name>Name of selection set</Name>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Name elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define un único conjunto de objetos .NET a los que se puede hacer referencia
SelectionSet mediante el nombre del conjunto.
Valor de texto
Especifique el nombre para hacer referencia al conjunto de selección. No hay ninguna
restricción en cuanto a los caracteres que se pueden usar.

Comentarios
El nombre especificado aquí se usa en el SelectionSetName elemento . Conjunto de
selección que puede usar una vista, una definición de una vista (las vistas pueden tener
varias definiciones) o al especificar una condición de selección. Para obtener más
información sobre los conjuntos de selección, vea Definir conjuntos de objetos.

Ejemplo
En este ejemplo se muestra SelectionSet un elemento que define cuatro tipos de .NET.
El nombre del conjunto de selección es "FileSystemTypes".

XML

<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>

Consulte también
Definición de conjuntos de selección

Elemento SelectionSet

Escritura de un archivo de formato de PowerShell


Elemento Types para SelectionSet
Artículo • 24/09/2021

Define los objetos .NET que se encuentran en el conjunto de selección.

Schema
Elemento de configuración
Elemento SelectionSets
Elemento SelectionSet
Elemento Types

Sintaxis
XML

<Types>
<TypeName>Nameof.NetType</TypeName>
</Types>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Types elemento . Debe haber al menos un elemento secundario,
pero no hay ningún límite máximo para el número de elementos secundarios que se
pueden agregar.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento TypeName de Types Elemento necesario.

Especifica el objeto .NET que pertenece al conjunto de selección.


Elementos primarios

Elemento Descripción

Elemento Define un conjunto de objetos .NET a los que se puede hacer referencia
SelectionSet mediante el nombre del conjunto.

Comentarios
Los objetos definidos por este elemento son un conjunto de selección que puede usar
una vista, una definición de una vista (las vistas pueden tener varias definiciones) o al
especificar una condición de selección. Para obtener más información sobre los
conjuntos de selección, vea Definir conjuntos de objetos.

Ejemplo
En este ejemplo se muestra SelectionSet un elemento que define cuatro tipos de .NET.

XML

<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>

Consulte también
Definir conjuntos de objetos

Elemento SelectionSet

Elemento TypeName de Types

Escritura de un archivo de formato de PowerShell


Elemento TypeName para types
Artículo • 24/09/2021

Especifica el tipo de .NET de un objeto que pertenece al conjunto de selección.

Schema
Elemento de configuración
Elemento SelectionSets
Elemento SelectionSet
Elemento Types
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</Name>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento . Se debe incluir TypeName al menos un
elemento en el conjunto de selección.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Types Define los objetos .NET que se encuentran en el conjunto de selección.
Valor de texto
Especifique el nombre completo para el tipo de .NET.

Comentarios
Puede usar conjuntos de selección si tiene un conjunto de objetos relacionados a los
que desea hacer referencia mediante un nombre único, como un conjunto de objetos
relacionados a través de la herencia. Al definir las vistas, puede especificar el conjunto
de objetos mediante el nombre del conjunto de selección en lugar de enumerar todos
los objetos de cada vista.

Los conjuntos de selección comunes se especifican por su nombre al definir las vistas
del archivo de formato. En estos casos, SelectionSetName el elemento secundario del
elemento para la vista especifica el ViewSelectedBy conjunto. Sin embargo, las distintas
entradas de una vista también pueden especificar un conjunto de selección que solo se
aplica a esa entrada de la vista. Para obtener más información sobre los conjuntos de
selección, vea Definir conjuntos de objetos.

Ejemplo
En el ejemplo siguiente se muestra SelectionSet un elemento que define cuatro tipos
de .NET.

<SelectionSets>
<SelectionSet>
<Name>FileSystemTypes</Name>
<Types>
<TypeName>System.IO.DirectoryInfo</TypeName>
<TypeName>System.IO.FileInfo</TypeName>
<TypeName>Deserialized.System.IO.DirectoryInfo</TypeName>
<TypeName>Deserialized.System.IO.FileInfo</TypeName>
</Types>
</SelectionSet>
</SelectionSets>

Consulte también
Definición de conjuntos de selección
Elemento SelectionSet

Elemento SelectionSets

Elemento Types

Escritura de un archivo de formato de Windows PowerShell


Elemento ViewDefinitions
Artículo • 24/09/2021

Define las vistas utilizadas para mostrar objetos .NET. Estas vistas pueden mostrar las
propiedades y los valores de script de un objeto en formato de tabla, formato de lista,
formato ancho y formato de control personalizado.

Schema
Elemento de configuración
ViewDefinitions

Sintaxis
XML

<ViewDefinitions>
<View>...</View>
</ViewDefinitions>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ViewDefinitions elemento . No hay ningún límite en el número
de vistas que se pueden definir en un archivo de formato y se pueden agregar en
cualquier orden.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento View Define una vista que se usa para mostrar uno o varios objetos .NET.
Elementos primarios

Elemento Descripción

Elemento Configuration Representa el elemento de nivel superior de un archivo de formato.

Comentarios
Para obtener más información sobre los componentes de los diferentes tipos de vistas,
vea los temas siguientes:

Creación de una vista de tabla

Creación de una vista de lista

Creación de una vista amplia

Controles personalizados

Ejemplo
En este ejemplo se ViewDefinitions muestra un elemento que contiene los elementos
primarios de una vista de tabla y una vista de lista.

XML

<Configuration>
<ViewDefinitions>
<View>
<TableControl>...</TableControl>
</View>
<View>
<ListControl>...</ListControl>
</View>
</ViewDefinitions>
</Configuration>

Consulte también
Elemento de configuración

Elemento View

Creación de una vista de tabla


Creación de una vista de lista

Creación de una vista amplia

Controles personalizados

Escritura de un archivo de formato de PowerShell


Elemento View
Artículo • 27/09/2021

Define una vista que muestra uno o varios objetos .NET. No hay ningún límite en el
número de vistas que se pueden definir en un archivo de formato.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View

Sintaxis
XML

<View>
<Name>Friendly name of view.</Name>
<OutOfBand />
<ViewSelectedBy>...</ViewSelectedBy>
<Controls>...</Controls>
<GroupBy>...</GroupBy>
<TableControl>...</TableControl>
<ListControl>...</ListControl>
<WideControl>...</WideControl>
<CustomControl>...</CustomControl>
</View>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del View elemento . Debe especificar uno y solo uno de los
elementos secundarios del control, y debe especificar el nombre de la vista y los objetos
que usan la vista. Definir controles personalizados, cómo agrupar objetos y especificar si
la vista está fuera de banda son opcionales.

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento Controls Elemento opcional.


para View
Define un conjunto de controles a los que se puede hacer referencia por su
nombre desde dentro de la vista.

Elemento Elemento opcional.


CustomControl
Define un formato de control personalizado para la vista.

Elemento Elemento opcional.


GroupBy para
View Define cómo se agrupan los miembros de los objetos de .NET.

Elemento Elemento opcional.


ListControl
Define un formato de lista para la vista.

Elemento Name Elemento necesario.


para View
Especifica el nombre utilizado para hacer referencia a la vista.

OutOfBand Elemento opcional

Cuando OutOfBand es true, la vista se aplica independientemente de los


objetos anteriores que puedan haber seleccionado una vista diferente.

Elemento Elemento opcional.


TableControl
Define un formato de tabla para la vista.

Elemento Elemento necesario.


ViewSelectedBy
para View Define los objetos .NET que muestra esta vista.

Elemento Elemento opcional.


WideControl
Define un formato de lista ancho (valor único) para la vista.

Elementos primarios

Elemento Descripción

Elemento ViewDefinitions Define las vistas utilizadas para mostrar objetos .


Comentarios
Para obtener más información sobre los componentes de diferentes vistas y controles
personalizados, vea los temas siguientes:

Componentes de la vista de tabla

Componentes de la vista de lista

Componentes de Wide View

Controles personalizados

Ejemplo
En este ejemplo se View muestra un elemento que define una vista de tabla para el
objeto System.Serviceprocess.Servicecontroller.

XML

<ViewDefinitions>
<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>
</ViewDefinitions>

Consulte también
Elemento ViewDefinitions

Elemento Name para View

Elemento ViewSelectedBy

Elemento Controls para View

Elemento GroupBy para View

Elemento TableControl

Elemento ListControl
Elemento WideControl

Elemento CustomControl

Escritura de un archivo de formato de PowerShell


Elemento Controls para View
Artículo • 24/09/2021

Define los controles de vista que puede usar una vista específica.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls

Sintaxis
XML

<Controls>
<Control>...</Control>
</Controls>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del Controls elemento. Este elemento debe tener al menos un
elemento secundario. No hay ningún número máximo de elementos secundarios, ni su
orden es significativo.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento Control para Controls for View Define un control que puede usar la vista.

Elementos primarios
Elemento Descripción

Elemento Define una vista que se usa para mostrar los miembros de uno o varios objetos
View .NET.

Comentarios

Consulte también
Elemento Control

Elemento View

Escritura de un archivo de formato de PowerShell


Elemento Control para Controls for View
Artículo • 24/09/2021

Define un control que puede usar la vista y el nombre que se usa para hacer referencia
al control.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control

Sintaxis
XML

<Control>
<Name>NameOfControl</Name>
<CustomControl>...</CustomControl>
</Control>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Control elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento Name para Control for View Elemento necesario.

Especifica el nombre del control.


Elemento Descripción

Elemento CustomControl para Control for Controls for Elemento necesario.


View
Define el control utilizado por esta
vista.

Elementos primarios

Elemento Descripción

Elemento Controls Define los controles de vista que puede usar una vista específica.

Comentarios
Este control se puede especificar mediante los siguientes elementos:

Elemento CustomControlName para ExpressionBinding for Controls for View

Elemento CustomControlName para ExpressionBinding para CustomControl for


View

Elemento CustomControlName para ExpressionBinding para GroupBy

Elemento CustomControlName para GroupBy

Consulte también
Elemento CustomControl para Control for Controls for View

Elemento CustomControlName para ExpressionBinding for Controls for View

Elemento CustomControlName para ExpressionBinding para CustomControl for View

Elemento CustomControlName para ExpressionBinding para GroupBy

Elemento CustomControlName para ExpressionBinding para GroupBy

Elemento Controls

Elemento Name para Control for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento CustomControl para Control
for Controls for View
Artículo • 24/09/2021

Define un control utilizado por la vista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl

Sintaxis
XML

<CustomControl>
<CustomEntries>...</CustomEntries>
</CustomControl>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControl elemento . Solo debe especificar un elemento
secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento CustomEntries para CustomControl for Controls Elemento necesario.


for View
Proporciona las definiciones del
control.

Elementos primarios

Elemento Descripción

Elemento Control para Define un control que puede usar la vista y el nombre que se usa
Controls for View para hacer referencia al control.

Comentarios

Consulte también
Elemento CustomEntries para CustomControl for View

Elemento Control para Controls for View

Escritura de un archivo de formato de PowerShell


Elemento CustomEntries para
CustomControl for Controls for View
Artículo • 25/09/2021

Proporciona las definiciones del control. Este elemento se usa al definir controles que
una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries

Sintaxis
XML

<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del CustomEntries elemento. No hay ningún límite máximo en el
número de elementos secundarios que se pueden especificar.

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento CustomEntry para CustomEntries for Controls for Elemento necesario.


View
Proporciona una definición del
control .

Elementos primarios

Elemento Descripción

Elemento CustomControl para Control for Controls for Define el control utilizado por la
View vista.

Comentarios
En la mayoría de los casos, un control solo tiene una definición, que se especifica en un
único CustomEntry elemento. Sin embargo, es posible proporcionar varias definiciones si
desea usar el mismo control para mostrar diferentes objetos .NET. En esos casos, puede
definir un CustomEntry elemento para cada objeto o conjunto de objetos.

Consulte también
Elemento CustomEntry para CustomEntries for Controls for View

Elemento CustomControl para Control for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento CustomEntry para
CustomEntries for Controls for View
Artículo • 24/09/2021

Proporciona una definición del control . Este elemento se usa al definir controles que
una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry

Sintaxis
XML

<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del CustomEntry elemento.

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento EntrySelectedBy para Elemento opcional.


CustomEntry for Controls for
View Define los tipos de .NET que usan esta definición de control o
la condición que debe existir para que se use esta definición.

Elemento CustomItem para Elemento necesario.


CustomEntry for Controls for
View Define cómo muestra el control los datos.

Elementos primarios

Elemento Descripción

Elemento CustomEntries para CustomControl for View Proporciona las definiciones del control.

Comentarios

Consulte también
Elemento CustomEntries para CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento CustomItem para
CustomEntry for Controls for View
Artículo • 25/09/2021

Define qué datos muestra el control y cómo se muestran. Este elemento se usa al definir
controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem

Sintaxis
XML

<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<NewLine/>
<Text>TextToDisplay</Text>
<Frame>...<Frame>
</CustomItem>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomItem elemento . Para obtener más información, vea la
sección Comentarios.

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento ExpressionBinding para Elemento opcional.


CustomItem for Controls for View
Define los datos que muestra el control .

Elemento Frame para CustomItem for Elemento opcional.


Controls for View
Define cómo se muestran los datos, como desplazar
los datos a la izquierda o a la derecha.

Elemento NewLine para CustomItem for Elemento opcional.


Controls for View
Agrega una línea en blanco a la presentación del
control.

Elemento Text para CustomItem for Elemento opcional.


Controls for View
Agrega texto, como paréntesis o corchetes, a la
presentación del control.

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomEntries for Controls for Proporciona una definición del
View control .

Comentarios
Al especificar los elementos secundarios del elemento, tenga en cuenta CustomItem lo
siguiente:

Los elementos secundarios deben agregarse en la secuencia siguiente:


ExpressionBinding , NewLine , y Text Frame .

No hay ningún límite máximo en el número de secuencias que puede especificar.


En cada secuencia, no hay ningún límite máximo para el número de
ExpressionBinding elementos que puede usar.

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for View
Elemento Frame para CustomItem for Controls for View

Elemento NewLine para CustomItem for Controls for View

Elemento Text para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento ExpressionBinding para
CustomItem for Controls for View
Artículo • 24/09/2021

Define los datos que muestra el control . Este elemento se usa al definir controles que
una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding

Sintaxis
XML

<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate></ScriptBlock>
</ExpressionBinding>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ExpressionBinding elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

CustomControl Element Elemento opcional.

Define un control utilizado por este control.

Elemento CustomControlName para Elemento opcional.


ExpressionBinding for Controls for View
Especifica el nombre de un control común o
un control de vista.

Elemento EnumerateCollection para Elemento opcional.


ExpressionBinding for Controls for View
Especifica que se muestran los elementos de
las colecciones.

Elemento ItemSelectionCondition de Elemento opcional.


ExpressionBinding for Controls for View
Define la condición que debe existir para
que se utilice este control.

Elemento PropertyName para ExpressionBinding Elemento opcional.


for Controls for View
Especifica la propiedad .NET cuyo valor
muestra el control .

Elemento ScriptBlock para ExpressionBinding for Elemento opcional.


Controls for View
Especifica el script cuyo valor muestra el
control .

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra el control y cómo
Controls for View se muestran.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for Controls for View

Elemento CustomControlName para ExpressionBinding for Controls for View

Elemento EnumerateCollection para ExpressionBinding for Controls for View

Elemento ItemSelectionCondition de ExpressionBinding for Controls for View

Elemento PropertyName para ExpressionBinding for Controls for View

Elemento ScriptBlock para ExpressionBinding for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento CustomControlName para
ExpressionBinding for Controls for View
Artículo • 24/09/2021

Especifica el nombre de un control común o un control de vista. Este elemento se usa al


definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento CustomControlName

Sintaxis
XML

<CustomControlName>NameofCustomControl</CustomControlName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControlName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls Define los datos que muestra el
for View control .

Valor de texto
Especifique el nombre del control.

Comentarios
Puede crear controles comunes que puedan usar todas las vistas de un archivo de
formato, y puede crear controles de vista que pueda usar una vista específica. Los
elementos siguientes especifican los nombres de estos controles:

Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Consulte también
Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Elemento ExpressionBinding para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento EnumerateCollection para
ExpressionBinding for Controls for View
Artículo • 24/09/2021

Se especifica que se muestran los elementos de las colecciones. Este elemento se usa al
definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento EnumerateCollection

Sintaxis
XML

<EnumerateCollection/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EnumerateCollection elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls Define los datos que muestra el
for View control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento ItemSelectionCondition para
ExpressionBinding for Controls for View
Artículo • 24/09/2021

Define la condición que debe existir para que se utilice este control. Este elemento se
usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition

Sintaxis
XML

<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ItemSelectionCondition elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para Elemento opcional.


ItemSelectionCondition for Controls for View
Especifica la propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para ItemSelectionCondition Elemento opcional.


for Controls for View
Especifica el script que desencadena la
condición.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls Define los datos que muestra el
for View control .

Comentarios
Puede especificar un nombre de propiedad o un script para esta condición, pero no
puede especificar ambos.

Consulte también
Elemento PropertyName para ItemSelectionCondition for Controls for View

Elemento ScriptBlock para ItemSelectionCondition for Controls for View

Elemento ExpressionBinding para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
ItemSelectionCondition for Controls for
View
Artículo • 24/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa el control .
Este elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition de Define la condición que debe existir para


ExpressionBinding for Controls for View que se utilice este control.

Valor de texto
Especifique el nombre de la propiedad .NET que desencadena la condición.

Comentarios
Si se usa este elemento, no puede especificar el elemento ScriptBlock al definir la
condición de selección.

Consulte también
Elemento ScriptBlock para ItemSelectionCondition for Controls for View

Elemento ItemSelectionCondition de ExpressionBinding for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ItemSelectionCondition for Controls for
View
Artículo • 24/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa el control . Este elemento se usa al definir
controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition de Define la condición que debe existir para


ExpressionBinding for Controls for View que se utilice este control.

Valor de texto
Especifique el script que se evalúa.

Comentarios
Si se usa este elemento, no se puede especificar el elemento PropertyName al definir la
condición de selección.

Consulte también
Elemento PropertyName para ItemSelectionCondition for Controls for View

Elemento ItemSelectionCondition de ExpressionBinding for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
ExpressionBinding for Controls for View
Artículo • 24/09/2021

Especifica la propiedad .NET cuyo valor muestra el control . Este elemento se usa al
definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
ExpressionBinding
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls Define los datos que muestra el
for View control .

Valor de texto
Especifique el nombre de la propiedad .NET cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ExpressionBinding for Controls for View
Artículo • 24/09/2021

Especifica el script cuyo valor muestra el control . Este elemento se usa al definir
controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Controls Define los datos que muestra el
for View control .

Valor de texto
Especifique el script cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento Frame para CustomItem for
Controls for View
Artículo • 24/09/2021

Define cómo se muestran los datos, como desplazar los datos a la izquierda o a la
derecha. Este elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame

Sintaxis
XML

<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Frame elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

CustomItem Element Elemento Required

Elemento FirstLineHanging de Frame of Elemento opcional.


Controls of View
Especifica cuántos caracteres se desplaza la primera
línea a la izquierda.

Elemento FirstLineIndent de Frame of Elemento opcional.


Controls of View
Especifica cuántos caracteres se desplaza la primera
línea a la derecha.

Elemento LeftIndent de Frame of Elemento opcional.


Controls of View
Especifica cuántos caracteres se desplazan los datos
del margen izquierdo.

Elemento RightIndent del marco de Elemento opcional.


controles de vista
Especifica cuántos caracteres se desplazan los datos
del margen derecho.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra el control y cómo
Controls for View se muestran.

Comentarios
No se pueden especificar los elementos FirstLineHanging y FirstLineIndent en el mismo
Frame elemento.

Consulte también
Elemento FirstLineHanging de Frame of Controls of View
Elemento FirstLineIndent de Frame of Controls of View

Elemento LeftIndent de Frame of Controls of View

Elemento RightIndent del marco de controles de vista

Elemento CustomItem para CustomEntry for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento FirstLineHanging para Frame
for Controls for View
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la izquierda. Este


elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineHanging

Sintaxis
XML

<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineHanging elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem Define cómo se muestran los datos, como desplazar los
for Controls for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el elemento FirstLineIndent.

Consulte también
Elemento FirstLineIndent para Frame for Controls for View

Elemento Frame para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento FirstLineIndent para Frame for
Controls for View
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la derecha. Este


elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineIndent

Sintaxis
XML

<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem Define cómo se muestran los datos, como desplazar los
for Controls for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el elemento FirstLineHanging.

Consulte también
Elemento FirstLineHanging para Frame for Controls for View

Elemento Frame para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento LeftIndent para Frame for
Controls for View
Artículo • 24/09/2021

Especifica cuántos caracteres se desplazan los datos del margen izquierdo. Este
elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento LeftIndent

Sintaxis
XML

<LeftIndent>CharactersToShift</LeftIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del LeftIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem Define cómo se muestran los datos, como desplazar los
for Controls for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la izquierda.

Comentarios

Consulte también
Elemento Frame para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento RightIndent para Frame for
Controls for View
Artículo • 24/09/2021

Especifica cuántos caracteres se desplazan los datos del margen derecho. Este elemento
se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento RightIndent

Sintaxis
XML

<RightIndent>CharactersToShift</RightIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del RightIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem Define cómo se muestran los datos, como desplazar los
for Controls for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la derecha.

Comentarios

Consulte también
Elemento Frame para CustomItem for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento NewLine para CustomItem for
Controls for View
Artículo • 27/09/2021

Agrega una línea en blanco a la presentación del control. Este elemento se usa al definir
controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento NewLine

Sintaxis
XML

<NewLine/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del NewLine elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra el control y cómo
Controls for View se muestran.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento Text para CustomItem for
Controls for View
Artículo • 24/09/2021

Especifica el texto que se agrega a los datos que muestra el control, como una etiqueta,
corchetes para incluir los datos y espacios para aplicar sangría a los datos. Este
elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem

Sintaxis
XML

<Text>TextToDisplay</Text>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Text elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra el control y cómo
Controls for View se muestran.

Valor de texto
Especifique el texto de un control para los datos que desea mostrar.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento EntrySelectedBy para
CustomEntry for Controls for View
Artículo • 25/09/2021

Define los tipos de .NET que usan esta definición de control o la condición que debe
existir para que se use esta definición. Este elemento se usa al definir controles que una
vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento . Debe especificar al menos un tipo,
conjunto de selección o condición de selección para una definición. No hay ningún
límite máximo en el número de elementos secundarios que puede usar.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy for Controls for View
Define la condición que debe existir para que se
utilice esta definición.

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy for Controls for View
Especifica un conjunto de tipos de .NET que usan
esta definición del control.

Elemento TypeName para EntrySelectedBy for Elemento opcional.


Controls for View
Especifica un tipo de .NET que usa esta
definición del control.

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomEntries for Controls for Proporciona una definición del
View control .

Comentarios
Las condiciones de selección se usan para definir una condición que debe existir para la
definición que se va a usar, como cuando un objeto tiene una propiedad específica o
cuando un valor de propiedad o script específico se evalúa como true . Para obtener
más información sobre las condiciones de selección, vea Definir condiciones para
cuando seusa una entrada de vista o un elemento .

Consulte también
Elemento CustomEntry para CustomEntries for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy for Controls for View
Artículo • 24/09/2021

Define una condición que debe existir para que se utilice la definición de control. Este
elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionCondition elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para Elemento opcional.


SelectionCondition for Controls for View
Especifica una propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition Elemento opcional.


for Controls for View
Especifica el script que desencadena la
condición.

Elemento SelectionSetName para Elemento opcional.


SelectionCondition for Controls for View
Especifica el conjunto de tipos de .NET que
desencadena la condición.

Elemento TypeName para SelectionCondition for Elemento opcional.


Controls for View
Especifica un tipo de .NET que desencadena la
condición.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para Define los tipos de .NET que usan esta definición de control o
CustomEntry for Controls for la condición que debe existir para que se use esta definición.
View

Comentarios
Al definir una condición de selección, se aplican los siguientes requisitos:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.

Para obtener más información sobre cómo usar condiciones de selección, vea Definición
de condiciones para cuando se muestran datos.
Consulte también
Elemento PropertyName para SelectionCondition for Controls for View

Elemento ScriptBlock para SelectionCondition for Controls for View

Elemento SelectionSetName para SelectionCondition for Controls for View

Elemento TypeName para SelectionCondition for Controls for View

Elemento EntrySelectedBy para CustomEntry for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
SelectionCondition for CustomControl
for View
Artículo • 24/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa la definición.
Este elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que
EntrySelectedBy for CustomControl for View se utilice la definición de control.

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
script, pero no puede especificar ambos. Para obtener más información sobre cómo se
pueden usar las condiciones de selección, vea Definir condiciones para mostrar datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for CustomControl
for View
Artículo • 27/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la definición . Este elemento se usa al definir una
vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que
EntrySelectedBy for CustomControl for View se utilice la definición de control.

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de script o propiedad
para evaluar, pero no puede especificar ambos. Para obtener más información sobre
cómo se pueden usar las condiciones de selección, vea Definir condiciones para mostrar
datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
SelectionCondition for Controls for View
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante este control. Este elemento se usa al definir controles que
una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy for Controls for View utilice la definición de control.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
selección.

La condición de selección puede especificar un conjunto de selección o un tipo de .NET,


pero no puede especificar ambos. Para obtener más información sobre cómo usar las
condiciones de selección, vea Definir condiciones para mostrar datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for View

Definir condiciones para cuando se muestran los datos

Definición de conjuntos de selección

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for Controls for View
Artículo • 24/09/2021

Especifica un tipo de .NET que desencadena la condición. Este elemento se usa al definir
controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy for Controls for View utilice la definición de control.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios

Consulte también
Elemento SelectionCondition para EntrySelectedBy for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy for Controls for View
Artículo • 24/09/2021

Especifica un conjunto de tipos de .NET que usan esta definición del control. Este
elemento se usa al definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
None

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para Define los tipos de .NET que usan esta definición de control o
CustomEntry for Controls for la condición que debe existir para que se use esta definición.
View

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Cada definición de control debe tener al menos un nombre de tipo, un conjunto de
selección o una condición de selección definidos.

Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de


objetos que se usan en varias vistas. Para obtener más información sobre cómo definir
conjuntos de selección, vea Definir conjuntos de selección.

Consulte también
Elemento EntrySelectedBy para CustomEntry for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy for Controls for View
Artículo • 24/09/2021

Especifica un tipo de .NET que usa esta definición del control . Este elemento se usa al
definir controles que una vista puede usar.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy para Define los tipos de .NET que usan esta definición de control o
CustomEntry for Controls for la condición que debe existir para que se use esta definición.
View

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios

Consulte también
Elemento EntrySelectedBy para CustomEntry for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento Name para Control for
Controls for View
Artículo • 27/09/2021

Especifica el nombre del control.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Controls
Elemento Control
Elemento Name

Sintaxis
XML

<Name>ControlName</Name>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Name elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción
Elemento Descripción

Elemento Control para Define un control que puede usar la vista y el nombre que se usa
Controls for View para hacer referencia al control.

Valor de texto
Especifique el nombre que se usa para hacer referencia al control.

Comentarios
El nombre especificado aquí se puede usar en los siguientes elementos para hacer
referencia a este control.

Al crear una tabla, una lista, una vista de control amplia o personalizada, el control
se puede especificar mediante el siguiente elemento: Elemento GroupBy para
View.

Al crear otro control que puede usar una vista, este control se puede especificar
mediante el siguiente elemento: Elemento ExpressionBinding para CustomItem for
Controls for View

Consulte también
Elemento GroupBy para View

Elemento ExpressionBinding para CustomItem for Controls for View

Elemento Control para Controls for View

Escritura de un archivo de formato de PowerShell


Elemento CustomControl para View
Artículo • 24/09/2021

Define un formato de control personalizado para la vista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl

Sintaxis
XML

<CustomControl>
<CustomEntries>...</CustomEntries>
</CustomControl>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControl elemento . Debe especificar un elemento
secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento CustomEntries para Elemento necesario.


CustomControl for View
Proporciona las definiciones de la vista de control
personalizada.
Elementos primarios

Elemento Descripción

Elemento View Define una vista que se usa para mostrar uno o varios objetos .NET.

Comentarios
En la mayoría de los casos, solo se requiere una definición para cada vista de control,
pero es posible proporcionar varias definiciones si desea usar la misma vista para
mostrar diferentes objetos .NET. En esos casos, puede proporcionar una definición
independiente para cada objeto o conjunto de objetos.

Consulte también
Elemento CustomEntries para CustomControl for View

Elemento View

Escritura de un archivo de formato de PowerShell


Elemento CustomEntries para
CustomControl for View
Artículo • 25/09/2021

Proporciona las definiciones de la vista de control personalizada. La vista de control


personalizado debe especificar una o varias definiciones.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries

Sintaxis
XML

<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControlEntries elemento . Debe especificar uno o varios
elementos secundarios.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento CustomEntry para Elemento necesario.


CustomEntries for View
Proporciona una definición de la vista de control
personalizada.

Elementos primarios

Elemento Descripción

Elemento CustomControl para View Elemento necesario.

Define un formato de control personalizado para la vista.

Comentarios
En la mayoría de los casos, un control solo tiene una definición, que se define en un
único CustomEntry elemento. Sin embargo, es posible tener varias definiciones si desea
usar el mismo control para mostrar diferentes objetos .NET. En esos casos, puede definir
un CustomEntry elemento para cada objeto o conjunto de objetos.

Consulte también
Elemento CustomControl para View

Elemento CustomEntry para CustomEntries for View

Escritura de un archivo de formato de PowerShell


Elemento CustomEntry para
CustomEntries for CustomControl for
View
Artículo • 25/09/2021

Proporciona una definición de la vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry

Sintaxis
XML

<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomEntry elemento . Debe especificar los elementos
mostrados por la definición.

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento Elemento opcional.


EntrySelectedBy para
CustomEntry for View Define los tipos de .NET que usan la definición de la vista de control
personalizada o la condición que debe existir para que se use esta
definición.

Elemento CustomItem Define un control para la definición del control personalizado.


para CustomEntry for
View

Elementos primarios

Elemento Descripción

Elemento CustomEntries Proporciona las definiciones de la vista de control personalizada. La


para CustomControl for vista de control personalizada debe especificar una o varias
View definiciones.

Comentarios
En la mayoría de los casos, solo se requiere una definición para cada vista de control
personalizada, pero es posible tener varias definiciones si desea usar la misma vista para
mostrar diferentes objetos .NET. En esos casos, puede proporcionar una definición
independiente para cada objeto o conjunto de objetos.

Consulte también
Elemento CustomControl para View

Elemento CustomItem para CustomEntry for View

Elemento EntrySelectedBy para CustomEntry for View

Escritura de un archivo de formato de PowerShell


Elemento CustomItem para
CustomEntry for CustomControl for
View
Artículo • 24/09/2021

Define qué datos muestra la vista de control personalizada y cómo se muestran. Este
elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem

Sintaxis
XML

<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<Frame>...</Frame>
<NewLine/>
<Text>TextToDisplay</Text>
</CustomItem>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomItem elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento ExpressionBinding para Elemento opcional.


CustomItem for CustomControl for View
Define los datos que muestra el control .

Elemento Frame para CustomItem for Elemento opcional.


CustomControl for View
Define qué datos muestra la vista de control
personalizada y cómo se muestran.

Elemento NewLine para CustomItem for Elemento opcional.


Custom Control for View
Agrega una línea en blanco a la presentación del
control.

Elemento Text para CustomItem for Elemento opcional.


CustomControl for View
Especifica texto adicional a los datos mostrados
por el control .

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomEntries for Proporciona una definición de la vista de


CustomControl for View control personalizada.

Comentarios

Consulte también
Elemento CustomEntry para CustomEntries for View

Elemento ExpressionBinding para CustomItem for CustomControl for View

Elemento Frame para CustomItem for CustomControl for View

Elemento NewLine para CustomItem for CustomControl for View

Elemento Text para CustomItem for CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento ExpressionBinding para
CustomItem for CustomControl for View
Artículo • 24/09/2021

Define los datos que muestra el control . Este elemento se usa al definir una vista de
control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding

Sintaxis
XML

<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate></ScriptBlock>
</ExpressionBinding>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ExpressionBinding elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

CustomControl Element Elemento opcional.

Define un control utilizado por este


control.

Elemento CustomControlName para Elemento opcional.


ExpressionBinding para CustomControl for View
Especifica el nombre de un control común
o un control de vista.

Elemento EnumerateCollection para Elemento opcional.


ExpressionBinding para CustomControl for View
Se especifica que se muestran los
elementos de las colecciones.

Elemento ItemSelectionCondition para Elemento opcional.


ExpressionBinding for CustomControl for View
Define la condición que debe existir para
que se utilice este control.

Elemento PropertyName para ExpressionBinding Elemento opcional.


para CustomControl for View
Especifica la propiedad .NET cuyo valor
muestra el control .

Elemento ScriptBlock para ExpressionBinding for Elemento opcional.


CustomCustomControl for View
Especifica el script cuyo valor muestra el
control .

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry Define qué datos muestra la vista de control
for CustomControl for View personalizada y cómo se muestran.

Comentarios

Consulte también
Elemento CustomControlName para ExpressionBinding para CustomControl for View

Elemento EnumerateCollection para ExpressionBinding para CustomControl for View

Elemento ItemSelectionCondition para ExpressionBinding for CustomControl for View

Elemento PropertyName para ExpressionBinding para CustomControl for View

Elemento ScriptBlock para ExpressionBinding para CustomControl for View

Elemento CustomItem para CustomEntry for CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento CustomControlName para
ExpressionBinding para CustomControl
for View
Artículo • 25/09/2021

Especifica el nombre de un control común o un control de vista. Este elemento se usa al


definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento CustomControlName

Sintaxis
XML

<CustomControlName>NameofCustomControl</CustomControlName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControlName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem Define los datos que muestra el control .

Valor de texto
Especifique el nombre del control.

Comentarios
Puede crear controles comunes que puedan usar todas las vistas de un archivo de
formato y puede crear controles de vista que pueda usar una vista específica. Los
nombres de estos controles se especifican mediante los elementos siguientes.

Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Consulte también
Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Elemento ExpressionBinding para CustomItem

Escritura de un archivo de formato de PowerShell


Elemento EnumerateCollection para
ExpressionBinding para CustomControl
for View
Artículo • 24/09/2021

Especifica que se muestran los elementos de las colecciones. Este elemento se usa al
definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento EnumerateCollection

Sintaxis
XML

<EnumerateCollection/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EnumerateCollection elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem Define los datos que muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem

Escritura de un archivo de formato de PowerShell


Elemento ItemSelectionCondition para
ExpressionBinding para CustomControl
Artículo • 24/09/2021

Define la condición que debe existir para que se utilice este control. No hay ningún
límite en el número de condiciones de selección que se pueden especificar para un
elemento de control. Este elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition

Sintaxis
XML

<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ItemSelectionCondition elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para ItemSelectionCondition Elemento opcional.


for CustomControl for View (formato)
Especifica la propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para ItemSelectionCondition for Elemento opcional.


CustomControl for View
Especifica el script que desencadena la
condición.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem para Define los datos que muestra el
CustomControl for View control .

Comentarios
Puede especificar un nombre de propiedad o un script para esta condición, pero no
puede especificar ambos.

Consulte también
Escritura de un archivo de formato de PowerShell

Elemento ExpressionBinding para CustomItem para CustomControl for View


Elemento PropertyName para
ItemSelectionCondition for
CustomControl for View
Artículo • 24/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa el control .
Este elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries para CustomControl for View
Elemento CustomEntry para CustomEntries for View
Elemento CustomItem para CustomEntry for View
Elemento ExpressionBinding para CustomItem for CustomControl for View
Elemento ItemSelectionCondition para el enlace de expresiones para
CustomControl for View
Elemento PropertyName para ItemSelectionCondition for CustomControl for View
(formato)

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para el enlace de Define la condición que debe existir


expresiones para CustomControl for View para que se utilice este control.

Valor de texto
Especifique el nombre de la propiedad .NET que desencadena la condición.

Comentarios
Si se usa este elemento, no puede especificar el elemento ScriptBlock al definir la
condición de selección.

Consulte también
Elemento ScriptBlock para ItemSelectionCondition for CustomControl for View

Elemento ItemSelectionCondition para el enlace de expresiones para CustomControl for


View

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ItemSelectionCondition for
CustomControl for View
Artículo • 27/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa el control . Este elemento se usa al definir una
vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para el enlace de Define la condición que debe existir


expresiones para CustomControl for View para que se utilice este control.

Valor de texto
Especifique el script que se evalúa.

Comentarios
Si se usa este elemento, no se puede especificar el elemento PropertyName al definir la
condición de selección.

Consulte también
Elemento PropertyName para ItemSelectionCondition for CustomControl for View

Elemento ItemSelectionCondition para el enlace de expresiones para CustomControl for


View

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
ExpressionBinding para CustomControl
for View
Artículo • 27/09/2021

Especifica la propiedad .NET cuyo valor muestra el control . Este elemento se usa al
definir una vista de control personalizada

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem for Define los datos que muestra el
CustomControl for View control .

Valor de texto
Especifique el nombre de la propiedad .NET cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem for CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ExpressionBinding para CustomControl
for View
Artículo • 27/09/2021

Especifica el script cuyo valor muestra el control . Este elemento se usa al definir una
vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem para Define los datos que muestra el
CustomControl for View control .

Valor de texto
Especifique el script cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem para CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento Frame para CustomItem para
CustomControl for View
Artículo • 24/09/2021

Define cómo se muestran los datos, como desplazar los datos a la izquierda o a la
derecha. Este elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame

Sintaxis
XML

<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Frame elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

CustomItem Element Elemento Required

Elemento Elemento opcional.


FirstLineHanging
Especifica cuántos caracteres se desplaza la primera línea de datos a la
izquierda.

Elemento Elemento opcional.


FirstLineIndent
Especifica cuántos caracteres se desplaza la primera línea de datos a la
derecha.

Elemento LeftIndent Elemento opcional.

Especifica cuántos caracteres se desplazan los datos del margen


izquierdo.

Elemento RightIndent Elemento opcional.

Especifica cuántos caracteres se desplazan los datos del margen


derecho.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define qué datos muestra el control y cómo se
View muestran.

Comentarios
No se pueden especificar los elementos FirstLineHanging y FirstLineIndent en el mismo
Frame elemento.

Consulte también
Elemento FirstLineHanging

Elemento FirstLineIndent

Elemento LeftIndent
Elemento RightIndent

Elemento CustomItem para CustomEntry for View

Escritura de un archivo de formato de PowerShell


Elemento FirstLineHanging para Frame
para CustomControl
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la izquierda. Este


elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineHanging

Sintaxis
XML

<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineHanging elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem para Define cómo se muestran los datos, como desplazar los
CustomControl for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el elemento FirstLineIndent.

Consulte también
Elemento FirstLineIndent para Frame for CustomControl for View

Elemento Frame para CustomItem para CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento FirstLineIndent para Frame for
CustomControl for View
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la derecha. Este


elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineIndent

Sintaxis
XML

<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem para Define cómo se muestran los datos, como desplazar los
CustomControl for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el elemento FirstLineHanging.

Consulte también
Elemento FirstLineHanging para Frame for CustomControl for View

Elemento Frame para CustomItem para CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento LeftIndent para Frame for
CustomControl for View
Artículo • 24/09/2021

Especifica cuántos caracteres se desplazan los datos del margen izquierdo. Este
elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento LeftIndent

Sintaxis
XML

<LeftIndent>CharactersToShift</LeftIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del LeftIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem para Define cómo se muestran los datos, como desplazar los
CustomControl for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la izquierda.

Comentarios

Consulte también
Elemento Frame para CustomItem para CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento RightIndent para Frame for
CustomControl for View
Artículo • 27/09/2021

Especifica cuántos caracteres se desplazan los datos del margen derecho. Este elemento
se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento RightIndent

Sintaxis
XML

<RightIndent>CharactersToShift</RightIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del RightIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Frame para CustomItem para Define cómo se muestran los datos, como desplazar los
CustomControl for View datos a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la derecha.

Comentarios

Consulte también
Elemento Frame para CustomItem para CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento NewLine para CustomItem for
CustomControl for View
Artículo • 24/09/2021

Agrega una línea en blanco a la presentación del control. Este elemento se usa al definir
una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento NewLine

Sintaxis
XML

<NewLine/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del NewLine elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define un control para la vista de control
View personalizada.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for View

Escritura de un archivo de formato de PowerShell


Elemento Text para CustomItem para
CustomView for View
Artículo • 24/09/2021

Especifica el texto que se agrega a los datos que muestra el control, como una etiqueta,
corchetes para incluir los datos y espacios para aplicar sangría a los datos. Este
elemento se usa al definir una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Text

Sintaxis
XML

<Text>TextToDisplay</Text>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Text elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry for Define un control para la vista de control
View personalizada.

Valor de texto
Especifique el texto de un control para los datos que desea mostrar.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry for View

Escritura de un archivo de formato de PowerShell


Elemento EntrySelectedBy para
CustomEntry for CustomControl for
View
Artículo • 24/09/2021

Define los tipos de .NET que usan esta entrada personalizada o la condición que debe
existir para que se use esta entrada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy for CustomEntry
Define la condición que debe existir para que se
utilice esta definición.

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy for CustomEntry
Especifica un conjunto de tipos de .NET que usan esta
definición de la vista de control.

Elemento TypeName para Elemento opcional.


EntrySelectedBy for CustomEntry
Especifica un tipo de .NET que usa esta definición de
la vista de control.

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomEntries Define los controles utilizados por objetos .NET
for View específicos.

Comentarios
Debe especificar al menos un tipo, conjunto de selección o condición de selección para
una entrada. No hay ningún límite máximo en el número de elementos secundarios que
puede usar.

Las condiciones de selección se usan para definir una condición que debe existir para la
entrada que se va a usar, como cuando un objeto tiene una propiedad específica o
cuando un valor de propiedad o script específico se evalúa como true . Para obtener
más información sobre las condiciones de selección, vea Definir condiciones para
cuando se usa una entrada de vista o un elemento.

Para obtener más información sobre los componentes de una vista de control
personalizado, vea Vista de control personalizado.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for CustomEntry

Elemento SelectionSetName para EntrySelectedBy for CustomEntry

Elemento TypeName para EntrySelectedBy for CustomEntry

Elemento CustomEntry para CustomEntries for View

Vista de control personalizado

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy para CustomControl
Artículo • 24/09/2021

Define una condición que debe existir para que se utilice una definición de control. Este
elemento se usa al definir una vista de control personalizada.

Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionCondition elemento .

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento PropertyName para SelectionCondition Elemento opcional.


for CustomControl for View
Especifica una propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition for Elemento opcional.


CustomControl for View
Especifica el script que desencadena la
condición.

Elemento SelectionSetName para Elemento opcional.


SelectionCondition for Custom Control for View
Especifica el conjunto de tipos de .NET que
desencadena la condición.

Elemento TypeName para SelectionCondition for Elemento opcional.


CustomControl for View
Especifica un tipo de .NET que desencadena
la condición.

Elementos primarios
| Elemento| Descripción| |-------------|-----------------| | Elemento EntrySelectedBy para
CustomEntry for CustomControl for View | Define los tipos de .NET que usan esta
definición de control o la condición que debe existir para que se use esta definición.|

Comentarios
Al definir una condición de selección, se aplican los siguientes requisitos:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.

Para obtener más información sobre cómo usar las condiciones de selección, vea Definir
condiciones para cuando se muestran los datos.

Consulte también
Elemento PropertyName para SelectionCondition for CustomControl for View

Elemento ScriptBlock para SelectionCondition for CustomControl for View


Elemento SelectionSetName para SelectionCondition for Custom Control for View

Elemento TypeName para SelectionCondition for CustomControl for View

Elemento EntrySelectedBy para CustomEntry for CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
SelectionCondition for EntrySelectedBy
for EnumerableExpansion
Artículo • 24/09/2021

Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad


está presente o cuando se evalúa como true , se cumple la condición y se usa la
definición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para expandir
EntrySelectedBy for EnumerableExpansion los objetos de colección de esta definición.

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
script para evaluar, pero no puede especificar ambos. Para obtener más información
sobre cómo usar condiciones de selección, vea Definición de condiciones para cuando
se muestran datos.

Consulte también
Definir condiciones para cuando se muestran los datos

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for


EnumerableExpansion

Elemento SelectionCondition para EntrySelectedBy for EnumerableExpansion

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for EntrySelectedBy
for EnumerableExpansion
Artículo • 24/09/2021

Especifica el script que desencadena la condición.

Schema
Elemento de configuración
Elemento DefaultSettings
Elemento EnumerableExpansions
Elemento EnumerableExpansion
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para expandir
EntrySelectedBy for EnumerableExpansion los objetos de colección de esta definición.

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de script o propiedad
para evaluar, pero no puede especificar ambos. Para obtener más información sobre
cómo usar condiciones de selección, vea Definición de condiciones para cuando se
muestran datos.

Consulte también
Definir condiciones para cuando se muestran los datos

Elemento PropertyName para SelectionCondition for EntrySelectedBy for


EnumerableExpansion

Elemento SelectionCondition para EntrySelectedBy for EnumerableExpansion

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
SelectionCondition for CustomControl
for View
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante este control. Este elemento se usa al definir una vista de
control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que
EntrySelectedBy for CustomControl for View se utilice la definición de control.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
objetos.

La condición de selección puede especificar un conjunto de selección o un tipo de .NET,


pero no puede especificar ambos. Para obtener más información sobre cómo usar las
condiciones de selección, vea Definir condiciones para cuando se muestran los datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for CustomControl for View

Definir condiciones para cuando se muestran los datos

Definición de conjuntos de selección

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for CustomControl
for View
Artículo • 24/09/2021

Especifica un tipo de .NET que desencadena la condición. Este elemento se usa al definir
una vista de control personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que
EntrySelectedBy for CustomControl for View se utilice la definición de control.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios

Consulte también
Elemento SelectionCondition para EntrySelectedBy for CustomControl for View

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy for CustomControl for
View
Artículo • 24/09/2021

Especifica un conjunto de objetos .NET para la entrada de lista. No hay ningún límite en
el número de conjuntos de selección que se pueden especificar para una entrada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy Define los tipos de .NET que usan esta entrada personalizada o la
para CustomEntry for View condición que debe existir para que se use esta entrada.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Cada entrada de control personalizado debe tener al menos un nombre de tipo, un
conjunto de selección o una condición de selección definidos.

Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de


objetos que se usan en varias vistas. Por ejemplo, puede crear una vista de tabla y una
vista de lista para el mismo conjunto de objetos. Para obtener más información sobre
cómo definir conjuntos de selección, vea Definición de conjuntos de selección.

Para obtener más información sobre los componentes de una vista de control
personalizado, vea Crear controles personalizados.

Consulte también
Elemento EntrySelectedBy para CustomEntry for View

Vista de control personalizado

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy for CustomEntry for
View
Artículo • 24/09/2021

Especifica un tipo de .NET que usa esta definición de la vista de control personalizada.
No hay ningún límite en el número de tipos que se pueden especificar para una
definición.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta definición de vista de control
EntrySelectedBy para personalizada o la condición que debe existir para que se use esta
CustomEntry for View definición.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
Cada definición de vista de control personalizada debe tener al menos un nombre de
tipo, un conjunto de selección o una condición de selección definidos.

Para obtener más información sobre los componentes de una vista de control
personalizada, vea Crear controles personalizados.

Consulte también
Creación de controles personalizados

Elemento EntrySelectedBy para CustomEntry for View

Escritura de un archivo de formato de PowerShell


Elemento GroupBy para View
Artículo • 24/09/2021

Define cómo se muestra un nuevo grupo de objetos. Este elemento se usa al definir una
tabla, una lista, una vista de control amplia o personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy

Sintaxis
XML

<GroupBy>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
<Label>TextToDisplay</Label>
<CustomControl>...</CustomControl>
<CustomControlName>NameOfControl</CustomControlName>
</GroupBy>

Atributos y elementos
En las siguientes secciones se describen los atributos, los elementos secundarios y los
elementos primarios.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento CustomControl para Elemento opcional.


GroupBy
Define el control personalizado que muestra los nuevos
grupos.

Elemento CustomControlName Elemento opcional.


para GroupBy
Especifica el nombre de un control que se usa para mostrar el
nuevo grupo.

Elemento Label para GroupBy Elemento opcional.

Especifica una etiqueta que se muestra cuando se encuentra


un nuevo grupo.

Elemento PropertyName para Elemento opcional.


GroupBy
Especifica la propiedad .NET que inicia un nuevo grupo cada
vez que cambia su valor.

Elemento ScriptBlock para Elemento opcional.


GroupBy
Especifica el script que inicia un nuevo grupo cada vez que
cambia su valor.

Elementos primarios

Elemento Descripción

Elemento View Define una vista que muestra uno o varios objetos .NET.

Comentarios
Al definir cómo se muestra un nuevo grupo de objetos, debe especificar la propiedad o
el script que iniciará el nuevo grupo. sin embargo, no puede especificar ambos.

Consulte también
Elemento CustomControlName para GroupBy

Elemento Label para GroupBy

Elemento PropertyName para GroupBy


Elemento ScriptBlock para GroupBy

Elemento View

Escritura de un archivo de formato de PowerShell


Elemento CustomControl para GroupBy
Artículo • 25/09/2021

Define el control personalizado que muestra el nuevo grupo.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl

Sintaxis
XML

<CustomControl>
<CustomEntries>...</CustomEntries>
<CustomControl>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControl elemento . Puede especificar cualquier número de
elementos secundarios y enumerarlos en cualquier orden.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento CustomEntries para CustomControl para Elemento necesario.


GroupBy
Proporciona las definiciones del
control.
Elementos primarios

Elemento Descripción

Elemento GroupBy para Define cómo Windows PowerShell muestra un nuevo grupo de
View objetos.

Comentarios

Consulte también
Elemento CustomEntries para CustomControl para GroupBy

Elemento GroupBy para View

Escritura de un archivo de formato de PowerShell


Elemento CustomEntries para
CustomControl para GroupBy
Artículo • 24/09/2021

Proporciona las definiciones del control. Este elemento se usa al definir cómo se
muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries

Sintaxis
XML

<CustomEntries>
<CustomEntry>...</CustomEntry>
</CustomEntries>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del CustomEntries elemento. No hay ningún límite máximo en el
número de elementos secundarios que se pueden especificar.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento CustomEntry para CustomControl para Elemento necesario.


GroupBy
Proporciona una definición del control
.

Elementos primarios

Elemento Descripción

Elemento CustomControl para Define el control personalizado que muestra el nuevo


GroupBy grupo.

Comentarios
En la mayoría de los casos, un control solo tiene una definición, que se especifica en un
solo CustomEntry elemento. Sin embargo, es posible proporcionar varias definiciones si
desea usar el mismo control para mostrar grupos diferentes. En esos casos, puede
definir un CustomEntry elemento para un grupo.

Consulte también
Elemento CustomEntry para CustomEntries for Controls for View

Elemento CustomControl para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento CustomEntry para
CustomControl para GroupBy
Artículo • 25/09/2021

Proporciona una definición del control . Este elemento se usa al definir cómo se muestra
un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry

Sintaxis
XML

<CustomEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<CustomItem>...</CustomItem>
</CustomEntry>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del CustomEntry elemento.

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento EntrySelectedBy Elemento opcional.


para CustomEntry for
GroupBy Define los tipos de .NET que usan esta definición de control o la
condición que debe existir para que se use esta definición.

Elemento CustomItem para Elemento necesario.


CustomEntry para GroupBy
Define cómo muestra el control los datos.

Elementos primarios

Elemento Descripción

Elemento CustomEntries para CustomControl para Proporciona las definiciones del


GroupBy control.

Comentarios

Consulte también
Elemento EntrySelectedBy para CustomEntry for GroupBy

Elemento CustomItem para CustomEntry para GroupBy

Elemento CustomEntries para CustomControl para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento CustomItem para
CustomEntry para GroupBy
Artículo • 25/09/2021

Define qué datos muestra la vista de control personalizada y cómo se muestran. Este
elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomItem

Sintaxis
XML

<CustomItem>
<ExpressionBinding>...</ExpressionBinding>
<Frame>...</Frame>
<NewLine/>
<Text>TextToDisplay</Text>
</CustomItem>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomItem elemento .

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento ExpressionBinding para Elemento opcional.


CustomItem para GroupBy
Define los datos que muestra el control .

Elemento Frame para CustomItem para Elemento opcional.


GroupBy
Define qué datos muestra la vista de control
personalizada y cómo se muestran.

Elemento NewLine para CustomItem Elemento opcional.


para GroupBy
Agrega una línea en blanco a la presentación del
control.

Elemento Text para CustomItem para Elemento opcional.


GroupBy
Especifica texto adicional a los datos mostrados por el
control .

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomControl Proporciona una definición de la vista de control


para GroupBy personalizada.

Comentarios

Consulte también
Elemento CustomEntry para CustomControl para GroupBy

Elemento ExpressionBinding para CustomItem para GroupBy

Elemento Frame para CustomItem para GroupBy

Elemento NewLine para CustomItem para GroupBy

Elemento Text para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento ExpressionBinding para
CustomItem para GroupBy
Artículo • 24/09/2021

Define los datos que muestra el control . Este elemento se usa al definir cómo se
muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding

Sintaxis
XML

<ExpressionBinding>
<CustomControl>...</CustomControl>
<CustomControlName>NameofCommonCustomControl</CustomControlName>
<EnumerateCollection/>
<ItemSelectionCondition>...</ItemSelectionCondition>
<PropertyName>Nameof.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate></ScriptBlock>
</ExpressionBinding>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ExpressionBinding elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

CustomControl Element Elemento opcional.

Define un control utilizado por


este control.

Elemento CustomControlName para ExpressionBinding para Elemento opcional.


GroupBy
Especifica el nombre de un
control común o un control de
vista.

Elemento EnumerateCollection para ExpressionBinding para Elemento opcional.


GroupBy Elemento EnumerateCollection para ExpressionBinding
para GroupBy Se especifica que se muestran
los elementos de las
colecciones.

Elemento ItemSelectionCondition para ExpressionBinding para Elemento opcional.


GroupBy
Define la condición que debe
existir para que se utilice este
control.

Elemento PropertyName para ExpressionBinding para GroupBy Elemento opcional.

Especifica la propiedad .NET


cuyo valor muestra el control .

Elemento ScriptBlock para ExpressionBinding para GroupBy Elemento opcional.

Especifica el script cuyo valor


muestra el control .

Elementos primarios

Elemento Descripción

Elemento CustomItem para Define qué datos muestra la vista de control


CustomEntry para GroupBy personalizada y cómo se muestran.
Consulte también
Elemento CustomControlName para ExpressionBinding para GroupBy

Elemento EnumerateCollection para ExpressionBinding para GroupBy

Elemento ItemSelectionCondition para ExpressionBinding para GroupBy

Elemento PropertyName para ExpressionBinding para GroupBy

Elemento ScriptBlock para ExpressionBinding para GroupBy

Elemento CustomItem para CustomEntry para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento CustomControlName para
ExpressionBinding para GroupBy
Artículo • 24/09/2021

Especifica el nombre de un control común o un control de vista. Este elemento se usa al


definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento CustomControlName

Sintaxis
XML

<CustomControlName>NameofCustomControl</CustomControlName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del CustomControlName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem para Define los datos que muestra el
GroupBy control .

Valor de texto
Especifique el nombre del control.

Comentarios
Puede crear controles comunes que puedan usar todas las vistas de un archivo de
formato, y puede crear controles de vista que pueda usar una vista específica. Los
elementos siguientes especifican los nombres de estos controles:

Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Consulte también
Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Elemento ExpressionBinding para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento EnumerateCollection para
ExpressionBinding para GroupBy
Artículo • 24/09/2021

Especifica que se muestran los elementos de las colecciones. Este elemento se usa al
definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento EnumerateCollection

Sintaxis
XML

<EnumerateCollection/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EnumerateCollection elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem para Define los datos que muestra el
GroupBy control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento ItemSelectionCondition para
ExpressionBinding para GroupBy
Artículo • 24/09/2021

Define la condición que debe existir para que se utilice este control. No hay ningún
límite en el número de condiciones de selección que se pueden especificar para un
elemento de control. Este elemento se usa al definir cómo se muestra un nuevo grupo
de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition

Sintaxis
XML

<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ItemSelectionCondition elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento PropertyName para Elemento opcional.


ItemSelectionCondition for GroupBy
Especifica la propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para Elemento opcional.


ItemSelectionCondition para GroupBy
Especifica el script que desencadena la
condición.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem para Define los datos que muestra el
GroupBy control .

Comentarios
Puede especificar un nombre de propiedad o un script para esta condición, pero no
puede especificar ambos.

Consulte también
Escritura de un archivo de formato de PowerShell

Elemento ExpressionBinding para CustomItem para GroupBy


Elemento PropertyName para
ItemSelectionCondition para GroupBy
Artículo • 24/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa el control .
Este elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para Define la condición que debe existir para que
ExpressionBinding para GroupBy se utilice este control.

Valor de texto
Especifique el nombre de la propiedad .NET que desencadena la condición.

Comentarios
Si se usa este elemento, no puede especificar el elemento ScriptBlock al definir la
condición de selección.

Consulte también
Elemento ScriptBlock para ItemSelectionCondition para GroupBy

Elemento ItemSelectionCondition para ExpressionBinding para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ItemSelectionCondition para GroupBy
Artículo • 24/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa el control . Este elemento se usa al definir cómo

se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ItemSelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para Define la condición que debe existir para que
ExpressionBinding para GroupBy se utilice este control.

Valor de texto
Especifique el script que se evalúa.

Comentarios
Si se usa este elemento, no se puede especificar el elemento PropertyName al definir la
condición de selección.

Consulte también
Elemento ItemSelectionCondition para ExpressionBinding para GroupBy

Elemento PropertyName para ItemSelectionCondition for GroupBy

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
ExpressionBinding para GroupBy
Artículo • 24/09/2021

Especifica la propiedad .NET cuyo valor muestra el control . Este elemento se usa al
definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem para Define los datos que muestra el
GroupBy control .

Valor de texto
Especifique el nombre de la propiedad .NET cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ExpressionBinding para GroupBy
Artículo • 27/09/2021

Especifica el script cuyo valor muestra el control . Este elemento se usa al definir cómo
se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento ExpressionBinding
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ExpressionBinding para CustomItem para Define los datos que muestra el
GroupBy control .

Valor de texto
Especifique el script cuyo valor muestra el control .

Comentarios

Consulte también
Elemento ExpressionBinding para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento Frame para CustomItem para
GroupBy
Artículo • 24/09/2021

Define cómo se muestran los datos, como desplazar los datos a la izquierda o a la
derecha. Este elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame

Sintaxis
XML

<Frame>
<LeftIndent>NumberOfCharactersToShift</LeftIndent>
<RightIndent>NumberOfCharactersToShift</RightIndent>
<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>
<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>
<CustomItem>...</CustomItem>
</Frame>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Frame elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

CustomItem Element Elemento Required

Elemento FirstLineHanging para Frame for Elemento opcional.


GroupBy
Especifica cuántos caracteres se desplaza la primera
línea de datos a la izquierda.

Elemento FirstLineIndent para Frame for Elemento opcional.


GroupBy
Especifica cuántos caracteres se desplaza la primera
línea de datos a la derecha.

Elemento LeftIndent para Frame for Elemento opcional.


GroupBy
Especifica cuántos caracteres se desplazan los
datos del margen izquierdo.

Elemento RightIndent para Frame for Elemento opcional.


GroupBy Elemento RightIndent
Especifica cuántos caracteres se desplazan los
datos del margen derecho.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry para Define qué datos muestra el control y cómo se
GroupBy muestran.

Comentarios
No se pueden especificar los elementos FirstLineHanging y FirstLineIndent en el mismo
Frame elemento.

Consulte también
Elemento FirstLineHanging para Frame for GroupBy

Elemento FirstLineIndent para Frame for GroupBy

Elemento LeftIndent para Frame for GroupBy


Elemento RightIndent para Frame for GroupBy

Elemento CustomItem para CustomEntry para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento FirstLineHanging para Frame
for GroupBy
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la izquierda. Este


elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineHanging

Sintaxis
XML

<FirstLineHanging>NumberOfCharactersToShift</FirstLineHanging>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineHanging elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para Define cómo se muestran los datos, como desplazar los datos
CustomItem para GroupBy a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el elemento FirstLineIndent.

Consulte también
Elemento FirstLineIndent para Frame for GroupBy

Elemento Frame para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento FirstLineIndent para Frame for
GroupBy
Artículo • 24/09/2021

Especifica cuántos caracteres se desplaza la primera línea de datos a la derecha. Este


elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy para View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento FirstLineIndent

Sintaxis
XML

<FirstLineIndent>NumberOfCharactersToShift</FirstLineIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FirstLineIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para Define cómo se muestran los datos, como desplazar los datos
CustomItem para GroupBy a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar la primera línea de los datos.

Comentarios
Si se especifica este elemento, no se puede especificar el elemento FirstLineHanging.

Consulte también
Elemento FirstLineHanging para Frame for GroupBy

Elemento Frame para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento LeftIndent para Frame
Artículo • 27/09/2021

Especifica cuántos caracteres se desplazan los datos del margen izquierdo. Este
elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento LeftIndent

Sintaxis
XML

<LeftIndent>CharactersToShift</LeftIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del LeftIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Frame para Define cómo se muestran los datos, como desplazar los datos
CustomItem para GroupBy a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la izquierda.

Comentarios

Consulte también
Elemento Frame para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento RightIndent para Frame for
GroupBy
Artículo • 24/09/2021

Especifica cuántos caracteres se desplazan los datos del margen derecho. Este elemento
se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Frame
Elemento RightIndent

Sintaxis
XML

<RightIndent>CharactersToShift</RightIndent>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del RightIndent elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Frame para Define cómo se muestran los datos, como desplazar los datos
CustomItem para GroupBy a la izquierda o a la derecha.

Valor de texto
Especifique el número de caracteres que desea desplazar los datos a la derecha.

Comentarios

Consulte también
Elemento Frame para CustomItem para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento NewLine para CustomItem
para GroupBy
Artículo • 27/09/2021

Agrega una línea en blanco a la presentación del control. Este elemento se usa al definir
cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento NewLine

Sintaxis
XML

<NewLine/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del NewLine elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry para Define un control para la vista de control
GroupBy personalizada.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento Text para CustomItem para
GroupBy
Artículo • 24/09/2021

Especifica el texto que se agrega a los datos que muestra el control, como una etiqueta,
corchetes para incluir los datos y espacios para aplicar sangría a los datos. Este
elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento CustomItem
Elemento Text

Sintaxis
XML

<Text>TextToDisplay</Text>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Text elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento CustomItem para CustomEntry para Define un control para la vista de control
GroupBy personalizada.

Valor de texto
Especifique el texto de un control para los datos que desea mostrar.

Comentarios

Consulte también
Elemento CustomItem para CustomEntry para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento EntrySelectedBy para
CustomEntry for GroupBy
Artículo • 24/09/2021

Define los tipos de .NET que usan esta definición de control o la condición que debe
existir para que se use esta definición. Este elemento se usa al definir cómo se muestra
un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy para View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento . Debe especificar al menos un tipo,
conjunto de selección o condición de selección para una definición. No hay ningún
límite máximo en el número de elementos secundarios que puede usar.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy para GroupBy
Define la condición que debe existir para que se
utilice esta definición.

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy para GroupBy
Especifica un conjunto de tipos de .NET que usan
esta definición del control.

Elemento TypeName para EntrySelectedBy Elemento opcional.


para GroupBy
Especifica un tipo de .NET que usa esta definición
del control.

Elementos primarios

Elemento Descripción

Elemento CustomEntry para CustomControl para Proporciona una definición del control
GroupBy .

Comentarios
Las condiciones de selección se usan para definir una condición que debe existir para la
definición que se va a usar, como cuando un objeto tiene una propiedad específica o
cuando un valor de propiedad o script específico se evalúa como true . Para obtener
más información sobre las condiciones de selección, vea Definir condiciones para
cuando seusa una entrada de vista o un elemento .

Consulte también
Elemento SelectionCondition para EntrySelectedBy para GroupBy

Elemento SelectionSetName para EntrySelectedBy para GroupBy

Elemento TypeName para EntrySelectedBy para GroupBy


Elemento CustomEntry para CustomEntries for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy for GroupBy
Artículo • 24/09/2021

Define una condición que debe existir para que se utilice una definición de control. Este
elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy para View
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionCondition elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para Elemento opcional.


SelectionCondition for GroupBy
Especifica una propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition Elemento opcional.


for GroupBy
Especifica el script que desencadena la
condición.

Elemento SelectionSetName para Elemento opcional.


SelectionCondition for GroupBy
Especifica el conjunto de tipos de .NET que
desencadena la condición.

Elemento TypeName para SelectionCondition Elemento opcional.


for GroupBy
Especifica un tipo de .NET que desencadena la
condición.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy Define los tipos de .NET que usan esta definición de control o la
para CustomEntry for condición que debe existir para que se use esta definición.
GroupBy

Comentarios
Al definir una condición de selección, se aplican los siguientes requisitos:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.

La condición de selección puede especificar cualquier número de tipos o conjuntos


de selección de .NET, pero no puede especificar

Ambos. Para obtener más información sobre cómo usar condiciones de selección,
vea Definición de condiciones para cuando se muestran datos.
Consulte también
Elemento PropertyName para SelectionCondition for CustomControl for View

Elemento ScriptBlock para SelectionCondition for CustomControl for View

Elemento SelectionSetName para SelectionCondition for Custom Control for View

Elemento TypeName para SelectionCondition for GroupBy

Elemento EntrySelectedBy para CustomEntry for GroupBy

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
SelectionCondition for GroupBy
Artículo • 24/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa la definición.
Este elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy para GroupBy utilice la definición de control.

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
script, pero no puede especificar ambos. Para obtener más información sobre cómo se
pueden usar las condiciones de selección, vea Definir condiciones para mostrar datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for EntrySelectedBy
for GroupBy
Artículo • 27/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la definición . Este elemento se usa al definir
cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy for GroupBy utilice la definición de control.

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de script o propiedad
para evaluar, pero no puede especificar ambos. Para obtener más información sobre
cómo se pueden usar las condiciones de selección, vea Definir condiciones para mostrar
datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy for GroupBy

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
SelectionCondition for GroupBy
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante este control. Este elemento se usa al definir cómo se
muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy para GroupBy utilice la definición de control.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
selección.

Cuando se especifica este elemento, no se puede especificar el elemento TypeName.


Para obtener más información sobre cómo definir condiciones de selección, vea Definir
condiciones para mostrar datos.

Consulte también
Elemento TypeName para SelectionCondition for GroupBy

Elemento SelectionCondition para EntrySelectedBy para GroupBy

Definir condiciones para cuando se muestran los datos

Definición de conjuntos de selección

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for GroupBy
Artículo • 27/09/2021

Especifica un tipo de .NET que desencadena la condición. Este elemento se usa al definir
cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define una condición que debe existir para que se
EntrySelectedBy para GroupBy utilice la definición de control.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
Cuando se especifica este elemento, no se puede especificar el SelectionSetName
elemento . Para obtener más información sobre cómo definir condiciones de selección,
vea Definir condiciones para mostrar datos.

Consulte también
Elemento SelectionCondition para EntrySelectedBy para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy for GroupBy
Artículo • 24/09/2021

Especifica un conjunto de objetos .NET para la entrada de lista. No hay ningún límite en
el número de conjuntos de selección que se pueden especificar para una entrada. Este
elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy Define los tipos de .NET que usan esta entrada personalizada o la
para CustomEntry for condición que debe existir para que se use esta entrada.
GroupBy

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Cada definición de control personalizado debe tener al menos un nombre de tipo, un
conjunto de selección o una condición de selección definidos.

Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de


objetos que se usan en varias vistas. Por ejemplo, puede crear una vista de tabla y una
vista de lista para el mismo conjunto de objetos. Para obtener más información sobre
cómo definir conjuntos de selección, vea Definición de conjuntos de selección.

Para obtener más información sobre los componentes de una vista de control
personalizado, vea Crear controles personalizados.

Consulte también
Elemento EntrySelectedBy para CustomEntry for GroupBy

Creación de controles personalizados

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy para GroupBy
Artículo • 24/09/2021

Especifica un tipo de .NET que usa esta definición del control personalizado. Este
elemento se usa al definir cómo se muestra un nuevo grupo de objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControl
Elemento CustomEntries
Elemento CustomEntry
Elemento EntrySelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy Define los tipos de .NET que usan esta definición de control o la
para CustomEntry for condición que debe existir para que se use esta definición.
GroupBy

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
Cada definición de control debe tener al menos un nombre de tipo, un conjunto de
selección o una condición de selección definidos.

Para obtener más información sobre los componentes de una vista de control
personalizado, vea Crear controles personalizados.

Consulte también
Creación de controles personalizados

Elemento EntrySelectedBy para CustomEntry for GroupBy

Escritura de un archivo de formato de PowerShell


Elemento CustomControlName para
GroupBy
Artículo • 25/09/2021

Especifica el nombre de un control personalizado que se usa para mostrar el nuevo


grupo. Este elemento se usa al definir una tabla, una lista, una vista de control amplia o
personalizada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento CustomControlName

Sintaxis
XML

<CustomControlName>ControlName</CustomControlName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del CustomControlName elemento.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios
Elemento Descripción

Elemento GroupBy para Define cómo Windows PowerShell muestra un nuevo grupo de
View objetos.

Valor de texto
Especifique el nombre del control personalizado que se usa para mostrar un nuevo
grupo.

Comentarios
Puede crear controles comunes que puedan usar todas las vistas de un archivo de
formato, y puede crear controles de vista que pueda usar una vista específica. Los
elementos siguientes especifican los nombres de estos controles personalizados:

Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Consulte también
Elemento GroupBy para View

Elemento Name para Control for Controls for Configuration

Elemento Name para Control for Controls for View

Escritura de un archivo de formato de PowerShell


Elemento Label para GroupBy
Artículo • 24/09/2021

Especifica una etiqueta que se muestra cuando se encuentra un nuevo grupo.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento Label

Sintaxis
XML

<Label>DisplayedLabel</Label>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Label elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento GroupBy para View Define cómo se muestra un nuevo grupo de objetos.
Valor de texto
Especifique el texto que se muestra cada vez Windows PowerShell encuentra una nueva
propiedad o un valor de script.

Comentarios
Además del texto especificado por este elemento, Windows PowerShell muestra el
nuevo valor que inicia el grupo y agrega una línea en blanco antes y después del grupo.

Ejemplo
En el ejemplo siguiente se muestra la etiqueta de un nuevo grupo. La etiqueta mostrada
tendría un aspecto similar al siguiente: Service Type: NewValueofProperty

XML

<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>

Para obtener un ejemplo de un archivo de formato completo que incluye este elemento,
vea Wide View (GroupBy).

Consulte también
Elemento GroupBy para View

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para GroupBy
Artículo • 27/09/2021

Especifica la propiedad .NET que inicia un nuevo grupo cada vez que cambia su valor.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento GroupBy para View Define cómo se muestra un grupo de objetos .NET.
Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
Windows PowerShell inicia un nuevo grupo cada vez que cambia el valor de esta
propiedad.

Cuando se especifica este elemento, no se puede especificar el elemento ScriptBlock


para iniciar un nuevo grupo.

Ejemplo
En el ejemplo siguiente se muestra cómo iniciar un nuevo grupo cuando cambia el valor
de una propiedad.

XML

<GroupBy>
<Label>Service Type</Label>
<PropertyName>ServiceType</PropertyName>
</GroupBy>

Para obtener un ejemplo de un archivo de formato completo que incluye este elemento,
vea Wide View (GroupBy).

Consulte también
Elemento GroupBy para View

Elemento ScriptBlock para GroupBy

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para GroupBy
Artículo • 24/09/2021

Especifica el script que inicia un nuevo grupo cada vez que cambia su valor.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento GroupBy
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento GroupBy para View Define cómo se muestra un grupo de objetos .NET.
Valor de texto
Especifique el script que se evalúa.

Comentarios
PowerShell inicia un nuevo grupo cada vez que cambia el valor de este script.

Cuando se especifica este elemento, no se puede especificar el elemento PropertyName


para iniciar un nuevo grupo.

Consulte también
Elemento PropertyName para GroupBy

Elemento GroupBy para View

Escritura de un archivo de formato de PowerShell


Elemento ListControl
Artículo • 27/09/2021

Define un formato de lista para la vista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl

Sintaxis
XML

<ListControl>
<ListEntries>...</ListEntries>
</ListControl>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ListControl elemento . Este elemento solo debe contener un
único elemento secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento ListEntries Elemento necesario.

Proporciona las definiciones de la vista de lista.


Elementos primarios

Elemento Descripción

Elemento View Define una vista que se usa para mostrar los miembros de uno o varios objetos.

Comentarios
Para obtener más información sobre cómo crear una vista de lista, vea Crear una vista
de lista.

Ejemplo
En este ejemplo se muestra una vista de lista para el objeto
System.Serviceprocess.Servicecontroller.

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>...</ListEntry>
</ListEntries>
</ListControl>
</View>

Consulte también
Elemento View

Elemento ListEntries

Creación de una vista de lista

Escribir un archivo Windows PowerShell de tipos y formato


Elemento ListEntries
Artículo • 24/09/2021

Proporciona las definiciones de la vista de lista. La vista de lista debe especificar una o
varias definiciones.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries

Sintaxis
XML

<ListEntries>
<ListEntry>...</ListEntry>
</ListEntries>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ListEntries elemento . Se debe especificar al menos un
elemento secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento ListEntry Proporciona una definición de la vista de lista.


Elementos primarios

Elemento Descripción

Elemento ListControl Define un formato de lista para la vista.

Comentarios
Para obtener más información sobre las vistas de lista, vea Vista de lista.

Ejemplo
En este ejemplo se muestran los elementos XML que definen la vista de lista para el
objeto System.Serviceprocess.Servicecontroller.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>...</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>

Consulte también
Elemento ListControl

Elemento ListEntry

Vista de lista

Escribir un archivo de Windows PowerShell y tipos


Elemento ListEntry
Artículo • 27/09/2021

Proporciona una definición de la vista de lista.

Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry

Sintaxis
XML

<ListEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ListEntry elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento Elemento opcional.


EntrySelectedBy para
ListEntry Define los objetos .NET que usan esta definición de vista de lista o la
condición que debe existir para que se use esta definición.
Elemento Descripción

Elemento ListItems Elemento necesario.

Define las propiedades y scripts cuyos valores se muestran en la vista de


lista.

Elementos primarios

Elemento Descripción

Elemento ListEntries Proporciona las definiciones de la vista de lista.

Comentarios
Una vista de lista es un formato de lista que muestra valores de propiedad o valores de
script para cada objeto. Para obtener más información sobre las vistas de lista, vea Crear
una vista de lista.

Ejemplo
En este ejemplo se muestran los elementos XML que definen la vista de lista para el
objeto System.Serviceprocess.Servicecontroller.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>
<ListEntries>
<ListEntry>
<ListItems>...</ListItems>
</ListEntry>
</ListEntries>
</ListControl>
</View>

Consulte también
Creación de una vista de lista
Elemento EntrySelectedBy para ListEntry

Elemento ListEntries

Elemento ListItems

Escribir un archivo Windows PowerShell de tipos y formato


Elemento EntrySelectedBy para ListEntry
Artículo • 24/09/2021

Define los tipos de .NET que usan esta definición de vista de lista o la condición que
debe existir para que se use esta definición. En la mayoría de los casos, solo se necesita
una definición para una vista de lista. Sin embargo, puede proporcionar varias
definiciones para la vista de lista si desea usar la misma vista de lista para mostrar datos
diferentes para distintos objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento EntrySelectedBy

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento .

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy for ListControl
Define la condición que debe existir para que se utilice
esta definición de vista de lista.

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy for ListControl
Especifica un conjunto de tipos de .NET que usan esta
definición de vista de lista.

Elemento TypeName para Elemento opcional.


EntrySelectedBy para ListControl
Especifica un tipo de .NET que usa esta definición de
vista de lista.

Elementos primarios

Elemento Descripción

Elemento ListEntry para ListControl Define cómo se muestran las filas de la lista.

Comentarios
Debe especificar al menos un tipo, conjunto de selección o condición de selección para
una definición de vista de lista. No hay ningún límite máximo en el número de
elementos secundarios que puede usar.

Las condiciones de selección se usan para definir una condición que debe existir para la
definición que se va a usar, como cuando un objeto tiene una propiedad específica o
cuando un valor de propiedad o script específico se evalúa como true . Para obtener
más información sobre las condiciones de selección, vea Definición de condiciones para
cuando se muestran datos.

Para obtener más información sobre los componentes de una vista de lista, vea Crear
una vista de lista.

Ejemplo
En el ejemplo siguiente se muestra cómo definir los objetos para una vista de lista con
su nombre de tipo .NET.
XML

<ListEntry>
<EntrySelectedBy>
<TypeName>NameofDotNetType</TypeName>>
</EntrySelectedBy>
</ListEntry>

Consulte también
Elemento ListEntry para ListControl

Elemento SelectionCondition para EntrySelectedBy for ListControl

Elemento SelectionSetName para EntrySelectedBy for ListControl

Elemento TypeName para EntrySelectedBy para ListControl

Creación de una vista de lista

Definir condiciones para cuando se muestran los datos

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy for ListControl
Artículo • 24/09/2021

Define la condición que debe existir para usar esta definición de la vista de lista. No hay
ningún límite en el número de condiciones de selección que se pueden especificar para
una definición de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionCondition elemento .

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para SelectionCondition Elemento opcional.


for EntrySelectedBy for ListEntry
Especifica la propiedad .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition for Elemento opcional.


EntrySelectedBy for ListEntry
Especifica el script que desencadena la
condición.

Elemento SelectionSetName para Elemento opcional.


SelectionCondition for EntrySelectedBy for ListEntry
Especifica el conjunto de tipos de .NET que
desencadenan la condición.

Elemento TypeName para SelectionCondition for Elemento opcional.


EntrySelectedBy for ListEntry
Especifica un tipo de .NET que
desencadena la condición.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy Define los tipos de .NET que usan esta entrada de tabla o la
para TableRowEntry condición que debe existir para que se use esta entrada.

Comentarios
lCuando define una condición de selección, se aplican los siguientes requisitos:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.

Para obtener más información sobre cómo usar condiciones de selección, vea Definición
de condiciones para cuando se muestran datos.

Para obtener más información sobre otros componentes de una vista de lista, vea Crear
una vista de lista.
Consulte también
Creación de una vista de lista

Definir condiciones para cuando se muestran los datos

Elemento ListEntry

Elemento SelectionSetName para EntrySelectedBy for ListEntry

Elemento TypeName para EntrySelectedBy for ListEntry

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
SelectionCondition for EntrySelectedBy
for ListControl
Artículo • 27/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como , se cumple la condición y true se usa la entrada de
lista.

Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy for ListEntry utilice esta entrada de lista.

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
bloque de script, pero no puede especificar ambos. Para obtener más información sobre
cómo usar condiciones de selección, vea Definir condiciones para cuando se usa una
entrada de vista o un elemento.

Para obtener más información sobre otros componentes de una vista de lista, vea
Creating List View.

Consulte también
Creación de una vista de lista

Definir condiciones para cuando se muestran los datos

Elemento ListEntry

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for ListEntry

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for EntrySelectedBy
for ListControl
Artículo • 24/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la entrada de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy for ListEntry utilice esta entrada de lista.

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de script o propiedad
para evaluar, pero no puede especificar ambos. (Para obtener más información sobre
cómo se pueden usar las condiciones de selección, vea Definir condiciones para cuando
se usa una entrada de vista o un elemento).

Para obtener más información sobre los demás componentes de una vista de lista, vea
Vista de lista.

Consulte también
Elemento ListEntry

Elemento PropertyName para SelectionCondition for EntrySelectedBy for ListEntry

Elemento SelectionCondition para EntrySelectedBy for ListEntry

Vista de lista

Definir condiciones para cuando se usa una entrada de vista o un elemento

Escribir un archivo Windows PowerShell de tipos y formato


Elemento SelectionSetName para
SelectionCondition for EntrySelectedBy
for ListEntry
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante esta definición de la vista de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para usar esta
EntrySelectedBy for ListEntry definición de la vista de lista.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
La condición de selección puede especificar un conjunto de selección o un tipo de .NET,
pero no puede especificar ambos. Para obtener más información sobre cómo usar las
condiciones de selección, vea Definir condiciones para cuando se muestran los datos.

Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
objetos.

Para obtener más información sobre otros componentes de una vista de lista, vea Crear
una vista de lista.

Consulte también
Creación de una vista de lista

Definir condiciones para cuando se muestran los datos

Elemento SelectionCondition para EntrySelectedBy for ListEntry

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for EntrySelectedBy
for ListControl
Artículo • 24/09/2021

Especifica un tipo de .NET que desencadena la condición. Cuando este tipo está
presente, se usa la entrada de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy for ListControl utilice esta entrada de lista.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
La condición de selección puede especificar cualquier número de tipos o conjuntos de
selección de .NET, pero no puede especificar ambos. Para obtener más información
sobre cómo usar las condiciones de selección, vea Definición de condiciones para
cuando se muestran datos.

Para obtener más información sobre otros componentes de una vista de lista, vea Crear
una vista de lista.

Consulte también
Creación de una vista de lista

Definir condiciones para cuando se muestran los datos

Elemento SelectionCondition para EntrySelectedBy for ListControl

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy for ListControl
Artículo • 24/09/2021

Especifica un conjunto de objetos .NET para la entrada de lista. No hay ningún límite en
el número de conjuntos de selección que se pueden especificar para una entrada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento EntrySelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta entrada de lista o la condición
EntrySelectedBy para que debe existir para que se use esta entrada.
ListEntry

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Cada entrada de lista debe tener al menos un nombre de tipo, un conjunto de selección
o una condición de selección definidos.

Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de


objetos que se usan en varias vistas. Por ejemplo, puede crear una vista de tabla y una
vista de lista para el mismo conjunto de objetos. Para obtener más información sobre
cómo definir conjuntos de selección, vea Definir conjuntos de objetos para una vista.

Para obtener más información sobre los componentes de una vista de lista, vea Crear
una vista de lista.

Ejemplo
En el ejemplo siguiente se muestra cómo especificar un conjunto de selección para una
entrada de una vista de lista.

XML

<ListEntry>
<EntrySelectedBy>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>

Consulte también
Creación de una vista de lista
Elemento EntrySelectedBy para ListEntry

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy para ListControl
Artículo • 24/09/2021

Especifica un tipo de .NET que usa esta entrada de la vista de lista. No hay ningún límite
en el número de tipos que se pueden especificar para una entrada de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
EntrySelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta entrada de lista o la condición
EntrySelectedBy para que debe existir para que se use esta entrada.
ListEntry

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
Cada entrada de lista debe tener al menos un nombre de tipo, un conjunto de selección
o una condición de selección definidos.

Para obtener más información sobre cómo se usa este elemento en una vista de lista,
vea Vista de lista.

Ejemplo
En el ejemplo siguiente se muestra cómo especificar un conjunto de selección para una
entrada de una vista de lista.

XML

<ListEntry>
<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
</EntrySelectedBy>
<ListItems>...</ListItems>
</ListEntry>

Consulte también
Creación de una vista de lista

Elemento EntrySelectedBy para ListEntry

Elemento SelectionSetName para EntrySelectedBy for ListEntry


Escritura de un archivo de formato de PowerShell
Elemento ListItems
Artículo • 27/09/2021

Define las propiedades y scripts cuyos valores se muestran en las filas de la vista de lista.

Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems

Sintaxis
XML

<ListItems>
<ListItem>...</ListItem>
</ListItems>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ListItems elemento . No hay ningún límite en el número de
elementos secundarios que se pueden especificar. El orden de los elementos
secundarios define el orden en que se muestran los valores en la vista de lista.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento ListItem para Elemento necesario.


ListControl
Define la propiedad o script cuyo valor se muestra en la vista
de lista.
Elementos primarios

Elemento Descripción

Elemento ListEntry para ListControl Proporciona una definición de la vista de lista.

Comentarios
Para obtener más información sobre este tipo de vista, vea Crear una vista de lista.

Ejemplo
En este ejemplo se muestran los elementos XML que definen tres filas de la vista de
lista.

XML

<ListEntry>
<ListItems>
<ListItem>
<Label>Property1: </Label>
<PropertyName>.NetTypeProperty1</PropertyName>
</ListItem>
<ListItem>
<PropertyName>.NetTypeProperty2</PropertyName>
</ListItem>
<ListItem>
<ScriptBlock>$_.ProcessName + ":" $_.Id</ScriptBlock>
</ListItem>
</ListEntry>

Consulte también
Elemento ListEntry para ListControl

Elemento ListItem para ListControl

Creación de una vista de lista

Escritura de un archivo de formato de PowerShell


Elemento FormatString para ListItem for
ListControl
Artículo • 19/01/2022

Especifica un patrón de formato que define cómo se muestra la propiedad o el valor del
script.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems
Elemento ListItem
Elemento FormatString

Sintaxis
XML

<FormatString>PropertyPattern</FormatString>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FormatString elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define la propiedad o script cuyo valor se muestra en una fila de la vista de
ListItem lista.

Valor de texto
Especifique el patrón que se usa para dar formato a los datos. Por ejemplo, puede usar
este patrón para dar formato al valor de cualquier propiedad que sea de tipo
System.Timespan: {0:MMM}{0:dd}{0:HH}:{0:mm}.

Comentarios
Las cadenas de formato se pueden usar al crear vistas de tabla, vistas de lista, vistas
anchas o vistas personalizadas. Para obtener más información sobre cómo dar formato a
un valor que se muestra en una vista, vea Aplicar formato a los datos mostrados.

Para obtener más información sobre el uso de cadenas de formato en vistas de lista, vea
Creating List View.

Ejemplo
En el ejemplo siguiente se muestra cómo definir una cadena de formato para el valor de
la StartTime propiedad .

XML

<ListItem>
<PropertyName>StartTime</PropertyName>
<FormatString>{0:MMM} {0:DD} {0:HH}:{0:MM}</FormatString>
</ListItem>

Consulte también
Creación de una vista de lista

Elemento ListItem

Escribir un archivo Windows PowerShell de tipos y formato


Elemento ItemSelectionCondition para
ListItem para ListControl
Artículo • 24/09/2021

Define la condición que debe existir para que se utilice este elemento de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems
Elemento ListItem
Elemento ItemSelectionCondition

Sintaxis
XML

<ItemSelectionCondition>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</ItemSelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ItemSelectionCondition elemento .

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento PropertyName para Elemento opcional.


ItemSelectionCondition para ListControl
Especifica la propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para ItemSelectionCondition Elemento opcional.


para ListControl
Especifica el script que desencadena la
condición.

Elementos primarios

Elemento Descripción

Elemento ListItem para ListItems Define la propiedad o script cuyo valor se muestra en una
para ListControl fila de la vista de lista.

Comentarios
Puede especificar un nombre de propiedad o un script para esta condición, pero no
puede especificar ambos.

Consulte también
Elemento ListItem para ListItems para ListControl

Elemento PropertyName para ItemSelectionCondition para ListControl

Elemento ScriptBlock para ItemSelectionCondition para ListControl

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
ItemSelectionCondition para ListControl
Artículo • 24/09/2021

Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad


está presente o cuando se evalúa como true , se cumple la condición y se usa la vista.
Este elemento se usa al definir una vista de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems
Elemento ListItem
Elemento ItemSelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del PropertyName elemento.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para ListItem para ListControl

Valor de texto
Especifique el nombre de la propiedad cuyo valor se muestra.

Comentarios
Si se usa este elemento, no se puede especificar el elemento ScriptBlock al definir la
condición de selección.

Consulte también
Elemento ScriptBlock para ItemSelectionCondition para ListIControl

Elemento ItemSelectionCondition para ListItem para ListControl

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
ItemSelectionCondition para ListControl
Artículo • 27/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa el elemento de lista. Este elemento se usa al

definir una vista de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries para ListControl
Elemento ListEntry para ListEntries for ListControl
Elemento ListItems para ListEntry for ListControl
Elemento ListItem para ListItems para el control List
Elemento ItemSelectionCondition para ListItem para ListControl
Elemento ScriptBlock para ItemSelectionCondition para ListControl

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del ScriptBlock elemento.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento ItemSelectionCondition para Define la condición que debe existir para que se
ListItem para ListControl utilice este elemento de lista.

Valor de texto
Especifique el script que se evalúa.

Comentarios
Si se usa este elemento, no se puede especificar el PropertyName elemento al definir la
condición de selección.

Consulte también
Escritura de un archivo de formato de PowerShell
Elemento Label para ListItem para
ListControl
Artículo • 24/09/2021

Especifica la etiqueta que se muestra a la izquierda de la propiedad o el valor de script


de la fila.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems
Elemento ListItem
Elemento Label

Sintaxis
XML

<Label>Label for displayed value</Label>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Label elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento ListItem para ListItems Define la propiedad o script cuyo valor se muestra en una
para ListControl fila de la vista de lista.

Valor de texto
Especifique la etiqueta que se va a mostrar a la izquierda de la propiedad o el valor del
script.

Comentarios
Si no se especifica una etiqueta, se muestra el nombre de la propiedad o el script. Para
obtener más información sobre el uso de etiquetas en una vista de lista, vea Crear una
vista de lista.

Ejemplo
En el ejemplo siguiente se muestra cómo agregar una etiqueta a una fila.

XML

<ListItem>
<Label>Property1: </Label>
<PropertyName>DotNetProperty1</PropertyName>
</ListItem>

Consulte también
Creación de una vista de lista

Elemento ListItem

Escritura de un archivo de formato de PowerShell


Elemento ListItem
Artículo • 27/09/2021

Define la propiedad o script cuyo valor se muestra en una fila de la vista de lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems
Elemento ListItem

Sintaxis
XML

<ListItem>
<PropertyName>PropertyToDisplay</PropertyName>
<ScriptBlock>ScriptToExecute</ScriptBlock>
<Label>LabelToDisplay</Label>
<FormatString>FormatPattern</FormatString>
<ItemSelectionCondition>...</ItemSelectionCondition>
</ListItem>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ListItem elemento . Solo se puede especificar una propiedad o
script.

Atributos
None

Elementos secundarios
Elemento Descripción

Elemento FormatString para ListItem Elemento opcional.


para ListControl
Especifica una cadena de formato que define cómo se
muestra la propiedad o el valor del script.

Elemento ItemSelectionCondition Elemento opcional.


para ListItem para ListControl
Define la condición que debe existir para que se utilice
este elemento de lista.

Elemento Label para ListItem para Elemento opcional


ListControl
Especifica la etiqueta que se muestra a la izquierda de la
propiedad o el valor de script de la fila.

Elemento PropertyName para Elemento opcional.


ListItem para ListControl
Especifica la propiedad .NET cuyo valor se muestra en la
fila.

Elemento ScriptBlock para ListItem Elemento opcional.


para ListControl
Especifica el script cuyo valor se muestra en la fila.

Elementos primarios

Elemento Descripción

Elemento ListItems para el Define las propiedades y scripts cuyos valores se muestran en la
control List vista de lista.

Comentarios
Para obtener más información sobre los componentes de una vista de lista, vea Crear
una vista de lista.

Ejemplo
En este ejemplo se muestran los elementos XML que definen tres filas de la vista de
lista. Las dos primeras filas muestran el valor de una propiedad de .NET y la última fila
muestra un valor generado por un script.

XML
<ListEntry>
<ListItems>
<ListItem>
<Label>Property1: </Label>
<PropertyName>DotNetProperty1</PropertyName>
</ListItem>
<ListItem>
<PropertyName>DotNetProperty2</PropertyName>
</ListItem>
<ListItem>
<ScriptBlock>$_.ProcessName + ":" $_.Id</ScriptBlock>
</ListItem>
</ListItems>
</ListEntry>

Consulte también
Elemento ListItems

Elemento FormatString para ListItem

Elemento Label para ListItem

Elemento PropertyName para ListItem

Elemento ScriptBlock para ListItem

Creación de una vista de lista

Escribir un archivo Windows PowerShell de tipos y formato


Elemento PropertyName para ListItem
para ListControl
Artículo • 24/09/2021

Especifica la propiedad .NET cuyo valor se muestra en la lista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems
Elemento ListItem
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define la propiedad o script cuyo valor se muestra en la fila de la vista de


ListItem lista.

Valor de texto
Especifique el nombre de la propiedad cuyo valor se muestra.

Comentarios
Cuando se especifica este elemento, no se puede especificar el elemento ScriptBlock.

Además de mostrar el valor de propiedad, también puede especificar una etiqueta para
el valor o una cadena de formato que se puede usar para cambiar la presentación del
valor. Para obtener más información sobre cómo especificar datos en una vista de lista,
vea Crear una vista de lista.

Ejemplo
En el ejemplo siguiente se muestra cómo especificar la etiqueta y la propiedad cuyo
valor se muestra.

XML

ListItem>
<Label>NameOfProperty</Label>
<PropertyName>.NetTypeProperty</PropertyName>
</ListItem>

Consulte también
Elemento ScriptBlock para ListItem para ListControl

Creación de una vista de lista

Elemento ListItem para ListControl(Format)

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para ListItem para
ListControl
Artículo • 24/09/2021

Especifica el script cuyo valor se muestra en la fila.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ListControl
Elemento ListEntries
Elemento ListEntry
Elemento ListItems
Elemento ListItem
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define la propiedad o script cuyo valor se muestra en una fila de la vista de
ListItem lista.

Valor de texto
Especifique el script cuyo valor se muestra en la fila.

Comentarios
Cuando se especifica este elemento, no se puede especificar el elemento PropertyName.

Para obtener más información sobre cómo especificar scripts en una vista de lista, vea
Vista de lista.

Ejemplo
En el ejemplo siguiente se muestra cómo especificar la propiedad cuyo valor se muestra.

XML

<ListItem>
<ScriptBlock>$_.ProcessName + ":" $_.Id</ScriptBlock>
</ListItem>

Consulte también
Elemento PropertyName para ListItem para ListControl

Creación de una vista de lista

Elemento ListItem para ListItems para ListControl

Escritura de un archivo de formato de PowerShell


Elemento Name para View
Artículo • 27/09/2021

Especifica el nombre que se usa para identificar la vista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento Name

Sintaxis
XML

<Name>ViewName</Name>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Name elemento . Solo se Name permite un elemento para cada
vista.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento Define una vista que se usa para mostrar los miembros de uno o varios objetos
View .NET.
Valor de texto
Especifique un nombre descriptivo único para la vista. Este nombre puede incluir una
referencia al tipo de vista (como una vista de tabla o vista de lista), qué objeto o
conjunto de objetos usan la vista, qué comando devuelve los objetos o una
combinación de estos.

Comentarios
Para obtener más información sobre los distintos tipos de vistas, vea los temas
siguientes:Vista de tabla ,Vista de lista , Vista anchay Vista personalizada.

Ejemplo
En el ejemplo siguiente se muestra View un elemento que define una vista de tabla para
el objeto System.Serviceprocess.Servicecontroller. El nombre de la vista es "service".

XML

<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>...</TableControl>
</View>

Consulte también
Creación de una vista de lista

Creación de una vista de tabla

Creación de una vista amplia

Creación de controles personalizados

Elemento View

Escritura de un archivo de formato de PowerShell


Elemento OutOfBand
Artículo • 01/03/2022

En una canalización, el primer objeto emitido se elige como el tipo para dar formato a la
salida de la canalización. PowerShell intenta dar formato a objetos posteriores con la
misma vista. Si el objeto no se ajusta a la vista, no se muestra. Puede crear vistas
OutOfBand que se pueden usar para dar formato a estos otros tipos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento OutOfBand

Sintaxis
XML

<OutOfBand/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del OutOfBand elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción
Elemento Descripción

Elemento View Define una vista que muestra uno o varios objetos .NET.

Comentarios
Cuando la "forma" del formato (vista) se ha determinado por objetos anteriores, puede
que desee que objetos de distintos tipos sigan usando esa forma (tabla, lista o lo que
sea) incluso si especifican sus propias vistas. O bien, a veces quiere que la vista tome el
control. Cuando OutOfBand es true, la vista se aplica independientemente de los
objetos anteriores que puedan haber seleccionado una vista diferente.

Consulte también
Elemento View

Escritura de un archivo de formato de PowerShell


Elemento TableControl
Artículo • 24/09/2021

Define un formato de tabla para una vista.

Schema
Elemento ViewDefinitions
Elemento View
Elemento TableControl

Sintaxis
XML

<TableControl>
<AutoSize/>
<HideTableHeaders/>
<TableHeaders>...</TableHeaders>
<TableRowEntries>...</TableRowEntries>
</TableControl>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TableControl elemento . Debe especificar las filas de la tabla.
Todos los demás elementos secundarios son opcionales.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento AutoSize para Elemento opcional.


TableControl
Especifica si el tamaño de columna y el número de columnas se
ajustan en función del tamaño de los datos.

Elemento HideTableHeaders Elemento opcional.


para TableControl
Indica si no se muestra el encabezado de la tabla.

Elemento TableHeaders Elemento necesario.


para TableControl
Define las etiquetas, los anchos y la alineación de los datos de las
columnas de la vista de tabla.

Elemento TableRowEntries Elemento opcional.


para TableControl
Proporciona las definiciones de la vista de tabla.

Elementos primarios

Elemento Descripción

Elemento View Define una vista que se usa para mostrar los miembros de uno o varios objetos.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En este ejemplo se TableControl muestra un elemento que se usa para mostrar las
propiedades del objeto System.Serviceprocess.Servicecontroller.

XML

<View>
<Name>service</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<TableControl>
<TableHeaders>...</TableHeaders>
<TableRowEntries>...</TableRowEntries>
</TableControl>
</View>

Consulte también
Creación de una vista de tabla

Elemento View

Elemento AutoSize para TableControl

Elemento HideTableHeaders

Elemento TableHeaders

Elemento TableRowEntries

Escritura de un archivo de formato de PowerShell


Elemento AutoSize para TableControl
Artículo • 24/09/2021

Especifica si el tamaño de columna y el número de columnas se ajustan en función del


tamaño de los datos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento AutoSize

Sintaxis
XML

<AutoSize/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del AutoSize elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento TableControl Define un formato de tabla para una vista.


Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Elemento TableControl

Escritura de un archivo de formato de PowerShell


Elemento HideTableHeaders
Artículo • 24/09/2021

Especifica que no se muestran los encabezados de la tabla.

Schema
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento HideTableHeaders

Sintaxis
VB

<HideTableHeaders/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del HideTableHeaders elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento TableControl Define un formato de tabla para una vista.


Valor de texto
Especifique true para ocultar los encabezados de la tabla.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Elemento TableControl
Elemento TableHeaders
Artículo • 24/09/2021

Define los encabezados de las columnas de una tabla.

Schema
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableHeaders para TableControl

Sintaxis
XML

<TableHeaders>
<TableColumnHeader>...</TableColumnHeader>
</TableHeaders>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del TableHeaders elemento. Debe haber un elemento secundario
para cada propiedad del objeto que se va a mostrar. La información del encabezado de
columna se muestra en el orden en que se especifican los elementos secundarios.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento Elemento opcional.


TableColumnHeader
Define la etiqueta, el ancho y la alineación de los datos de una columna
de una vista de tabla.

Elementos primarios

Elemento Descripción

Elemento TableControl Define un formato de tabla para una vista.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En este ejemplo se muestra TableHeaders un elemento que define dos encabezados de
columna.

XML

<TableHeaders>
<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Column 2</Label)
<Width>10</Width>
<Alignment>Centered</Alignment>
</TableColumnHeader>
</TableHeaders>

Consulte también
Creación de una vista de tabla

Elemento TableColumnHeader
Elemento TableControl

Escritura de un archivo de formato de PowerShell


Elemento TableColumnHeader
Artículo • 24/09/2021

Define la etiqueta, el ancho de la columna y la alineación de la etiqueta para una


columna de la tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableHeaders
Elemento TableColumnHeader

Sintaxis
XML

<TableColumnHeader>
<Label>DisplayedLabel</Label>
<Width>NumberOfCharacters</Width>
<Alignment>Left, Right, or Centered</Alignment>
</TableColumnHeader>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TableColumnHeader elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento Label para Elemento opcional.


TableColumnHeader
para TableControl Define la etiqueta que se muestra en la parte superior de la columna.
Si no se especifica ninguna etiqueta, se usa el nombre de la propiedad
cuyo valor se muestra en las filas.

Elemento Width para Elemento necesario.


TableColumnHeader
para TableControl Especifica el ancho (en caracteres) de la columna.

Elemento Alignment Elemento opcional.


para
TableColumnHeader Especifica cómo se muestra la etiqueta de la columna. Si no se
para TableControl especifica ninguna alineación, la etiqueta se alinea a la izquierda.

Elementos primarios

Elemento Descripción

Elemento TableHeaders Define las columnas de una vista de tabla.

Comentarios
Especifique un encabezado para cada columna de la tabla. Las columnas se muestran en
el orden en que se TableColumnHeader definen los elementos.

Una tabla debe tener el mismo número de TableColumnHeader elementos que


TableRowEntry los elementos. El encabezado de columna define cómo se muestra el
texto de la parte superior de la tabla. Las entradas de fila definen qué datos se muestran
en las filas de la tabla.

Para obtener más información sobre los componentes de una vista de tabla, vea Vista
de tabla.

Ejemplo
En el ejemplo siguiente se muestran dos TableColumnHeader elementos . El primer
elemento define una columna cuya etiqueta es "Columna 1", tiene un ancho de 16
caracteres y cuya etiqueta está alineada a la izquierda. El segundo elemento define una
columna cuya etiqueta es "Columna 2", tiene un ancho de 10 caracteres y cuya etiqueta
se centra en la columna.
XML

<TableHeaders>
<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>
<TableColumnHeader>
<Label>Column 2</Label)
<Width>10</Width>
<Alignment>Centered</Alignment>
</TableColumnHeader>
</TableHeaders>

Consulte también
Elemento Alignment para TableColumnHeader para TableControl

Creación de una vista de tabla

Elemento Label para TableColumnHeader para TableControl

Elemento TableHeaders para TableControl

Width para TableColumnHeader para el elemento TableControl

Escritura de un archivo de formato de PowerShell


Elemento Alignment para
TableColumnHeader
Artículo • 24/09/2021

Define cómo se muestran los datos de un encabezado de columna.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableHeaders
Elemento TableColumnHeader
Elemento Alignment

Sintaxis
XML

<Alignment>AlignmentType</Alignment>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Alignment elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios
Elemento Descripción

Elemento Define una etiqueta, el ancho y la alineación de los datos de una


TableColumnHeader columna de la tabla.

Valor de texto
Especifique uno de los valores siguientes. Estos valores no distinguen mayúsculas de
minúsculas.

Left: alinea los datos mostrados en la columna de la izquierda. Este es el valor


predeterminado si no se especifica este elemento.
Derecha: alinea los datos que se muestran en la columna de la derecha.
Centro: centra los datos mostrados en la columna.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En este ejemplo se TableColumnHeader muestra un elemento cuyos datos están
alineados en el centro.

XML

<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Center</Alignment>
</TableColumnHeader>

Consulte también
Creación de una vista de tabla

Elemento TableColumnHeader

Escritura de un archivo de formato de PowerShell


Elemento Label para
TableColumnHeader para TableControl
Artículo • 24/09/2021

Define la etiqueta que se muestra en la parte superior de una columna. Este elemento se
usa al definir una vista de tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableHeaders
Elemento TableColumnHeader
Elemento Label

Sintaxis
XML

<Label>DisplayedLabel</Label>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Label elemento . Solo se permite una etiqueta para cada
columna.

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento TableColumnHeader para Define una etiqueta, el ancho y la alineación de los


TableHeaders para TableControl datos de una columna de la tabla.

Valor de texto
Especifique el texto que se muestra en la parte superior de la columna de la tabla. No
hay caracteres restringidos para la etiqueta de columna.

Comentarios
Si no se especifica ninguna etiqueta, se usa el nombre de la propiedad cuyo valor se
muestra en las filas.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En este ejemplo se TableColumnHeader muestra un elemento cuya etiqueta es "Columna
1".

XML

<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>

Consulte también
Creación de una vista de tabla

Elemento TableColumnHeader

Escritura de un archivo de formato de PowerShell


Elemento Width para
TableColumnHeader
Artículo • 24/09/2021

Define el ancho (en caracteres) de una columna.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableHeaders
TableColumnHeader
Elemento Width

Sintaxis
XML

<Width>NumberOfCharacters</Width>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Width elemento utilizado al definir encabezados de columna.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios
Elemento Descripción

Elemento TableColumnHeader para Define una etiqueta, ancho y alineación de los datos
TableHeaders para TableControl de una columna de la tabla.

Valor de texto
Cuando sea posible, especifique un ancho (en caracteres) mayor que la longitud de los
valores de propiedad mostrados.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En el ejemplo siguiente se muestra TableColumnHeader un elemento cuyo ancho es de 16
caracteres.

XML

<TableColumnHeader>
<Label>Column 1</Label)
<Width>16</Width>
<Alignment>Left</Alignment>
</TableColumnHeader>

Consulte también
Creación de una vista de tabla

Elemento TableColumnHeader para TableHeader para TableControl

Escritura de un archivo de formato de PowerShell


Elemento TableRowEntries
Artículo • 24/09/2021

Define las filas de la tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries

Sintaxis
XML

<TableRowEntries>
<TableRowEntry>...</TableRowEntry>
</TableRowEntries>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TableRowEntries elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento TableRowEntry para TableRowEntries Elemento necesario.


para TableControl
Define los datos que se muestran en una fila
de la tabla.
Elementos primarios

Elemento Descripción

Elemento TableControl Define un formato de tabla para una vista.

Comentarios
Debe especificar uno o varios elementos TableRowEntry para la vista de tabla. No hay
ningún límite máximo en el número de elementos que se pueden TableRowEntry
agregar ni su orden es significativo.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En el ejemplo siguiente se muestra un elemento que define una fila que muestra los
valores de dos propiedades del objeto TableRowEntries System.Diagnostics.Process.

XML

<TableRowEntries>
<TableRowEntry>
<EntrySelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</EntrySelectedBy>
<TableColumnItems>
<TableColumnItem>
<PropertyName> Property for first column</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName> Property for second column</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>
</TableRowEntries>

Consulte también
Creación de una vista de tabla

Elemento TableControl
Elemento TableRowEntry

Escritura de un archivo de formato de PowerShell


Elemento TableColumnItems
Artículo • 24/09/2021

Define las propiedades o scripts cuyos valores se muestran en una fila.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries para TableControl
Elemento TableRowEntry para TableRowEntries para TableControl
Elemento TableColumnItems para TableControlEntry para TableControl

Sintaxis
XML

TableColumnItems>
<TableColumnItem>...</TableColumnItem>
</TableColumnItems>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TableColumnItems elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento TableColumnItem para Elemento necesario.


TableColumnItems para TableControl
Define la propiedad o script cuyo valor se
muestra en una columna de la fila.

Elementos primarios

Elemento Descripción

Elemento TableRowEntry para TableRowEntries Define los datos que se muestran en una fila
para TableControl de la tabla.

Comentarios
Se TableColumnItem requiere un elemento para cada columna de la fila. La primera
entrada se muestra en la primera columna, la segunda entrada en la segunda columna, y
así sucesivamente.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En el ejemplo siguiente se TableColumnItems muestra un elemento que define tres
propiedades del objeto System.Diagnostics.Process.

XML

<TableColumnItems>
<TableColumnItem>
<PropertyName>Status</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>Name</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>DisplayName</PropertyName>
</TableColumnItem>
</TableColumnItems>
Consulte también
Creación de una vista de tabla

Elemento TableColumnItem

Elemento TableRowEntry

Escritura de un archivo de formato de PowerShell


Elemento TableColumnItem
Artículo • 24/09/2021

Define la propiedad o script cuyo valor se muestra en la columna de la fila.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento TableColumnItems
Elemento TableColumnItem

Sintaxis
XML

<TableColumnItem>
<Alignment>Left, Right, or Center</Alignment>
<FormatString>FormatPattern</FormatString>
<PropertyName>Nameof.NetProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</TableColumnItem>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TableColumnItem elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento Alignment para Elemento opcional.


TableColumnItem para TableControl
Define cómo se muestran los datos de una columna de
la fila.

Elemento FormatString para Especifica un patrón de formato que se usa para dar
TableColumnItem para TableControl formato a los datos de la columna de la fila.

Elemento PropertyName para Elemento opcional.


TableColumnItem para TableControl
Especifica el nombre de la propiedad cuyo valor se
muestra.

Elemento ScriptBlock para Elemento opcional.


TableColumnItem para TableControl
Especifica el script cuyo valor se muestra en la columna
de una fila.

Elementos primarios

Elemento Descripción

Elemento TableColumnItems para Define las propiedades o scripts cuyos valores


TableControlEntry para TableControl se muestran en la fila.

Comentarios
Puede especificar una propiedad de un objeto o un script en cada columna de la fila. Si
no se especifica ningún elemento secundario, el elemento es un marcador de posición y
no se muestra ningún dato.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En este ejemplo se TableColumnItem muestra un elemento que muestra el valor de la
propiedad del objeto Status System.Diagnostics.Process.

XML
<TableColumnItem>
<Alignment>Centered</Alignment>
<PropertyName>Status</PropertyName>
</TableColumnItem>

Consulte también
Creación de una vista de tabla

Elemento Alignment para TableColumnItem para TableControl

Elemento TableColumnItems

Elemento FormatString para TableColumnItem para TableControl

Elemento PropertyName para TableColumnItem para TableControl

Elemento ScriptBlock para TableColumnItem para TableControl

Escritura de un archivo de formato de PowerShell


Elemento Alignment para
TableColumnItem
Artículo • 24/09/2021

Define cómo se muestran los datos de una columna de la fila.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento TableColumnItems
Elemento TableColumnItem
Elemento Alignment

Sintaxis
XML

<Alignment>AlignmentType</Alignment>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del Alignment elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define una etiqueta, el ancho y la alineación de los datos de una


TableColumnItem columna de la tabla.

Valor de texto
Especifique uno de los valores siguientes. (Estos valores no distinguen mayúsculas de
minúsculas).

Izquierda: desplaza los datos mostrados en la columna a la izquierda. (Este es el


valor predeterminado si no se especifica este elemento).
Derecha: desplaza los datos mostrados en la columna a la derecha.
Centro: centra los datos mostrados en la columna.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Vista
de tabla.

Consulte también
Vista tabla

Elemento TableColumnItem
Elemento FormatString para
TableColumnItem for TableControl
Artículo • 19/01/2022

Especifica un patrón de formato que define cómo se muestra la propiedad o el valor de


script de la tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento TableColumnItems
Elemento TableColumnItem
Elemento FormatString

Sintaxis
XML

<FormatString>FormatPattern</FormatString>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FormatString elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define la propiedad o script cuyo valor se muestra en la columna de


TableColumnItem la fila.

Valor de texto
Especifique el patrón que se usa para dar formato a los datos. Por ejemplo, este patrón
se puede usar para dar formato al valor de cualquier propiedad que sea de tipo
System.Timespan: {0:MMM}{0:dd}{0:HH}:{0:mm}.

Comentarios
Las cadenas de formato se pueden usar al crear vistas de tabla, vistas de lista, vistas
anchas o vistas personalizadas. Para obtener más información sobre cómo dar formato a
un valor que se muestra en una vista, vea Aplicar formato a los datos mostrados.

Para obtener más información sobre los componentes de una vista de tabla, vea Vista
de tabla.

Ejemplo
En el ejemplo siguiente se muestra cómo definir una cadena de formato para el valor de
la StartTime propiedad .

XML

<TableColumnItem>
<PropertyName>StartTime</PropertyName>
<FormatString>{0:MMM} {0:DD} {0:HH}:{0:MM}</FormatString>
</TableColumnItem>

Consulte también
Creación de una vista de tabla

Datos de formato mostrados

Elemento TableColumnItem
Escritura de un archivo de formato de PowerShell
Elemento PropertyName para
TableColumnItem para TableControl
Artículo • 27/09/2021

Especifica la propiedad cuyo valor se muestra en la columna de la fila.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento TableColumnItems
Elemento TableColumnItem
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define la propiedad o script cuyo valor se muestra en la columna de


TableColumnItem la fila.

Valor de texto
Especifique el nombre de la propiedad cuyo valor se muestra.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En este ejemplo se TableColumnItem muestra un elemento que especifica la propiedad
del objeto Status System.Diagnostics.Process.

XML

<TableColumnItem>
<Alignment>Centered</Alignment>
<PropertyName>Status</PropertyName>
</TableColumnItem>

Consulte también
Creación de una vista de tabla

Elemento TableColumnItem

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
TableColumnItem para TableControl
Artículo • 27/09/2021

Especifica el script cuyo valor se muestra en la columna de la fila.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento TableColumnItems
Elemento TableColumnItem
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define la propiedad o script cuyo valor se muestra en la columna de


TableColumnItem la fila.

Valor de texto
Especifique el script cuyo valor se muestra.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Elemento TableColumnItem

Escritura de un archivo de formato de PowerShell


Elemento TableRowEntry
Artículo • 24/09/2021

Define los datos que se muestran en una fila de la tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries para TableControl
Elemento TableRowEntry para TableRowEntries

Sintaxis
XML

<TableRowEntry>
<Wrap/>
<EntrySelectedBy>...</EntrySelectedBy>
<TableColumnItems>...</TableColumnItems>
</TableRowEntry>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TableRowEntry elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento EntrySelectedBy para Elemento necesario.


TableRowEntry para TableControl
Define los objetos cuyos valores de propiedad se
muestran en la fila.

Elemento TableColumnItems para Elemento necesario.


TableRowEntry para TableControl
Define las propiedades o scripts cuyos valores se
muestran.

Elemento Wrap para TableRowEntry para Elemento opcional.


TableControl
Especifica que el texto que supera el ancho de
columna se muestra en la línea siguiente.

Elementos primarios

Elemento Descripción

Elemento TableRowEntries para TableControl Define las filas de la tabla.

Comentarios
Se TableColumnItems deben especificar un elemento y un EntrySelectedBy elemento.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En el ejemplo siguiente se muestra un elemento que define una fila que muestra los
valores de dos propiedades del objeto TableRowEntry System.Diagnostics.Process.

XML

<TableRowEntry>
<EntrySelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</EntrySelectedBy>
<TableColumnItems>
<TableColumnItem>
<PropertyName> Property for first column</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName> Property for second column</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>

Consulte también
Creación de una vista de tabla

Elemento EntrySelectedBy para TableRowEntry para TableControl

Elemento TableColumnItems para TableRowEntry para TableControl

Elemento TableRowEntries para TableControl

Elemento Wrap para TableRowEntry para TableControl

Escritura de un archivo de formato de PowerShell


Elemento EntrySelectedBy para
TableRowEntry
Artículo • 24/09/2021

Define los tipos de .NET que usan esta definición de la vista de tabla o la condición que
debe existir para que se use esta definición.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento .

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy para TableControl
Define la condición que debe existir para que se
utilice esta definición de vista de tabla.

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy para TableControl
Especifica un conjunto de tipos de .NET que usan
esta definición de vista de tabla.

Elemento TypeName para Elemento opcional.


EntrySelectedBy para TableControl
Especifica un tipo de .NET que usa esta definición de
vista de tabla.

Elementos primarios

Elemento Descripción

Elemento TableRowEntry para Define los datos que se muestran en una fila de la
TableControl tabla.

Comentarios
Debe especificar al menos un tipo, conjunto de selección o condición de selección para
una definición de vista de tabla. No hay ningún límite máximo en el número de
elementos secundarios que puede usar.

Las condiciones de selección se usan para definir una condición que debe existir para
que se utilice la definición, como cuando un objeto tiene una propiedad específica o
cuando un valor de propiedad o script específico se evalúa como true . Para obtener
más información sobre las condiciones de selección, vea Definir condiciones para
cuando seusa una entrada de vista o un elemento .

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Ejemplo
En el ejemplo siguiente se muestra un elemento que se usa para mostrar TableRowEntry
las propiedades del objeto System.Diagnostics.Process.
XML

<TableRowEntry>
<EntrySelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</EntrySelectedBy>
<TableColumnItems>
<TableColumnItem>
<PropertyName>PropertyForFirstColumn</PropertyName>
</TableColumnItem>
<TableColumnItem>
<PropertyName>PropertyForSecondColumn</PropertyName>
</TableColumnItem>
</TableColumnItems>
</TableRowEntry>

Consulte también
Creación de una vista de tabla

Elemento SelectionCondition para EntrySelectedBy para TableControl

Elemento SelectionSetName para EntrySelectedBy para TableControl

Elemento TableRowEntry para TableControl

Elemento TypeName para EntrySelectedBy para TableControl

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy para TableControl
Artículo • 24/09/2021

Define la condición que debe existir para usar para esta definición de la vista de tabla.
No hay ningún límite en el número de condiciones de selección que se pueden
especificar para una definición de tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del elemento SelectionCondition.

Atributos
Ninguno.
Elementos secundarios

Elemento Descripción

Elemento PropertyName para SelectionCondition for Elemento opcional.


EntrySelectedBy for TableRowEntry
Especifica la propiedad .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition for Elemento opcional.


EntrySelectedBy for TableRowEntry
Especifica el script que desencadena la
condición.

Elemento SelectionSetName para SelectionCondition Elemento opcional.


for EntrySelectedBy for TableRowEntry
Especifica el conjunto de tipos de .NET
que desencadenan la condición.

Elemento TypeName para SelectionCondition for Elemento opcional.


EntrySelectedBy for TableRowEntry
Especifica un tipo de .NET que
desencadena la condición.

Elementos primarios

Elemento Descripción

Elemento EntrySelectedBy Define los tipos de .NET que usan esta entrada de tabla o la
para TableRowEntry condición que debe existir para que se use esta entrada.

Comentarios
Cada entrada de lista debe tener al menos un nombre de tipo, un conjunto de selección
o una condición de selección definidos.

Al definir una condición de selección, se aplican los siguientes requisitos:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.

Para obtener más información sobre cómo usar condiciones de selección, vea Definir
condiciones para cuando se usa una entrada de vista o un elemento.
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Definir condiciones para cuando se muestran los datos

Elemento EntrySelectedBy

Elemento PropertyName para SelectionCondition for EntrySelectedBy for TableRowEntry

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for TableRowEntry

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


TableRowEntry

Elemento TypeName para SelectionCondition for EntrySelectedBy for TableRowEntry

Escribir un archivo Windows PowerShell de tipos y formato


Elemento PropertyName para
SelectionCondition for EntrySelectedBy
for TableRowEntry
Artículo • 24/09/2021

Especifica la propiedad .NET que desencadena la condición. Cuando esta propiedad está
presente o cuando se evalúa como true , se cumple la condición y se usa la entrada de
tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy para TableRowEntry utilice esta entrada de tabla.

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
bloque de script, pero no puede especificar ambos. Para obtener más información sobre
cómo se pueden usar las condiciones de selección, vea Definir condiciones para cuando
se usa una entrada de vista o un elemento.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Definir condiciones para cuando se muestran los datos

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for TableRowEntry

Elemento SelectionCondition para EntrySelectedBy para TableRowEntry

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for EntrySelectedBy
for TableControl
Artículo • 27/09/2021

Especifica el bloque de script que desencadena la condición. Cuando este script se


evalúa como true , se cumple la condición y se usa la entrada de tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy para TableRowEntry utilice esta entrada de tabla.

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o bloque
de script, pero no puede especificar ambos. Para obtener más información sobre cómo
usar condiciones de selección, vea Definir condiciones para cuando se usa una entrada
de vista o un elemento.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Definir condiciones para cuando se muestran los datos

Elemento PropertyName para SelectionCondition for EntrySelectedBy for TableRowEntry

Elemento SelectionCondition para EntrySelectedBy para TableRowEntry

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
SelectionCondition for EntrySelectedBy
for TableControl
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante esta definición de la vista de tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para usar para
EntrySelectedBy for TableRowEntry esta definición de la vista de tabla.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
La condición de selección puede especificar un conjunto de selección o un tipo de .NET,
pero no puede especificar ambos. Para obtener más información sobre cómo usar
condiciones de selección, vea Definición de condiciones para cuando se muestran datos.

Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
objetos.

Para obtener más información sobre otros componentes de una vista amplia, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Definir condiciones para cuando se muestran los datos

Elemento TypeName para SelectionCondition for EntrySelectedBy for TableRowEntry

Elemento SelectionCondition para EntrySelectedBy for TableRowEntry

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for EntrySelectedBy
for TableControl
Artículo • 27/09/2021

Especifica un tipo de .NET que desencadena la condición. Cuando este tipo está
presente, se cumple la condición y se usa la fila de tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy para TableRowEntry utilice esta fila de tabla.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
La condición de selección puede especificar cualquier número de tipos o conjuntos de
selección de .NET, pero no puede especificar ambos. Para obtener más información
sobre cómo usar condiciones de selección, vea Definir condiciones para cuando se usa
una entrada de vista o un elemento.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Definir condiciones para cuando se muestran los datos

Elemento SelectionCondition para EntrySelectedBy para TableRowEntry

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for


TableRowEntry

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy para TableControl
Artículo • 24/09/2021

Especifica un conjunto de tipos de .NET que usan esta entrada de la vista de tabla. No
hay ningún límite en el número de conjuntos de selección que se pueden especificar
para una entrada.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las siguientes secciones se describen los atributos, los elementos secundarios y los
elementos primarios.

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta entrada o la condición que debe
EntrySelectedBy existir para que se use esta entrada.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de
objetos que se usan en varias vistas. Por ejemplo, puede que desee crear una vista de
tabla y una vista de lista para el mismo conjunto de objetos. Para obtener más
información sobre cómo definir conjuntos de selección, vea Definir conjuntos de objetos
para una vista.

Si especifica un conjunto de selección para una entrada, no puede especificar un


nombre de tipo. Para obtener más información sobre cómo especificar un tipo de .NET,
vea Elemento TypeName para EntrySelectedBy para TableRowEntry.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Elemento EntrySelectedBy

Definir conjuntos de objetos para una vista

Creación de una vista de tabla

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy para TableControl
Artículo • 24/09/2021

Especifica un tipo de .NET que usa esta entrada de la vista de tabla. No hay ningún
límite en el número de tipos que se pueden especificar para una entrada de tabla.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries
Elemento TableRowEntry
Elemento EntrySelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta entrada o la condición que debe
EntrySelectedBy existir para que se use esta entrada.

Valor de texto
Especifique el nombre del tipo de .NET.

Comentarios
Cada entrada de lista debe tener al menos un nombre de tipo, un conjunto de selección
o una condición de selección definidos.

Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Elemento EntrySelectedBy

Escritura de un archivo de formato de PowerShell


Elemento Wrap para TableRowEntry
Artículo • 27/09/2021

Especifica que el texto que supera el ancho de columna se muestra en la línea siguiente.
De forma predeterminada, el texto que supera el ancho de columna se trunca.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento TableControl
Elemento TableRowEntries para TableControl
Elemento TableRowEntry para TableRowEntries para TableControl
Elemento Wrap para TableRowEntry para TableControl

Sintaxis
XML

<Wrap/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del Wrap elemento.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios
Elemento Descripción

Elemento TableRowEntry para TableRowEntries Define los datos que se muestran en una fila
para TableControl de la tabla.

Comentarios
Para obtener más información sobre los componentes de una vista de tabla, vea Crear
una vista de tabla.

Consulte también
Creación de una vista de tabla

Elemento TableRowEntry para TableRowEntries para TableControl

Escritura de un archivo de formato de PowerShell


Elemento ViewSelectedBy
Artículo • 27/09/2021

Define los objetos .NET que muestra la vista. Cada vista debe especificar al menos un
objeto .NET.

Schema
Elemento ViewDefinitions
Elemento View
Elemento ViewSelectedBy

Sintaxis
XML

<ViewSelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>SelectionSet</SelectionSetName>
</ViewSelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ViewSelectedBy elemento . Este elemento debe contener al
menos uno TypeName o SelectionSetName un elemento secundario. No hay ningún límite
en el número de elementos secundarios que se pueden especificar ni su orden es
significativo.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento TypeName para ViewSelectedBy Elemento opcional.

Especifica un objeto .NET que muestra la vista.

Elemento SelectionSetName para Elemento opcional.


ViewSelectedBy
Especifica un conjunto de objetos .NET que muestra
la vista.

Elementos primarios

Elemento Descripción

Elemento View Define una vista que muestra uno o varios objetos .NET.

Comentarios
Para obtener más información sobre cómo se usa este elemento en diferentes vistas,
vea Componentes de vista de tabla ,Componentes de vista de lista ,Componentes de
vista ancha y Componentes de control personalizados.

El SelectionSetName elemento se usa cuando el archivo de formato define un conjunto


de objetos que se muestran en varias vistas. Para obtener más información sobre cómo
se definen y hacen referencia a los conjuntos de selección, vea Definir conjuntos de
objetos.

Ejemplo
En el ejemplo siguiente se muestra cómo especificar el objeto
System.Serviceprocess.Servicecontroller para una vista de lista. El mismo esquema se usa
para vistas de tabla, anchas y personalizadas.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>
Consulte también
Creación de una vista de lista

Creación de una vista de tabla

Creación de una vista amplia

Creación de controles personalizados

Definición de conjuntos de selección

Elemento SelectionSetName para ViewSelectedBy

Elemento TypeName

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
ViewSelectedBy
Artículo • 24/09/2021

Especifica un conjunto de objetos .NET que la vista muestra.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ViewSelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>Name of selection set<SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción
Elemento Descripción

Elemento ViewSelectedBy Define los objetos .NET que se muestran en la vista.

Valor de texto
Especifique el nombre del conjunto de selección definido por el Name elemento para el
conjunto de selección.

Comentarios
Puede usar conjuntos de selección cuando tenga un conjunto de objetos relacionados a
los que desea hacer referencia mediante un solo nombre, como un conjunto de objetos
relacionados a través de la herencia. Para obtener más información sobre cómo definir y
hacer referencia a conjuntos de selección, vea Definir conjuntos de objetos.

Ejemplo
En el ejemplo siguiente se muestra cómo especificar un conjunto de selección para una
vista de lista. El mismo esquema se usa para vistas de tabla, anchas y personalizadas.

XML

<View>
<Name>Name of View</Name>
<ViewSelectedBy>
<SelectionSetName>NameofSelectionSet</SelectionSetName>>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>

Consulte también
Definición de conjuntos de selección

Elemento ViewSelectedBy

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
ViewSelectedBy
Artículo • 27/09/2021

Especifica un objeto .NET que muestra la vista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento ViewSelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>FullyQualifiedTypeName</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y los
elementos primarios del TypeName elemento.

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción
Elemento Descripción

Elemento ViewSelectedBy Define los objetos .NET que muestra la vista.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
Para obtener más información sobre cómo se usa este elemento en diferentes vistas,
vea Crear una vista de tabla ,Crear una vista de lista ,Crear una vista ancha y
Componentes de vista personalizados.

Ejemplo
En el ejemplo siguiente se muestra cómo especificar el objeto
System.Serviceprocess.Servicecontroller para una vista de lista. El mismo esquema se usa
para vistas de tabla, anchas y personalizadas.

XML

<View>
<Name>System.ServiceProcess.ServiceController</Name>
<ViewSelectedBy>
<TypeName>System.ServiceProcess.ServiceController</TypeName>
</ViewSelectedBy>
<ListControl>...</ListControl>
</View>

Consulte también
Creación de una vista de lista

Creación de una vista de tabla

Creación de una vista amplia

Creación de controles personalizados

Elemento ViewSelectedBy
Escritura de un archivo de formato de PowerShell
Elemento WideControl
Artículo • 24/09/2021

Define un formato de lista ancho (valor único) para la vista. Esta vista muestra un valor
de propiedad única o un valor de script para cada objeto.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl

Sintaxis
XML

<WideControl>
<AutoSize/>
<ColumnNumber>PositiveInteger</ColumnNumber>
<WideEntries>...</WideEntries>
</WideControl>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del WideControl elemento . No se pueden especificar AutoSize los
elementos y al mismo ColumnNumber tiempo.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento AutoSize para Elemento opcional.


WideControl
Especifica si el tamaño de columna y el número de columnas se
ajustan en función del tamaño de los datos.

Elemento ColumnNumber Elemento opcional.


para WideControl
Especifica el número de columnas que se muestran en la vista
ancha.

Elemento WideEntries Elemento necesario.

Proporciona las definiciones de la vista ancha.

Elementos primarios

Elemento Descripción

Elemento View Define una vista que se usa para mostrar uno o varios objetos .NET.

Comentarios
Al definir una vista ancha, puede agregar el AutoSize elemento o , pero no puede
agregar ColumnNumber ambos.

En la mayoría de los casos, solo se requiere una definición para cada vista ancha, pero es
posible tener varias definiciones si desea usar la misma vista para mostrar diferentes
objetos .NET. En esos casos, puede proporcionar una definición independiente para
cada objeto o conjunto de objetos.

Para obtener más información sobre los componentes de una vista ancha, vea
Componentes de vista ancha.

Ejemplo
En el ejemplo siguiente se WideControl muestra un elemento que se usa para mostrar
una propiedad del objeto System.Diagnostics.Process.

XML

<View>
<Name>process</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<WideControl>
<WideEntries>...</WideEntries>
</WideControl>
</View>

Para obtener un ejemplo completo de una vista ancha, vea Vista ancha (básica).

Consulte también
Elemento Autosize para WideControl

Elemento ColumnNumber para WideControl

Elemento View

Elemento WideEntries

Vista amplia (Basic)

Creación de una vista amplia

Escritura de un archivo de formato de PowerShell


Elemento AutoSize para WideControl
Artículo • 24/09/2021

Especifica si el tamaño de columna y el número de columnas se ajustan en función del


tamaño de los datos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento Autosize

Sintaxis
XML

<AutoSize/>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del AutoSize elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno

Elementos primarios

Elemento Descripción

Elemento WideControl Define un formato de lista ancho (valor único) para la vista.
Comentarios
Al definir una vista ancha, puede agregar el AutoSize elemento o el elemento
ColumnNumber, pero no puede agregar ambos.

Para obtener más información sobre los componentes de una vista ancha, vea Crear una
vista ancha.

Para obtener un ejemplo de una vista amplia, vea Wide View (Basic).

Consulte también
Elemento ColumnNumber para WideControl

Creación de una vista amplia

Elemento WideControl

Escritura de un archivo de formato de PowerShell


Elemento ColumnNumber para
WideControl
Artículo • 24/09/2021

Especifica el número de columnas que se muestran en la vista ancha.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento ColumnNumber

Sintaxis
XML

<ColumnNumber>PositiveInteger</ColumnNumber>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ColumnNumber elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción
Elemento Descripción

Elemento WideControl Define un formato de lista ancho (valor único) para la vista.

Valor de texto
Especifique un valor entero positivo.

Comentarios
Al definir una vista ancha, puede agregar el AutoSize elemento o el elemento , pero no
puede agregar ColumnNumber ambos.

Para obtener más información sobre los componentes de una vista ancha, vea Creating
a Wide View.

Para obtener un ejemplo de una vista ancha, vea Vista ancha (básica).

Consulte también
Elemento Autosize para WideControl

Creación de una vista amplia

Vista amplia (Basic)

Escritura de un archivo de formato de PowerShell


Elemento WideEntries
Artículo • 27/09/2021

Proporciona las definiciones de la vista ancha. La vista ancha debe especificar una o
varias definiciones.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries

Sintaxis
XML

<WideEntries>
<WideEntry>...</WideEntry>
</WideEntries>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del WideEntries elemento . Se debe especificar al menos un
elemento secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento WideEntry Proporciona una definición de la vista ancha.


Elementos primarios

Elemento Descripción

Elemento WideControl Define un formato de lista ancho (valor único) para la vista.

Comentarios
Una vista ancha es un formato de lista que muestra un valor de propiedad único o un
valor de script para cada objeto. Para obtener más información sobre los componentes
de una vista ancha, vea Componentes de vista ancha.

Ejemplo
En el ejemplo siguiente se WideEntries muestra un elemento que define un único
WideEntry elemento. El WideEntry elemento contiene un único elemento que define

qué propiedad o valor de script se muestra en la WideItem vista.

XML

<WideControl>
<WideEntries>
<WideEntry>
<WideItem>...</WideItem>
<WideEntry>
</WideEntries>
</WideControl>

Para obtener un ejemplo completo de una vista ancha, vea Vista ancha (básica).

Consulte también
Creación de una vista amplia

Elemento WideControl

Elemento WideEntry

Escritura de un archivo de formato de PowerShell


Elemento WideEntry
Artículo • 24/09/2021

Proporciona una definición de la vista ancha.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry

Sintaxis
XML

<WideEntry>
<EntrySelectedBy>...</EntrySelectedBy>
<WideItem>...</WideItem>
</WideEntry>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del WideEntry elemento . Debe especificar un único WideItem
elemento secundario.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción
Elemento Descripción

Elemento Elemento opcional.


EntrySelectedBy para
WideEntry Define los tipos de .NET que usan esta definición de entrada amplia o la
condición que debe existir para que se use esta definición.

Elemento WideItem Elemento necesario.

Define la propiedad o script cuyo valor se muestra.

Elementos primarios

Elemento Descripción

Elemento WideEntries Proporciona las definiciones de la vista ancha.

Comentarios
Una vista ancha es un formato de lista que muestra un valor de propiedad único o un
valor de script para cada objeto. A diferencia de otros tipos de vistas, solo puede
especificar un elemento para cada definición de vista. Para obtener más información
sobre los demás componentes de una vista amplia, vea Crear una vista ancha.

Ejemplo
En el ejemplo siguiente se muestra WideEntry un elemento que define un único
WideItem elemento. El WideItem elemento define la propiedad cuyo valor se muestra en

la vista.

XML

<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>

Para obtener un ejemplo completo de una vista amplia, vea Wide View (Básico).
Consulte también
Creación de una vista amplia

Elemento SelectionCondition para WideEntry

Elemento SelectionSetName para WideEntry

Elemento TypeName para WideEntry

Elemento WideEntries

Elemento WideItem

Escritura de un archivo de formato de PowerShell


Elemento EntrySelectedBy para
WideEntry
Artículo • 24/09/2021

Define los tipos de .NET que usan esta definición de la vista ancha o la condición que
debe existir para que se use esta definición.

Schema
Elemento Configuration ViewDefinitions Elemento de vista de elemento WideControl
Elemento WideEntries Elemento WideEntry EntrySelectedBy Element

Sintaxis
XML

<EntrySelectedBy>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<SelectionCondition>...</SelectionCondition>
</EntrySelectedBy>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del EntrySelectedBy elemento .

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento SelectionCondition para Elemento opcional.


EntrySelectedBy para WideEntry
Define la condición que debe existir para que se
utilice esta definición de vista ancha.
Elemento Descripción

Elemento SelectionSetName para Elemento opcional.


EntrySelectedBy for WideEntry
Especifica un conjunto de tipos de .NET que usan esta
definición de vista ancha.

Elemento TypeName para Elemento opcional.


EntrySelectedBy for WideEntry
Especifica un tipo de .NET que usa esta definición de
vista ancha.

Elementos primarios

Elemento Descripción

Elemento WideEntry Proporciona una definición de la vista ancha.

Comentarios
Debe especificar al menos un tipo, conjunto de selección o condición de selección para
una definición de vista ancha. No hay ningún límite máximo en el número de elementos
secundarios que puede usar.

Las condiciones de selección se usan para definir una condición que debe existir para la
definición que se va a usar, como cuando un objeto tiene una propiedad específica o
cuando un valor de propiedad o script específico se evalúa como true . Para obtener
más información sobre las condiciones de selección, vea Definir condiciones para
mostrar datos.

Para obtener más información sobre otros componentes de una vista ancha, vea
Creating a Wide View.

Consulte también
Elemento WideEntry

Elemento SelectionCondition para EntrySelectedBy para WideEntry

Elemento SelectionSetName para EntrySelectedBy for WideEntry

Elemento TypeName para EntrySelectedBy for WideEntry


Creación de una vista amplia

Definición de condiciones para mostrar datos

Escritura de un archivo de formato de PowerShell


Elemento SelectionCondition para
EntrySelectedBy para WideControl
Artículo • 24/09/2021

Define la condición que debe existir para que se utilice esta definición. No hay ningún
límite en el número de condiciones de selección que se pueden especificar para una
definición de entrada amplia.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento EntrySelectedBy
Elemento SelectionCondition

Sintaxis
XML

<SelectionCondition>
<TypeName>Nameof.NetType</TypeName>
<SelectionSetName>NameofSelectionSet</SelectionSetName>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToEvaluate</ScriptBlock>
</SelectionCondition>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionCondition elemento . Debe especificar un único
PropertyName elemento ScriptBlock o . Los SelectionSetName elementos y son
TypeName opcionales. Puede especificar uno de los dos elementos.

Atributos
Ninguno.

Elementos secundarios

Elemento Descripción

Elemento PropertyName para SelectionCondition for Elemento opcional.


EntrySelectedBy for WideEntry
Especifica la propiedad de .NET que
desencadena la condición.

Elemento ScriptBlock para SelectionCondition for Elemento opcional.


EntrySelectedBy for WideEntry
Especifica el bloque de script que
desencadena la condición.

Elemento SelectionSetName para SelectionCondition Elemento opcional.


for EntrySelectedBy for WideEntry
Especifica el conjunto de tipos de .NET
que desencadena la condición.

Elemento TypeName para SelectionCondition for Elemento opcional.


EntrySelectedBy for WideEntry
Especifica un tipo de .NET que
desencadena la condición.

Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta entrada ancha o la condición
EntrySelectedBy para que debe existir para que se use esta entrada.
WideEntry

Comentarios
Cada entrada ancha debe tener al menos un nombre de tipo, un conjunto de selección
o una condición de selección definidos.

Al definir una condición de selección, se aplican los siguientes requisitos:

La condición de selección debe especificar al menos un nombre de propiedad o un


bloque de script, pero no puede especificar ambos.
La condición de selección puede especificar cualquier número de tipos o conjuntos
de selección de .NET, pero no puede especificar ambos.
Para obtener más información sobre cómo usar condiciones de selección, vea Definir
condiciones para cuando se usa una entrada de vista o un elemento.

Para obtener más información sobre otros componentes de una vista amplia, vea
Creating a Wide View.

Consulte también
Creación de una vista amplia

Definir condiciones para cuando se muestran los datos

Elemento EntrySelectedBy para WideEntry

Elemento PropertyName para SelectionCondition for EntrySelectedBy for WideEntry

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for WideEntry

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for WideEntry

Elemento TypeName para SelectionCondition for EntrySelectedBy for WideEntry

Escritura de un archivo de formato de PowerShell


Elemento PropertyName para
SelectionCondition for EntrySelectedBy
for WideEntry
Artículo • 27/09/2021

Especifica la propiedad de .NET que desencadena la condición. Cuando esta propiedad


está presente o cuando se evalúa como true , se cumple la condición y se usa la
definición.

Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

C#

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy for WideEntry utilice esta definición.

Valor de texto
Especifique el nombre de la propiedad .NET.

Comentarios
La condición de selección debe especificar al menos un nombre de propiedad o un
script para evaluar, pero no puede especificar ambos. Para obtener más información
sobre cómo usar las condiciones de selección, vea Definición de condiciones para
cuando se muestran datos.

Para obtener más información sobre otros componentes de una vista amplia, vea Wide
View.

Consulte también
Creación de una vista amplia

Definir condiciones para cuando se muestran los datos

Elemento ScriptBlock para SelectionCondition for EntrySelectedBy for WideEntry

Elemento SelectionCondition para EntrySelectedBy for WideEntry

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para
SelectionCondition for EntrySelectedBy
for WideControl
Artículo • 24/09/2021

Especifica el script que desencadena la condición. Cuando este script se evalúa como
true , se cumple la condición y se usa la definición de entrada ancha.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento EntrySelectedBy
SelectionCondition
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToEvaluate</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy para WideEntry utilice esta definición.

Valor de texto
Especifique el script que se evalúa.

Comentarios
La condición de selección debe especificar al menos un nombre de script o propiedad
para evaluar, pero no puede especificar ambos. Para obtener más información sobre
cómo usar las condiciones de selección, vea Definir condiciones para cuando se
muestran los datos.

Para obtener más información sobre otros componentes de una vista ancha, vea Vista
ancha.

Consulte también
Creación de una vista amplia

Definir condiciones para cuando se muestran los datos

Elemento PropertyName para SelectionCondition for EntrySelectedBy for WideEntry

Elemento SelectionCondition para EntrySelectedBy para WideEntry

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
SelectionCondition for EntrySelectedBy
for WideEntry
Artículo • 24/09/2021

Especifica el conjunto de tipos de .NET que desencadenan la condición. Cuando


cualquiera de los tipos de este conjunto está presente, se cumple la condición y el
objeto se muestra mediante esta definición de la vista ancha.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.
Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy para WideEntry utilice esta definición.

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
La condición de selección puede especificar un conjunto de selección o un tipo de .NET,
pero no puede especificar ambos. Para obtener más información sobre cómo usar las
condiciones de selección, vea Definir condiciones para cuando se muestran los datos.

Los conjuntos de selección son grupos comunes de objetos .NET que puede usar
cualquier vista que defina el archivo de formato. Para obtener más información sobre
cómo crear y hacer referencia a conjuntos de selección, vea Definir conjuntos de
objetos.

Para obtener más información sobre otros componentes de una vista ancha, vea
Creating a Wide View.

Consulte también
Creación de una vista amplia

Definir condiciones para cuando se muestran los datos

Definición de conjuntos de selección

Elemento SelectionCondition para EntrySelectedBy para WideEntry

Elemento TypeName para SelectionCondition for EntrySelectedBy for WideEntry

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
SelectionCondition for EntrySelectedBy
for WideControl
Artículo • 24/09/2021

Especifica un tipo de .NET que desencadena la condición. Cuando este tipo está
presente, se usa la definición.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento EntrySelectedBy
Elemento SelectionCondition
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción

Elemento SelectionCondition para Define la condición que debe existir para que se
EntrySelectedBy para WideEntry utilice esta entrada ancha.

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
La condición de selección puede especificar un tipo de .NET o un conjunto de selección,
pero no puede especificar ambos. Para obtener más información sobre cómo usar las
condiciones de selección, vea Definir condiciones para cuando se muestran los datos.

Para obtener más información sobre otros componentes de una vista ancha, vea Crear
una vista ancha.

Consulte también
Creación de una vista amplia

Definir condiciones para cuando se muestran los datos

Elemento SelectionCondition para EntrySelectedBy para WideEntry

Elemento SelectionSetName para SelectionCondition for EntrySelectedBy for WideEntry

Escritura de un archivo de formato de PowerShell


Elemento TypeName para
EntrySelectedBy for WideEntry
Artículo • 24/09/2021

Especifica un tipo de .NET para la definición. La definición se usa siempre que se


muestra este objeto.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento EntrySelectedBy
Elemento TypeName

Sintaxis
XML

<TypeName>Nameof.NetType</TypeName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del TypeName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta entrada ancha o la condición
EntrySelectedBy para que debe existir para que se use esta entrada.
WideEntry

Valor de texto
Especifique el nombre completo del tipo .NET, como System.IO.DirectoryInfo .

Comentarios
Cada entrada ancha debe especificar uno o varios tipos de .NET, un conjunto de
selección o la condición de selección que debe existir para que se utilice la definición.

Para obtener más información sobre otros componentes de una vista ancha, vea
Creating a Wide View.

Consulte también
Creación de una vista amplia

Elemento EntrySelectedBy para WideEntry

Escritura de un archivo de formato de PowerShell


Elemento SelectionSetName para
EntrySelectedBy para WideControl
Artículo • 24/09/2021

Especifica un conjunto de objetos .NET para la definición. La definición se usa siempre


que se muestra uno de estos objetos.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento EntrySelectedBy
Elemento SelectionSetName

Sintaxis
XML

<SelectionSetName>NameofSelectionSet</SelectionSetName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del SelectionSetName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.
Elementos primarios

Elemento Descripción

Elemento Define los tipos de .NET que usan esta entrada ancha o la condición
EntrySelectedBy para que debe existir para que se use esta entrada.
WideEntry

Valor de texto
Especifique el nombre del conjunto de selección.

Comentarios
Cada definición debe especificar un nombre de tipo, un conjunto de selección o una
condición de selección.

Los conjuntos de selección se usan normalmente cuando se desea definir un grupo de


objetos que se usan en varias vistas. Por ejemplo, puede crear una vista de tabla y una
vista de lista para el mismo conjunto de objetos. Para obtener más información sobre
cómo definir conjuntos de selección, vea Definir conjuntos de objetos para una vista.

Para obtener más información sobre otros componentes de una vista amplia, vea
Creating a Wide View.

Consulte también
Creación de una vista amplia

Definición de conjuntos de selección

Elemento EntrySelectedBy para WideEntry

Escritura de un archivo de formato de PowerShell


Elemento WideItem para WideControl
Artículo • 27/09/2021

Define la propiedad o script cuyo valor se muestra.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento WideItem

Sintaxis
XML

<WideItem>
<PropertyName>.NetTypeProperty</PropertyName>
<ScriptBlock>ScriptToExecute</ScriptBlock>
<FormatString>FormatPattern</FormatString>
</WideItem>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del WideItem elemento . El elemento FormatString es opcional. Sin
embargo, debe especificar un PropertyName elemento o , pero no puede especificar
ScriptBlock ambos.

Atributos
Ninguno.

Elementos secundarios
Elemento Descripción

Elemento FormatString para Elemento opcional.


WideItem para WideControl
Especifica un patrón de formato que define cómo se muestra
la propiedad o el valor del script en la vista.

Elemento PropertyName para Especifica la propiedad del objeto cuyo valor se muestra en la
WideItem vista ancha.

Elemento ScriptBlock para Especifica el script cuyo valor se muestra en la vista ancha.
WideItem

Elementos primarios

Elemento Descripción

Elemento WideEntry Proporciona una definición de la vista ancha.

Comentarios
Para obtener más información sobre los componentes de una vista ancha, vea Wide
View.

Ejemplo
En el ejemplo siguiente se WideEntry muestra un elemento que define un único
WideItem elemento. El WideItem elemento define la propiedad o script cuyo valor se

muestra en la vista.

XML

<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>

Para obtener un ejemplo completo de una vista ancha, vea Vista ancha (básica).

Consulte también
Elemento FormatString para WideItem para WideControl
Elemento PropertyName para WideItem

Elemento ScriptBlock para WideItem

Elemento WideEntry

Escritura de un archivo de formato de PowerShell


Elemento FormatString para WideItem
Artículo • 19/01/2022

Especifica un patrón de formato que define cómo se muestra la propiedad o el valor del
script en la vista.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento WideItem
Elemento FormatString

Sintaxis
XML

<FormatString>PropertyPattern</FormatString>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del FormatString elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios
Elemento Descripción

Elemento WideItem for Define la propiedad o script cuyo valor se muestra en una fila de
WideControl la vista de lista.

Valor de texto
Especifique el patrón que se usa para dar formato a los datos. Por ejemplo, puede usar
este patrón para dar formato al valor de cualquier propiedad que sea de tipo
System.Timespan: {0:MMM}{0:dd}{0:HH}:{0:mm}.

Comentarios
Las cadenas de formato se pueden usar al crear vistas de tabla, vistas de lista, vistas
anchas o vistas personalizadas. Para obtener más información sobre cómo dar formato a
un valor que se muestra en una vista, vea Aplicar formato a los datos mostrados.

Para obtener más información sobre el uso de cadenas de formato en vistas anchas, vea
Creating a Wide View.

Ejemplo
En el ejemplo siguiente se muestra cómo definir una cadena de formato para el valor de
la StartTime propiedad .

XML

<WideItem>
<PropertyName>StartTime</PropertyName>
<FormatString>{0:MMM} {0:DD} {0:HH}:{0:MM}</FormatString>
</WideItem>

Consulte también
Creación de una vista amplia

Elemento WideItem for WideControl

Escribir un archivo Windows PowerShell de tipos y formato


Elemento PropertyName para WideItem
para WideControl
Artículo • 24/09/2021

Especifica la propiedad del objeto cuyo valor se muestra en la vista ancha.

Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento WideItem
Elemento PropertyName

Sintaxis
XML

<PropertyName>.NetTypeProperty</PropertyName>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del PropertyName elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios

Elemento Descripción
Elemento Descripción

Elemento WideItem Define la propiedad o script cuyo valor se muestra en la vista ancha.

Valor de texto
Especifique el nombre de la propiedad cuyo valor se muestra.

Comentarios
Para obtener más información sobre los componentes de una vista amplia, vea Crear
una vista ancha.

Ejemplo
En este ejemplo se muestra una vista amplia que muestra el valor de la propiedad
ProcessName del objeto System.Diagnostics.Process.

XML

View>
<Name>process</Name>
<ViewSelectedBy>
<TypeName>System.Diagnostics.Process</TypeName>
</ViewSelectedBy>
<WideControl>
<WideEntries>
<WideEntry>
<WideItem>
<PropertyName>ProcessName</PropertyName>
</WideItem>
</WideEntry>
</WideEntries>
</WideControl>
</View>

Consulte también
Elemento WideItem

Creación de una vista amplia

Escritura de un archivo de formato de PowerShell


Elemento ScriptBlock para WideItem
para WideControl
Artículo • 24/09/2021

Especifica el script cuyo valor se muestra en la vista ancha.

Schema
Elemento de configuración
Elemento ViewDefinitions
Elemento View
Elemento WideControl
Elemento WideEntries
Elemento WideEntry
Elemento WideItem
Elemento ScriptBlock

Sintaxis
XML

<ScriptBlock>ScriptToExecute</ScriptBlock>

Atributos y elementos
En las secciones siguientes se describen los atributos, los elementos secundarios y el
elemento primario del ScriptBlock elemento .

Atributos
Ninguno.

Elementos secundarios
Ninguno.

Elementos primarios
Elemento Descripción

Elemento Define la propiedad o el bloque de script cuyo valor se muestra en la vista


WideItem ancha.

Valor de texto
Especifique el script cuyo valor se muestra.

Comentarios
Para obtener más información sobre los componentes de una vista ancha, vea Crear una
vista ancha.

Ejemplo
En este ejemplo se WideItem muestra un elemento que define un script cuyo valor se
muestra en la vista.

XML

<WideItem>
<ScriptBlock>ScriptToExecute</ScriptBlock>
</WideItem>

Consulte también
Elemento WideItem

Creación de una vista amplia

Escritura de un archivo de formato de PowerShell


Escritura de ayuda para scripts y
funciones de PowerShell
Artículo • 25/09/2021

Los scripts y funciones de PowerShell deben documentarse completamente cada vez


que se compartan con otros usuarios. El cmdlet muestra los temas de ayuda de script y
función en el mismo formato que muestra ayuda para cmdlets, y todos los parámetros
funcionan en temas de ayuda de Get-Help Get-Help script y función.

Los scripts de PowerShell pueden incluir un tema de ayuda sobre el script y temas de
ayuda sobre cada función del script. Las funciones que se comparten
independientemente de los scripts pueden incluir sus propios temas de ayuda.

En este documento se explica el formato y la ubicación correcta de los temas de ayuda,


y se sugieren directrices para el contenido.

Tipos de Ayuda de script y función

Ayuda basada en comentarios


El tema de ayuda que describe un script o una función se puede implementar como un
conjunto de comentarios dentro del script o la función. Al escribir ayuda basada en
comentarios para un script y para las funciones de un script, preste mucha atención a las
reglas para colocar la ayuda basada en comentarios. La selección de ubicación
determina si el Get-Help cmdlet asocia el tema de ayuda con el script o una función.
Para obtener más información sobre cómo escribir temas de ayuda basados en
comentarios, vea about_Comment_Based_Help.

XML-Based Ayuda del comando


El tema de ayuda que describe un script o una función se puede implementar en un
archivo XML que usa el esquema de ayuda del comando. Para asociar el script o la
función al archivo XML, use la palabra clave comment seguida de la ruta de acceso y el
nombre ExternalHelp del archivo XML.

Cuando la palabra clave comment está presente, tiene prioridad sobre la ayuda basada
en comentarios, incluso cuando no puede encontrar un archivo de ayuda que coincida
con el ExternalHelp valor de la palabra clave Get-Help ExternalHelp .
Ayuda en línea
Puede publicar los temas de ayuda en Internet y, a continuación, dirigir Get-Help para
abrir los temas. Para obtener más información sobre cómo escribir temas de ayuda
basados en comentarios, vea Supporting Online Help.

No hay ningún método establecido para escribir temas conceptuales ("Acerca de") para
scripts y funciones. Sin embargo, puede publicar temas conceptuales en Internet para
enumerar los temas y sus direcciones URL en la sección Vínculos relacionados de un
tema de ayuda de comandos.

Consideraciones de contenido para la Ayuda de


script y función
Si está escribiendo un tema de ayuda muy breve con solo algunas de las secciones
de ayuda de comandos disponibles, asegúrese de incluir descripciones claras de
los parámetros de script o función. Incluya también uno o dos comandos de
ejemplo en la sección de ejemplos, incluso si decide omitir las descripciones de
ejemplo.

En todas las descripciones, consulte el comando como script o función. Esta


información ayuda al usuario a comprender y administrar el comando.

Por ejemplo, la siguiente descripción detallada indica que New-Topic comando es


un script. Esto recuerda a los usuarios que deben especificar la ruta de acceso y el
nombre completo cuando la ejecutan.

"El script New-Topic crea un tema conceptual en blanco para cada nombre de
tema en el archivo de entrada..."

La siguiente descripción detallada indica que Disable-PSRemoting es una función.


Esta información es especialmente útil para los usuarios cuando la sesión incluye
varios comandos con el mismo nombre, algunos de los cuales podrían estar
ocultos por un comando con mayor prioridad.

La Disable-PSRemoting función deshabilita todas las configuraciones de sesión


en el equipo local...

En un tema de ayuda de script, explique cómo usar el script como un todo. Si


también escribe temas de ayuda para las funciones del script, mencione las
funciones del tema de ayuda de script e incluya referencias a los temas de ayuda
de la función en la sección Vínculos relacionados del tema de ayuda de script. Por
el contrario, cuando una función forma parte de un script, explique en el tema de
ayuda de la función el rol que la función desempeña en el script y cómo se podría
usar de forma independiente. A continuación, enumérea el tema de ayuda de
script en la sección Vínculos relacionados del tema de ayuda de la función.

Al escribir ejemplos para un tema de ayuda de script, asegúrese de incluir la ruta


de acceso al archivo de script en el comando de ejemplo. Esto recuerda a los
usuarios que deben especificar la ruta de acceso explícitamente, incluso cuando el
script está en el directorio actual.

En un tema de ayuda de función, recuerde a los usuarios que la función solo existe
en la sesión actual y, para usarla en otras sesiones, deben agregarla o agregarla a
un perfil de PowerShell.

Get-Help muestra el tema de ayuda para un script o función solo cuando los

archivos de archivo de script y tema de ayuda se guardan en las ubicaciones


correctas. Por lo tanto, no resulta útil incluir instrucciones para instalar PowerShell
ni guardar o instalar el script o la función en un tema de ayuda de script o función.
En su lugar, incluya las instrucciones de instalación en el documento que use para
distribuir el script o la función.

Consulte también
Escritura de temas de Ayuda basados en comentarios
Escritura de temas de Ayuda basados en
comentarios
Artículo • 25/09/2021

Puede escribir temas de Ayuda basados en comentarios para funciones y scripts


mediante palabras clave especiales de comentarios de Ayuda.

El cmdlet muestra la Ayuda basada en comentarios en el mismo formato en el que


muestra los temas de ayuda del Get-Help cmdlet que se generan a partir de archivos
XML. Los usuarios pueden usar todos los parámetros de , como Detallado, Completo,
Ejemplo y En línea, para mostrar la función Get-Help y la Ayuda del script.

También puede escribir temas de Ayuda basados en XML para scripts y funciones y usar
las palabras clave de comentario de Ayuda para redirigir a los usuarios a los temas
basados en XML u otros temas.

En esta sección
Sintaxis de Comment-Based Ayuda Describe la sintaxis de la ayuda basada en
comentarios.

Palabras clave de ayuda basadas en comentarios Enumera las palabras clave de la ayuda
basada en comentarios.

Colocación Comment-Based ayuda en funciones Muestra dónde colocar la ayuda


basada en comentarios para una función.

Colocación Comment-Based ayuda en scripts Muestra dónde colocar la ayuda basada


en comentarios para un script.
Sintaxis de la Ayuda basada en
comentarios
Artículo • 25/09/2021

En esta sección se describe la sintaxis de la ayuda basada en comentarios.

Diagrama de sintaxis
La sintaxis de la Ayuda basada en comentarios es la siguiente:

# .< help keyword>


# <help content>

-or -

<#
.< help keyword>
< help content>
#>

Descripción de la sintaxis
La Ayuda basada en comentarios se escribe como una serie de comentarios. Puede
escribir un símbolo de comentario ( ) antes de cada línea de comentarios, o puede usar
los símbolos # y para crear un bloque de <# #> comentarios. Todas las líneas dentro
del bloque de comentarios se interpretan como comentarios.

Cada sección de la Ayuda basada en comentarios se define mediante una palabra clave
y cada palabra clave va precedida de un punto ( . ). Las palabras clave pueden aparecer
en cualquier orden. Los nombres de palabra clave no distinguen mayúsculas de
minúsculas.

Un bloque de comentarios debe contener al menos una palabra clave de ayuda. Algunas
de las palabras clave, como EXAMPLE, pueden aparecer muchas veces en el mismo
bloque de comentarios. El contenido de ayuda de cada palabra clave comienza en la
línea después de la palabra clave y puede abarcar varias líneas.

Todas las líneas de un tema de Ayuda basado en comentarios deben ser contiguas. Si un
tema de Ayuda basado en comentarios sigue un comentario que no forma parte del
tema de Ayuda, debe haber al menos una línea en blanco entre la última línea de
comentario que no es de Ayuda y el principio de la Ayuda basada en comentarios.

Por ejemplo, el siguiente tema de ayuda basado en comentarios contiene . Palabra clave
Description y su valor, que es una descripción de una función o script.

PowerShell

<#
.Description
The Get-Function function displays the name and syntax of all functions
in the session.
#>
Palabras clave de la Ayuda basadas en
comentarios
Artículo • 04/02/2022

En este tema se enumeran y describen las palabras clave de la ayuda basada en


comentarios.

Palabras clave en Comment-Based Ayuda


Las siguientes son palabras clave de Ayuda válidas basadas en comentarios. Se
muestran en el orden en que suelen aparecer en un tema de Ayuda junto con su uso
previsto. Estas palabras clave pueden aparecer en cualquier orden en la Ayuda basada
en comentarios y no distinguen mayúsculas de minúsculas.

Tenga en cuenta que la .EXTERNALHELP palabra clave tiene prioridad sobre todas las
demás palabras clave de ayuda basadas en comentarios. Cuando .EXTERNALHELP está
presente, el cmdlet Get-Help no muestra ayuda basada en comentarios, incluso cuando
no encuentra un archivo de ayuda que coincida con el valor de la palabra clave .

.SYNOPSIS
Breve descripción de la función o script. Esta palabra clave solo se puede usar una vez
en cada tema.

.DESCRIPTION
Descripción detallada de la función o el script. Esta palabra clave solo se puede usar una
vez en cada tema.

.PARAMETER <Parameter-Name>
Descripción de un parámetro. Puede incluir una palabra clave .PARAMETER para cada
parámetro en la función o script.

Las .PARAMETER palabras clave pueden aparecer en cualquier orden en el bloque de


comentarios, Param pero el orden en que los parámetros aparecen en la declaración de
instrucción o función determina el orden en que aparecen los parámetros en el tema de
Ayuda. Para cambiar el orden de los parámetros en el tema de Ayuda, cambie el orden
de los parámetros en Param la declaración de instrucción o función.

También puede especificar una descripción de parámetro colocando un comentario en


la Param instrucción inmediatamente antes del nombre de la variable de parámetro. Si
usa un comentario de instrucción y una palabra clave, .PARAMETER se usa la descripción
asociada a Param .PARAMETER la palabra clave y Param se omite el comentario de la
instrucción.

.EXAMPLE
Un comando de ejemplo que usa la función o el script, seguido opcionalmente de una
salida de ejemplo y una descripción. Repita esta palabra clave para cada ejemplo.

.INPUTS
Microsoft .NET Framework tipos de objetos que se pueden canalizar a la función o
script. También puede incluir una descripción de los objetos de entrada.

.OUTPUTS
Tipo .NET Framework de los objetos que devuelve el cmdlet. También puede incluir una
descripción de los objetos devueltos.

.NOTES
Información adicional sobre la función o el script.

.LINK
Nombre de un tema relacionado. Repita esta palabra clave para cada tema relacionado.
Este contenido aparece en la sección Vínculos relacionados del tema de Ayuda.

El .LINK contenido de la palabra clave también puede incluir un identificador uniforme


de recursos (URI) en una versión en línea del mismo tema de Ayuda. La versión en línea
se abre cuando se usa el Online parámetro de Get-Help . El URI debe comenzar por
"http" o "https".
.COMPONENT
Nombre de la tecnología o característica que usa la función o script, o con la que está
relacionada. El Component parámetro de Get-Help utiliza este valor para filtrar los
resultados de búsqueda devueltos por Get-Help .

.ROLE
Nombre del rol de usuario para el tema de ayuda. El Role parámetro de Get-Help utiliza
este valor para filtrar los resultados de búsqueda devueltos por Get-Help .

.FUNCTIONALITY
Palabras clave que describen el uso previsto de la función. El Functionality parámetro de
Get-Help utiliza este valor para filtrar los resultados de búsqueda devueltos por Get-

Help .

.FORWARDHELPTARGETNAME <Command-Name>
Redirige al tema de Ayuda del comando especificado. Puede redirigir a los usuarios a
cualquier tema de Ayuda, incluidos los temas de Ayuda para una función, un script, un
cmdlet o un proveedor.

.FORWARDHELPCATEGORY <Category>
Especifica la categoría Ayuda del elemento en .FORWARDHELPTARGETNAME . Use esta palabra
clave para evitar conflictos cuando haya comandos con el mismo nombre.

Los valores válidos son:

Alias
Cmdlet
HelpFile
Function
Provider
General
FAQ
Glossary
ScriptCommand
ExternalScript
Filtrar
All

.REMOTEHELPRUNSPACE <PSSession-variable>
Especifica una sesión que contiene el tema de Ayuda. Escriba una variable que contenga
una PSSession. El cmdlet usa esta palabra clave Export-PSSession para buscar los temas
de Ayuda de los comandos exportados.

.EXTERNALHELP <XML Help File>


Especifica la ruta de acceso o el nombre de un archivo de Ayuda basado en XML para el
script o la función.

La .EXTERNALHELP palabra clave indica al cmdlet Get-Help que obtenga ayuda para el
script o la función en un archivo basado en XML. La .EXTERNALHELP palabra clave es
necesaria cuando se usa un archivo de ayuda basado en XML para un script o función.
Sin él, Get-Help no encontrará un archivo de ayuda para la función o el script.

La palabra .EXTERNALHELP clave tiene prioridad sobre todas las demás palabras clave de
ayuda basadas en comentarios. Cuando .EXTERNALHELP está presente, el cmdlet Get-
Help no muestra ayuda basada en comentarios, incluso cuando no encuentra un archivo
de ayuda que coincida con el valor de la palabra clave .

Cuando un módulo de script exporta la función, el valor de .EXTERNALHELP debe ser un


nombre de archivo sin una ruta de acceso. Get-Help busca el archivo en un
subdirectorio específico de la configuración regional del directorio del módulo. No hay
ningún requisito para el nombre de archivo, pero un procedimiento recomendado es
usar el siguiente formato de nombre de archivo: <ScriptModule>.psm1-help.xml .

Cuando la función no está asociada a un módulo, incluya una ruta de acceso y un


nombre de archivo en el valor de la palabra .EXTERNALHELP clave . Si la ruta de acceso
especificada al archivo XML contiene subdirectorios específicos de la referencia cultural
de la interfaz de usuario, Get-Help busca de forma recursiva en los subdirectorios un
archivo XML con el nombre del script o la función de acuerdo con los estándares de
reserva de lenguaje establecidos para Windows, igual que en todos los temas de Ayuda
basados en XML.

Para obtener más información sobre el formato de archivo de Ayuda basado en XML de
la Ayuda del cmdlet, vea Escribir Windows PowerShell ayuda del cmdlet.
Colocación de la Ayuda basada en
comentarios en las funciones
Artículo • 25/09/2021

En este tema se explica dónde colocar la ayuda basada en comentarios de una función
para que el cmdlet asocie el tema de ayuda basado en comentarios a Get-Help la
función correcta.

Dónde colocar la Comment-Based para una


función
Al principio del cuerpo de la función.

Al final del cuerpo de la función.

Antes de la Function palabra clave . Cuando la función está en un módulo de


script o script, no puede haber más de una línea en blanco entre la última línea de
la ayuda basada en comentarios y la palabra Function clave . De lo Get-Help
contrario, asocia la ayuda con el script, no con la función .

Ejemplos de colocación de ayuda en una


función
En los ejemplos siguientes se muestra cada una de las tres opciones de selección de
ubicación para la ayuda basada en comentarios de una función.

Ayuda al principio de un cuerpo de función


En el ejemplo siguiente se muestra el comentario basado en al principio de un cuerpo
de función.

PowerShell

function MyProcess
{
<#
.Description
The MyProcess function gets the Windows PowerShell process.
#>
Get-Process powershell
}

Ayuda al final de un cuerpo de función


En el ejemplo siguiente se muestra el comentario basado en al final de un cuerpo de
función.

PowerShell

function MyFunction
{
Get-Process powershell

<#
.Description
The MyProcess function gets the Windows PowerShell process.
#>
}

Ayuda antes de la palabra clave Function


En los ejemplos siguientes se muestra el comentario basado en la línea anterior a la
palabra clave function.

PowerShell

<#
.Description
The MyProcess function gets the Windows PowerShell process.
#>
function MyFunction { Get-Process powershell}
Colocación de la Ayuda basada en
comentarios en los scripts
Artículo • 25/09/2021

En este tema se explica dónde colocar la ayuda basada en comentarios de un script para
que el cmdlet asocie el tema de ayuda basado en comentarios con scripts y no con
ninguna función que pueda estar en Get-Help el script.

Dónde colocar Comment-Based ayuda para un


script
Al principio del archivo de script.

La Ayuda de script solo puede ir precedida en el script por comentarios y líneas en


blanco.

Al final del archivo de script.

Si el primer elemento del cuerpo del script (después de la Ayuda) es una


declaración de función, debe haber al menos dos líneas en blanco entre el final de
la Ayuda del script y la declaración de función. De lo contrario, la Ayuda se
interpreta como Ayuda para la función, no como Ayuda para el script.

Ejemplos de colocación de ayuda en un script


En los ejemplos siguientes se muestra cada una de las opciones de selección de
ubicación para la ayuda basada en comentarios de un script.

Ayuda al principio de un script


En el ejemplo siguiente se muestra el comentario basado en al principio de un script.

PowerShell

<#
.Description
This script performs a series of network connection tests.
#>

param [string]$ComputerName
...
Ayuda al final de un script
En el ejemplo siguiente se muestra la base de comentarios al final de un script.

PowerShell

...
function Ping { Test-Connection -ComputerName $ComputerName }

<#
.Description
This script performs a series of network connection tests.
#>
Elementos generados automáticamente
de la Ayuda basada en comentarios
Artículo • 27/09/2021

El Get-Help cmdlet genera automáticamente varios elementos de un tema basado en


comentarios. Estos elementos generados automáticamente hacen que la ayuda basada
en comentarios se parezca mucho a la ayuda generada a partir de archivos XML.

Elementos generados automáticamente


El Get-Help cmdlet genera automáticamente los siguientes elementos de un tema de
ayuda. No puede editar estos elementos directamente, pero en muchos casos puede
cambiar los resultados cambiando el origen del elemento.

Nombre
La sección Nombre de un tema de Ayuda de función se toma del nombre de la función
en la definición de función. El nombre de un tema de ayuda de script se toma del
nombre de archivo del script. Para cambiar el nombre o su uso de mayúsculas, cambie la
definición de función o el nombre de archivo del script.

Sintaxis
La sección Sintaxis del tema de Ayuda se genera a partir de la lista de parámetros de la
instrucción Param de la función o script. Para agregar detalles a la sintaxis del tema de
Ayuda, como el tipo .NET de un parámetro, agregue los detalles a la lista de parámetros.
Si no especifica un tipo de parámetro, el tipo de objeto se inserta como valor
predeterminado.

Lista de parámetros
La sección Parámetros del tema de Ayuda se genera a partir de la lista de parámetros de
la función o script y de las descripciones que se agregan mediante la palabra clave o los
comentarios de la .Parameters lista de parámetros.

Los parámetros aparecen en la sección Parámetros en el mismo orden en que aparecen


en la lista de parámetros. La ortografía y el uso de mayúsculas y mayúsculas de los
nombres de parámetro también se toman de la lista de parámetros. no se ve afectado
por el nombre de parámetro especificado por la palabra .Parameter clave .

Parámetros comunes
Los parámetros comunes se agregan a la sintaxis y la lista de parámetros del tema de
Ayuda, incluso si no tienen ningún efecto. Para obtener más información sobre los
parámetros comunes, vea about_CommonParameters.

Tabla de atributos de parámetro


Get-Help genera la tabla de atributos de parámetro que aparece cuando se usa el
parámetro Full o Parameter de Get-Help . El valor de los atributos Required, Position y
Default value se toma de la sintaxis de función o script.

Comentarios
La sección Comentarios del tema de Ayuda se genera automáticamente a partir de la
función o el nombre del script. No puede cambiar ni afectar a su contenido.
Ejemplos de la Ayuda basada en
comentarios
Artículo • 27/09/2021

En este tema se incluye un ejemplo que muestra cómo usar la ayuda basada en
comentarios para scripts y funciones.

Ejemplo 1: Comment-Based ayuda para una


función
La siguiente función de ejemplo incluye ayuda basada en comentarios.

PowerShell

function Add-Extension
{
param ([string]$Name,[string]$Extension = "txt")
$name = $name + "." + $extension
$name

<#
.SYNOPSIS
Adds a file name extension to a supplied name.

.DESCRIPTION
Adds a file name extension to a supplied name.
Takes any strings for the file name or extension.

.PARAMETER Name
Specifies the file name.

.PARAMETER Extension
Specifies the extension. "Txt" is the default.

.INPUTS
None. You cannot pipe objects to Add-Extension.

.OUTPUTS
System.String. Add-Extension returns a string with the extension or
file name.

.EXAMPLE
PS> extension -name "File"
File.txt

.EXAMPLE
PS> extension -name "File" -extension "doc"
File.doc

.EXAMPLE
PS> extension "File" "doc"
File.doc

.LINK
Online version: http://www.fabrikam.com/extension.html

.LINK
Set-Item
#>
}

En la salida siguiente se muestran los resultados de Get-Help un comando que muestra


la ayuda de la Add-Extension función.

PowerShell

PS> Get-Help Add-Extension -full

Output

NAME
Add-Extension

SYNOPSIS
Adds a file name extension to a supplied name.

SYNTAX
Add-Extension [[-Name] <String>] [[-Extension] <String>]
[<CommonParameters>]

DESCRIPTION
Adds a file name extension to a supplied name. Takes any strings
for the file name or extension.

PARAMETERS
-Name
Specifies the file name.

Required? false
Position? 0
Default value
Accept pipeline input? false
Accept wildcard characters?

-Extension
Specifies the extension. "Txt" is the default.

Required? false
Position? 1
Default value
Accept pipeline input? false
Accept wildcard characters?

<CommonParameters>
This cmdlet supports the common parameters: -Verbose, -Debug,
-ErrorAction, -ErrorVariable, -WarningAction, -
WarningVariable,
-OutBuffer and -OutVariable. For more information, type
"get-help about_commonparameters".

INPUTS
None. You cannot pipe objects to Add-Extension.

OUTPUTS
System.String. Add-Extension returns a string with the extension
or file name.

-------------------------- EXAMPLE 1 --------------------------

PS> extension -name "File"


File.txt

-------------------------- EXAMPLE 2 --------------------------

PS> extension -name "File" -extension "doc"


File.doc

-------------------------- EXAMPLE 3 --------------------------

PS> extension "File" "doc"


File.doc

RELATED LINKS
Online version: http://www.fabrikam.com/extension.html
Set-Item

Ejemplo 2: Comment-Based ayuda para un


script
La siguiente función de ejemplo incluye ayuda basada en comentarios.

Observe las líneas en blanco entre el cierre #> y la Param instrucción . En un script que
no tiene una instrucción , debe haber al menos dos líneas en blanco entre el comentario
final del tema de Ayuda y la Param primera declaración de función. Sin estas líneas en
blanco, Get-Help asocia el tema de Ayuda a la función , en lugar del script.

PowerShell
<#
.SYNOPSIS
Performs monthly data updates.

.DESCRIPTION
The Update-Month.ps1 script updates the registry with new data generated
during the past month and generates a report.

.PARAMETER InputPath
Specifies the path to the CSV-based input file.

.PARAMETER OutputPath
Specifies the name and path for the CSV-based output file. By default,
MonthlyUpdates.ps1 generates a name from the date and time it runs, and
saves the output in the local directory.

.INPUTS
None. You cannot pipe objects to Update-Month.ps1.

.OUTPUTS
None. Update-Month.ps1 does not generate any output.

.EXAMPLE
PS> .\Update-Month.ps1

.EXAMPLE
PS> .\Update-Month.ps1 -inputpath C:\Data\January.csv

.EXAMPLE
PS> .\Update-Month.ps1 -inputpath C:\Data\January.csv -outputPath
C:\Reports\2009\January.csv
#>

param ([string]$InputPath, [string]$OutPutPath)

function Get-Data { }

El comando siguiente obtiene la Ayuda del script. Dado que el script no está en un
directorio que aparece en la variable de entorno Path, el comando que obtiene el script
Help debe especificar la Get-Help ruta de acceso del script.

PowerShell

PS> Get-Help c:\ps-test\update-month.ps1 -full

Output

NAME
C:\ps-test\Update-Month.ps1

SYNOPSIS
Performs monthly data updates.

SYNTAX
C:\ps-test\Update-Month.ps1 [-InputPath] <String> [[-
OutputPath]
<String>] [<CommonParameters>]

DESCRIPTION
The Update-Month.ps1 script updates the registry with new
data
generated during the past month and generates a report.

PARAMETERS
-InputPath
Specifies the path to the CSV-based input file.

Required? true
Position? 0
Default value
Accept pipeline input? false
Accept wildcard characters?

-OutputPath
Specifies the name and path for the CSV-based output
file. By
default, MonthlyUpdates.ps1 generates a name from the
date
and time it runs, and saves the output in the local
directory.

Required? false
Position? 1
Default value
Accept pipeline input? false
Accept wildcard characters?

<CommonParameters>
This cmdlet supports the common parameters: -Verbose, -
Debug,
-ErrorAction, -ErrorVariable, -WarningAction, -
WarningVariable,
-OutBuffer and -OutVariable. For more information, type,
"get-help about_commonparameters".

INPUTS
None. You cannot pipe objects to Update-Month.ps1.

OUTPUTS
None. Update-Month.ps1 does not generate any output.

-------------------------- EXAMPLE 1 --------------------------

PS> .\Update-Month.ps1

-------------------------- EXAMPLE 2 --------------------------


PS> .\Update-Month.ps1 -inputpath C:\Data\January.csv

-------------------------- EXAMPLE 3 --------------------------

PS> .\Update-Month.ps1 -inputpath C:\Data\January.csv -


outputPath
C:\Reports\2009\January.csv

RELATED LINKS

Ejemplo 3: Descripciones de parámetros en una


instrucción Param
En este ejemplo se muestra cómo insertar descripciones de parámetros en la Param
instrucción de una función o script. Este formato es muy útil cuando las descripciones
de los parámetros son breves.

PowerShell

function Add-Extension
{
param
(
[string]
# Specifies the file name.
$name,

[string]
# Specifies the file name extension. "Txt" is the default.
$extension = "txt"
)
$name = $name + "." + $extension
$name

<#
.SYNOPSIS
Adds a file name extension to a supplied name.
...
#>

Los resultados son los mismos que los del ejemplo 1. Get-Help interpreta las
descripciones de parámetros como si estuvieran acompañadas de la palabra .Parameter
clave .

Ejemplo 4: Redirigir a un archivo XML


Puede escribir temas de Ayuda basados en XML para funciones y scripts. Aunque la
Ayuda basada en comentarios es más fácil de implementar, la Ayuda basada en XML es
necesaria si desea un control más preciso sobre el contenido de la Ayuda o si va a
traducir temas de Ayuda a varios idiomas. En el ejemplo siguiente se muestran las
primeras líneas del Update-Month.ps1 script. El script usa la palabra clave para especificar
la ruta de acceso a un tema de Ayuda basado .ExternalHelp en XML para el script.

PowerShell

# .ExternalHelp C:\MyScripts\Update-Month-Help.xml

param ([string]$InputPath, [string]$OutPutPath)

function Get-Data { }

En el ejemplo siguiente se muestra el uso de la .ExternalHelp palabra clave en una


función.

PowerShell

function Add-Extension
{
param ([string] $name, [string]$extension = "txt")
$name = $name + "." + $extension
$name

# .ExternalHelp C:\ps-test\Add-Extension.xml
}

Ejemplo 5: Redirigir a otro tema de Ayuda


El código siguiente es un extracto del principio de la función integrada en PowerShell,
que muestra una pantalla de texto de ayuda Help a la vez. Dado que el tema de Ayuda
del cmdlet Get-Help describe la función Help, la función help usa las palabras clave y
para redirigir al usuario al tema de ayuda del .ForwardHelpTargetName
.ForwardHelpCategory cmdlet Get-Help.

PowerShell

function help
{

<#
.FORWARDHELPTARGETNAME Get-Help
.FORWARDHELPCATEGORY Cmdlet
#>
[CmdletBinding(DefaultParameterSetName='AllUsersView')]
param(
[Parameter(Position=0, ValueFromPipelineByPropertyName=$true)]
[System.String]
${Name},
...

El comando siguiente usa esta característica. Cuando un usuario tipos un Get-Help


comando para la Help función, muestra el tema de Ayuda Get-Help para el Get-Help
cmdlet.

PowerShell

PS> get-help help

Output

NAME
Get-Help

SYNOPSIS
Displays information about Windows PowerShell cmdlets and
concepts.
...
Escritura de la ayuda de los cmdlets de
PowerShell
Artículo • 25/09/2021

Los cmdlets de PowerShell pueden ser útiles, pero a menos que los temas de Ayuda
expliquen claramente lo que hace el cmdlet y cómo usarlo, es posible que el cmdlet no
se use o, incluso peor, pueda frustrar a los usuarios. El formato de archivo de ayuda del
cmdlet basado en XML mejora la coherencia, pero una gran ayuda requiere mucho más.

Si nunca ha escrito la Ayuda del cmdlet, revise las instrucciones siguientes. El esquema
XML necesario para crear el tema de Ayuda del cmdlet se describe en la sección
siguiente. Comience con Creación del archivo de Ayuda del cmdlet. En este tema se
incluye una descripción de los nodos XML de nivel superior.

Escribir directrices para la Ayuda de cmdlets

Escribir bien
Nada reemplaza a un tema bien escrito. Si no es un escritor profesional, busque un
escritor o editor que le ayude. Otra alternativa es copiar el texto de ayuda en Microsoft
Word y usar la gramática y las comprobaciones ortográficas para mejorar el trabajo.

Escribir simplemente
Use palabras y frases simples. Evite usar jerga. Tenga en cuenta que muchos lectores
solo están equipados con un diccionario de idioma externo y el tema de Ayuda.

Escritura coherente
La ayuda de los cmdlets relacionados debe ser similar (por ejemplo, get-x y set-x). Use
las descripciones estándar para los parámetros estándar, como Force y InputObject.
(Cópielos de la Ayuda de los cmdlets principales). Use términos estándar. Por ejemplo,
use "parameter", no "argument" y use "cmdlet" no "command" ni "command-let".

Iniciar la sinopsis con un verbo


El campo synopsis informa al usuario de lo que hace el cmdlet, no de lo que es ni de
cómo funciona. Los verbos crean una instrucción basada en tareas que informa a los
usuarios si este cmdlet cumple sus requisitos. Use verbos simples como "get", "create" y
"change". Evite "set", que puede ser impreciso y con palabras elegantes, como "modify".

Centrarse en objetos
La mayoría de los cmdlets "get" muestran algo, pero su función principal es obtener un
objeto . En la Ayuda, céntrate en el objeto para que los usuarios entiendan que la
presentación predeterminada es una de muchas y que pueden usar los métodos y
propiedades del objeto que recuperaste para ellos de maneras diferentes.

Escribir descripciones detalladas


Enumé una breve lista de todo lo que el cmdlet puede hacer en la descripción detallada.
Si la función main va a cambiar una propiedad, pero el cmdlet puede cambiar todas las
propiedades, enumédalo en la descripción detallada.

Uso de la sintaxis convencional


Use el formato Backus-Naur estándar, que es común para Windows y UNIX ayuda de la
línea de comandos.

Usar Microsoft .NET para los valores de parámetro


Los marcadores de posición de los valores de parámetro (en la sintaxis y las
descripciones de parámetros) muestran los .NET Framework de los objetos que el
parámetro aceptará. El equipo de PowerShell desarrolló esta convención para ayudar a
enseñar a los usuarios sobre el .NET Framework.

Escritura de descripciones de parámetros completas


Las descripciones de parámetros deben informar a los usuarios de dos cosas: qué hace
el parámetro (su efecto) y qué deben escribir para los valores de parámetro.

Escribir ejemplos prácticos


Los ejemplos deben mostrar cómo usar todos los parámetros, pero lo más importante
es mostrar cómo usar el cmdlet en tareas del mundo real. Comience con un ejemplo
sencillo y escriba ejemplos cada vez más complejos. En el ejemplo final, muestre cómo
usar el cmdlet en una canalización.
Uso del campo Notes
Use el campo Notas para explicar los conceptos que los usuarios necesitan para
comprender el cmdlet. También puede usar notas para ayudar a los usuarios a evitar
errores comunes. Evite las direcciones URL a medida que cambian. En su lugar,
proporcione a los usuarios términos para buscar.

Prueba de la Ayuda
Pruebe la Ayuda de la forma en que pruebe el código. Haga que sus amigos y
compañeros lean el contenido de ayuda y proporcionen comentarios. También puede
solicitar comentarios de grupos de noticias.

Consulte también
Cómo crear el archivo de Ayuda del cmdlet

Cómo agregar el nombre del cmdlet y la sinopsis a un tema de Ayuda del cmdlet

Cómo agregar la descripción detallada a un tema de ayuda de cmdlets

Cómo agregar una sintaxis a un tema de Ayuda del cmdlet

Cómo agregar parámetros a un tema de Ayuda de cmdlets

Cómo agregar tipos de entrada a un tema de Ayuda de cmdlets

Cómo agregar valores devueltos a un tema de Ayuda del cmdlet

Cómo agregar notas a un tema de Ayuda del cmdlet

Cómo agregar ejemplos a un tema de Ayuda del cmdlet

Cómo agregar vínculos relacionados a un tema de Ayuda del cmdlet

Windows PowerShell SDK


Cómo crear el archivo de Ayuda del
cmdlet
Artículo • 13/05/2022

En esta sección se describe cómo crear un archivo XML válido que contenga contenido
para Windows PowerShell temas de ayuda de cmdlets. En esta sección se describe cómo
asignar un nombre al archivo de Ayuda, cómo agregar los encabezados XML adecuados
y cómo agregar nodos que contendrán las distintas secciones del contenido de ayuda
del cmdlet.

7 Nota

Para obtener una vista completa de un archivo de Ayuda, abra uno de los dll-
Help.xml archivos ubicados en el directorio de instalación de Windows PowerShell.

Por ejemplo, el Microsoft.PowerShell.Commands.Management.dll-Help.xml archivo


contiene contenido para varios de los cmdlets de PowerShell.

Creación de un archivo de ayuda de cmdlets


1. Cree un archivo de texto y guárdelo con codificación UTF8. El nombre de archivo
debe tener el siguiente formato para que Windows PowerShell pueda detectarlo
como un archivo de ayuda de cmdlet.

<PSSnapInAssemblyName>.dll-Help.xml

2. Agregue los siguientes encabezados XML al archivo de texto. Tenga en cuenta que
el archivo se validará con el esquema del lenguaje de marcado de asistencia de
Microsoft (MAML). Actualmente, PowerShell no proporciona ninguna herramienta
para validar el archivo.

<?xml version="1.0" encoding="utf-8" ?> <helpItems xmlns="http://msh"

schema="maml">

3. Agregue un nodo Command al archivo de ayuda del cmdlet para cada cmdlet del
ensamblado. Cada nodo del nodo Comando se relaciona con las diferentes
secciones del tema ayuda del cmdlet.

En la tabla siguiente se muestra el elemento XML de cada nodo, seguido de una


descripción de cada nodo.
Nodo Descripción

<details> Agrega contenido para las secciones NAME y SYNOPSIS del


tema de ayuda del cmdlet. Para obtener más información, vea
Cómo agregar el nombre del cmdlet y Synopsis.

<maml:description> Agrega contenido para la sección DESCRIPTION del tema de


ayuda del cmdlet. Para obtener más información, vea How to
Add the Detailed Description to a Cmdlet Help Topic.

<command:syntax> Agrega contenido para la sección SINTAXIS del tema ayuda del
cmdlet. Para obtener más información, vea Cómo agregar
sintaxis a un tema de ayuda de cmdlets.

<command:parameters> Agrega contenido para la sección PARAMETERS del tema de


ayuda del cmdlet. Para obtener más información, vea Cómo
agregar parámetros a un tema de ayuda de cmdlet.

<command:inputTypes> Agrega contenido para la sección INPUTS del tema ayuda del
cmdlet. Para obtener más información, vea How to Add Input
Types to a Cmdlet Help Topic.

<command:returnValues> Agrega contenido para la sección OUTPUTS del tema de ayuda


del cmdlet. Para obtener más información, vea Cómo agregar
valores devueltos a un tema de ayuda de cmdlet.

<maml:alertset> Agrega contenido para la sección NOTES del tema de ayuda del
cmdlet. Para obtener más información, vea How to add Notes to
a Cmdlet Help Topic.

<command:examples> Agrega contenido para la sección EJEMPLOS del tema ayuda del
cmdlet. Para obtener más información, vea Cómo agregar
ejemplos a un tema de ayuda de cmdlet.

<maml:relatedLinks> Agrega contenido para la sección VÍNCULOS RELACIONADOS


del tema de ayuda del cmdlet. Para obtener más información,
vea How to Add Related Links to a Cmdlet Help Topic.

Ejemplo
Este es un ejemplo de un nodo Comando que incluye los nodos de las distintas
secciones del tema ayuda del cmdlet.

XML

<command:command
xmlns:maml="http://schemas.microsoft.com/maml/2004/10"
xmlns:command="http://schemas.microsoft.com/maml/dev/command/2004/10"
xmlns:dev="http://schemas.microsoft.com/maml/dev/2004/10">
<command:details>
<!--Add name and synopsis here-->
</command:details>
<maml:description>
<!--Add detailed description here-->
</maml:description>
<command:syntax>
<!--Add syntax information here-->
</command:syntax>
<command:parameters>
<!--Add parameter information here-->
</command:parameters>
<command:inputTypes>
<!--Add input type information here-->
</command:inputTypes>
<command:returnValues>
<!--Add return value information here-->
</command:returnValues>
<maml:alertSet>
<!--Add Note information here-->
</maml:alertSet>
<command:examples>
<!--Add cmdlet examples here-->
</command:examples>
<maml:relatedLinks>
<!--Add links to related content here-->
</maml:relatedLinks>
</command:command>

Consulte también
Cómo agregar el nombre del cmdlet y Synopsis

Cómo agregar la descripción detallada a un tema de ayuda de cmdlet

Cómo agregar una sintaxis a un tema de Ayuda del cmdlet

Cómo agregar parámetros a un tema de ayuda de cmdlets

Cómo agregar tipos de entrada a un tema de Ayuda del cmdlet

Cómo agregar valores devueltos a un tema de Ayuda del cmdlet

Cómo agregar notas a un tema de ayuda de cmdlets

Cómo agregar ejemplos a un tema de Ayuda del cmdlet

Cómo agregar vínculos relacionados a un tema de Ayuda del cmdlet

Windows PowerShell SDK


Cómo agregar el nombre del cmdlet y la
sinopsis a un tema de Ayuda del cmdlet
Artículo • 25/09/2021

En esta sección se describe cómo agregar contenido que se muestra en las secciones
NAME y SYNOPSIS de la ayuda del cmdlet. En el archivo de Ayuda, este contenido se
agrega al nodo Comando para cada cmdlet.

7 Nota

Para obtener una vista completa de un archivo de Ayuda, abra uno de los dll-
Help.xml archivos ubicados en el directorio de instalación de PowerShell. Por
ejemplo, el Microsoft.PowerShell.Commands.Management.dll-Help.xml archivo
contiene contenido para varios de los cmdlets de PowerShell.

Para agregar el nombre del cmdlet y una


sinopsis
La Ayuda del cmdlet puede mostrar dos descripciones para el cmdlet. La primera
descripción es una breve descripción a la que se hace referencia como sinopsis. La
segunda descripción es una descripción más detallada que se describe en el tema
Adding the Detailed Description to a Cmdlet Help Topic. Ambas descripciones
deben escribirse como un solo párrafo.

En la sinopsis, no repita el nombre del cmdlet. Informar al usuario de que el Get-


Server cmdlet obtiene un servidor es breve, pero no informativo. En su lugar, use

sinónimos y agregue detalles a la descripción.

Ejemplo: "Obtiene un objeto que representa un equipo local o remoto".

Use verbos simples como "get", "create" y "change" en la sinopsis. Evite el uso de
"set" porque es impreciso y tiene palabras elegantes, como "modify".

Ejemplo: "Obtiene información sobre la firma Authenticode en un archivo".

Escriba en voz activa. Por ejemplo, "Usar el objeto TimeSpan..." es mucho más claro
que "el objeto TimeSpan se puede usar para..."
Evite el verbo "display" al describir cmdlets que obtienen objetos. Aunque
Windows PowerShell muestra datos de cmdlet, es importante presentar a los
usuarios el concepto de que el cmdlet devuelve .NET Framework objetos cuyos
datos no se pueden mostrar. Si hace hincapié en la presentación, es posible que el
usuario no se dé cuenta de que el cmdlet puede haber devuelto muchas otras
propiedades y métodos útiles que no se muestran.

Consulte también
Windows PowerShell SDK
Cómo agregar una descripción del
cmdlet
Artículo • 26/09/2021

En esta sección se describe cómo agregar contenido que se muestra en la sección


DESCRIPCIÓN de la Ayuda del cmdlet. En el archivo de Ayuda, este contenido se agrega
al nodo Comando para cada cmdlet.

7 Nota

Para obtener una vista completa de un archivo de Ayuda, abra uno de los dll-
Help.xml archivos ubicados en el directorio de instalación de PowerShell. Por
ejemplo, el Microsoft.PowerShell.Commands.Management.dll-Help.xml archivo
contiene contenido para varios de los cmdlets de PowerShell.

Para agregar una descripción


Comience por explicar las características básicas del cmdlet con más detalle. En
muchos casos, puede explicar los términos usados en el nombre del cmdlet e
ilustrar conceptos desconocidos con un ejemplo. Por ejemplo, si el cmdlet anexa
datos a un archivo, explique que agrega datos al final de un archivo existente.

Para buscar todas las características del cmdlet, revise la lista de parámetros.
Describa la función principal del cmdlet y, a continuación, incluya otras funciones y
características. Por ejemplo, si la función principal del cmdlet es cambiar una
propiedad, pero el cmdlet puede cambiar todas las propiedades, por ejemplo, en
la descripción detallada. Si los parámetros del cmdlet permiten a los usuarios
solicitar información de maneras diferentes, explíquela.

Incluya información sobre las formas en que los usuarios pueden usar el cmdlet,
además de los usos obvios. Por ejemplo, puede usar el objeto que recupera el
cmdlet para cambiar el color del texto en la Get-Host Windows PowerShell
comandos.

Ejemplo: "El Get-Acl cmdlet obtiene objetos que representan el descriptor de


seguridad de un archivo o recurso. El descriptor de seguridad contiene las listas de
control de acceso (ACL) del recurso. La ACL especifica los permisos que los
usuarios y grupos de usuarios tienen para acceder al recurso".
La descripción detallada debe describir el cmdlet, pero no debe describir los
conceptos que usa el cmdlet. Coloque las definiciones de concepto en Notas
adicionales.

Consulte también
Windows PowerShell SDK
Cómo agregar una sintaxis a un tema de
Ayuda del cmdlet
Artículo • 25/09/2021

Antes de empezar a codificar el CÓDIGO XML para el diagrama de sintaxis en el archivo


de Ayuda del cmdlet, lea esta sección para obtener una imagen clara del tipo de datos
que debe proporcionar, como los atributos de parámetro y cómo se muestran esos
datos en el diagrama de sintaxis.

Atributos de parámetro
Obligatorio
Si es true, el parámetro debe aparecer en todos los comandos que usan el
conjunto de parámetros.
Si es false, el parámetro es opcional en todos los comandos que usan el
conjunto de parámetros.
Posición
Si se le denomina, se requiere el nombre del parámetro.
Si es posicional, el nombre del parámetro es opcional. Cuando se omite, el valor
del parámetro debe estar en la posición especificada en el comando. Por
ejemplo, si el valor es position="1", el valor del parámetro debe ser el primer o
único valor de parámetro sin nombre del comando.
Entrada de la canalización
Si es true (ByValue), puede canalizar la entrada al parámetro . La entrada está
asociada al parámetro ("enlazado a"), aunque el nombre de propiedad y el tipo
de objeto no coincidan con el tipo esperado. Los componentes de enlace de
parámetros de PowerShell intentan convertir la entrada al tipo correcto y no se
puede ejecutar el comando solo cuando el tipo no se puede convertir. Solo un
parámetro de un conjunto de parámetros se puede asociar por valor.
Si es true (ByPropertyName), puede canalizar la entrada al parámetro . Sin
embargo, la entrada está asociada al parámetro solo cuando el nombre del
parámetro coincide con el nombre de una propiedad del objeto de entrada. Por
ejemplo, si el nombre del parámetro es , los objetos canalados al cmdlet solo se
asocian a ese parámetro cuando el objeto Path tiene una propiedad
denominada path.
Si es true (ByValue, ByPropertyName), puede canalizar la entrada al parámetro
por nombre de propiedad o por valor. Solo un parámetro de un conjunto de
parámetros se puede asociar por valor.
Si es false, no se puede canalizar la entrada a este parámetro.
Englobamiento
Si es true, el texto que el usuario tipos para el valor del parámetro puede incluir
caracteres comodín.
Si es false, el texto que el usuario tipos para el valor del parámetro no puede
incluir caracteres comodín.

Atributos de valor de parámetro


Obligatorio
Si es true, el valor especificado debe usarse siempre que se use el parámetro en
un comando.
Si es false, el valor del parámetro es opcional. Normalmente, un valor es
opcional solo cuando es uno de varios valores válidos para un parámetro, como
en un tipo enumerado.

El atributo Required de un valor de parámetro es diferente del atributo Required de un


parámetro.

El atributo necesario de un parámetro indica si el parámetro (y su valor) deben incluirse


al invocar el cmdlet . Por el contrario, el atributo necesario de un valor de parámetro
solo se usa cuando el parámetro se incluye en el comando . Indica si ese valor concreto
debe usarse con el parámetro .

Normalmente, los valores de parámetro que son marcadores de posición son necesarios
y los valores de parámetro que son literales no son necesarios, ya que son uno de los
varios valores que se pueden usar con el parámetro .

Recopilación de información de sintaxis


1. Comience con el nombre del cmdlet.

SYNTAX
Get-Tech

2. Enumera todos los parámetros del cmdlet. Escriba un guion ( - ) (ASCII 45) antes
de cada nombre de parámetro. Separe los parámetros en conjuntos de parámetros
(algunos cmdlets pueden tener solo un conjunto de parámetros). En este ejemplo,
el cmdlet Get-Tech tiene dos conjuntos de parámetros.
SYNTAX
Get-Tech -name -type
Get-Tech -ID -list -type

Inicie cada conjunto de parámetros con el nombre del cmdlet.

En primer lugar, enume el conjunto de parámetros predeterminado. La clase de


cmdlet especifica el parámetro predeterminado.

Para cada conjunto de parámetros, enumere primero su parámetro único, a menos


que haya parámetros posicionales que deben aparecer primero. En el ejemplo
anterior, los parámetros Name e ID son parámetros únicos para los dos conjuntos
de parámetros (cada conjunto de parámetros debe tener un parámetro que sea
único para ese conjunto de parámetros). Esto facilita a los usuarios la identificación
del parámetro que necesitan proporcionar para el conjunto de parámetros.

Enumera los parámetros en el orden en que deben aparecer en el comando. Si el


orden no importa, enuméndose los parámetros relacionados o enuméndo primero
los parámetros usados con más frecuencia.

Asegúrese de enumerar los parámetros WhatIf y Confirm si el cmdlet admite


ShouldProcess.

No muestre los parámetros comunes (como Verbose, Debug y ErrorAction) en el


diagrama de sintaxis. El Get-Help cmdlet agrega esa información automáticamente
cuando muestra el tema ayuda.

3. Agregue los valores de parámetro. En PowerShell, los valores de parámetro se


representan mediante su tipo .NET. Sin embargo, el nombre de tipo se puede
abreviar, como "string" para System.String.

SYNTAX
Get-Tech -name string -type basic advanced
Get-Tech -ID int -list -type basic advanced

Abreviar tipos siempre que su significado sea claro, como cadena para
System.String e int para System.Int32.

Enumera todos los valores de enumeraciones, como el parámetro del ejemplo


anterior, que se puede -type establecer en básico o avanzado.

Los parámetros switch, como -list en el ejemplo anterior, no tienen valores.


4. Agregue corchetes angulares a los valores de parámetros que son marcadores de
posición, en comparación con los valores de parámetro que son literales.

SYNTAX
Get-Tech -name <string> -type basic advanced
Get-Tech -ID <int> -list -type basic advanced

5. Incluya parámetros opcionales y sus vales entre corchetes.

SYNTAX
Get-Tech -name <string> [-type basic advanced]
Get-Tech -ID <int> [-list] [-type basic advanced]

6. Incluya nombres de parámetros opcionales (para parámetros posicionales) entre


corchetes. El nombre de los parámetros que son posicionales, como el parámetro
Name del ejemplo siguiente, no tiene que incluirse en el comando .

SYNTAX
Get-Tech [-name] <string> [-type basic advanced]
Get-Tech -ID <int> [-list] [-type basic advanced]

7. Si un valor de parámetro puede contener varios valores, como una lista de


nombres en el parámetro Name, agregue un par de corchetes directamente
después del valor del parámetro.

SYNTAX
Get-Tech [-name] <string[]> [-type basic advanced]
Get-Tech -ID <int[]> [-list] [-type basic advanced]

8. Si el usuario puede elegir entre parámetros o valores de parámetro, como el


parámetro Type, incluya las opciones entre llaves y separelas con el símbolo OR
exclusivo (;).

SYNTAX
Get-Tech [-name] <string[]> [-type {basic | advanced}]
Get-Tech -ID <int[]> [-list] [-type {basic | advanced}]

9. Si el valor del parámetro debe usar formatos específicos, como comillas o


paréntesis, muestre el formato en la sintaxis.

SYNTAX
Get-Tech [-name] <"string[]"> [-type {basic | advanced}]
Get-Tech -ID <int[]> [-list] [-type {basic | advanced}]

Codificación del XML del diagrama de sintaxis


El nodo de sintaxis del XML comienza inmediatamente después del nodo de
descripción, que termina con la </maml:description> etiqueta . Para obtener
información sobre cómo recopilar los datos usados en el diagrama de sintaxis, vea
Recopilación de información de sintaxis.

Agregar un nodo de sintaxis


El diagrama de sintaxis que se muestra en el tema de ayuda del cmdlet se genera a
partir de los datos del nodo de sintaxis del XML. El nodo de sintaxis se incluye en un par
de <command:syntax> etiquetas. Con cada conjunto de parámetros del cmdlet incluido
en un par de <command:syntaxitem> etiquetas. No hay ningún límite en el número de
<command:syntaxitem> etiquetas que puede agregar.

En el ejemplo siguiente se muestra un nodo de sintaxis que tiene nodos de elemento de


sintaxis para dos conjuntos de parámetros.

XML

<command:syntax>
<command:syntaxItem>
...
<!--Parameter Set 1 (default parameter set) parameters go here-->
...
</command:syntaxItem>
<command:syntaxItem>
...
<!--Parameter Set 2 parameters go here-->
...
</command:syntaxItem>
</command:syntax>
Agregar el nombre del cmdlet a los datos del conjunto de
parámetros
Cada conjunto de parámetros del cmdlet se especifica en un nodo de elemento de
sintaxis. Cada nodo de elemento de sintaxis comienza con un par de <maml:name>
etiquetas que incluyen el nombre del cmdlet.

En el ejemplo siguiente se incluye un nodo de sintaxis que tiene nodos de elementos de


sintaxis para dos conjuntos de parámetros.

XML

<command:syntax>
<command:syntaxItem>
<maml:name>Cmdlet-Name</maml:name>
</command:syntaxItem>
<command:syntaxItem>
<maml:name>Cmdlet-Name</maml:name>
</command:syntaxItem>
</command:syntax>

Agregar parámetros
Cada parámetro agregado al nodo de elemento de sintaxis se especifica dentro de un
par de <command:parameter> etiquetas. Necesita un par de etiquetas para cada
parámetro incluido en el conjunto de parámetros, a excepción de los parámetros
comunes proporcionados <command:parameter> por PowerShell.

Los atributos de la etiqueta de <command:parameter> apertura determinan cómo aparece


el parámetro en el diagrama de sintaxis. Para obtener información sobre los atributos de
parámetro, vea Atributos de parámetro.

7 Nota

La <command:parameter> etiqueta admite un elemento secundario cuyo contenido


nunca se <maml:description> muestra. Las descripciones de parámetros se
especifican en el nodo de parámetros del XML. Para evitar incoherencias entre la
información de los elementos de sintaxis y el nodo de parámetro, omita ( o
<maml:description> déjelo vacío.

En el ejemplo siguiente se incluye un nodo de elemento de sintaxis para un conjunto de


parámetros con dos parámetros.
XML

<command:syntaxItem>
<maml:name>Cmdlet-Name</maml:name>
<command:parameter required="true" globbing="true"
pipelineInput="true (ByValue)" position="1">
<maml:name>ParameterName1</maml:name>
<command:parameterValue required="true">
string[]
</command:parameterValue>
</command:parameter>
<command:parameter required="true" globbing="true"
pipelineInput="true (ByPropertyName)">
<maml:name>ParameterName2</maml:name>
<command:parameterValue required="true">
int32[]
</command:parameterValue>
</command:parameter>
</command:syntaxItem>
Cómo agregar información de
parámetros
Artículo • 09/12/2021

En esta sección se describe cómo agregar contenido que se muestra en la sección


PARAMETERS del tema de Ayuda del cmdlet. En la sección PARAMETERS del tema de
Ayuda se muestra cada uno de los parámetros del cmdlet y se proporciona una
descripción detallada de cada parámetro.

El contenido de la sección PARAMETERS debe ser coherente con el contenido de la


sección SYNTAX del tema de Ayuda. Es responsabilidad del autor de la Ayuda
asegurarse de que el nodo Sintaxis y parámetros contienen elementos XML similares.

7 Nota

Para obtener una vista completa de un archivo de Ayuda, abra uno de los dll-
Help.xml archivos ubicados en el directorio de instalación de PowerShell. Por

ejemplo, el Microsoft.PowerShell.Commands.Management.dll-Help.xml archivo


contiene contenido para varios de los cmdlets de PowerShell.

Para agregar parámetros


1. Abra el archivo de Ayuda del cmdlet y busque el nodo Comando del cmdlet que
está documentando. Si va a agregar un nuevo cmdlet, deberá crear un nuevo nodo
Comando. El archivo de Ayuda contendrá un nodo Comando para cada cmdlet
para el que proporcione contenido de Ayuda. Este es un ejemplo de un nodo
command en blanco.

XML

<command:command>
</command:command>

2. En el nodo Comando, busque el nodo Descripción y agregue un nodo


Parámetros como se muestra a continuación. Solo se permite un nodo Parámetros
y debe seguir inmediatamente el nodo Sintaxis.

XML
<command:command>
<command:details></command:details>
<maml:description></maml:description>
<command:syntax></command:syntax>
<command:parameters>
</command:parameters>
</command:command>

3. En el nodo Parámetros, agregue un nodo Parámetro para cada parámetro del


cmdlet como se muestra a continuación.

En este ejemplo, se agrega un nodo Parámetro para tres parámetros.

XML

<command:parameters>
<command:parameter></command:parameter>
<command:parameter></command:parameter>
<command:parameter></command:parameter>
</command:parameters>

Dado que se trata de las mismas etiquetas XML que se usan en el nodo Sintaxis y
dado que los parámetros especificados aquí deben coincidir con los parámetros
especificados por el nodo Sintaxis, puede copiar los nodos Parameter del nodo
Sintaxis y pegarlos en el nodo Parámetros. Sin embargo, asegúrese de copiar solo
una instancia de un nodo Parameter, incluso si el parámetro se especifica en varios
conjuntos de parámetros en la sintaxis.

4. Para cada nodo Parámetro, establezca los valores de atributo que definen las
características de cada parámetro. Estos atributos incluyen los siguientes: required,
globbing, pipelineinput y position.

XML

<command:parameters>
<command:parameter required="true" globbing="true"
pipelineInput="false" position="named">
</command:parameter>
<command:parameter required="false" globbing="false"
pipelineInput="false" position="named">
</command:parameter>
<command:parameter required="false" globbing="false"
pipelineInput="false" position="named" ></command:parameter>
</command:parameters>
5. Para cada nodo Parámetro, agregue el nombre del parámetro. Este es un ejemplo
del nombre del parámetro agregado al nodo Parámetro.

XML

<command:parameters>
<command:parameter required="true" globbing="true"
pipelineInput="false" position="named">
<maml:name> Add parameter name... </maml:name>
</command:parameter>
</command:parameters>

6. Para cada nodo Parámetro, agregue la descripción del parámetro. Este es un


ejemplo de la descripción del parámetro agregada al nodo Parámetro.

XML

<command:parameters>
<command:parameter required="true" globbing="true"
pipelineInput="false" position="named">
<maml:name> Add parameter name... </maml:name>
<maml:description>
<maml:para> Add parameter description... </maml:para>
</maml:description>
</command:parameter>
</command:parameters>

7. Para cada nodo Parámetro, agregue el tipo de .NET del parámetro. El tipo de
parámetro se muestra junto con el nombre del parámetro.

Este es un ejemplo del tipo de parámetro .NET agregado al nodo Parámetro.

XML

<command:parameters>
<command:parameter required="true" globbing="true"
pipelineInput="false" position="named">
<maml:name> Add parameter name... </maml:name>
<maml:description>
<maml:para> Add parameter description... </maml:para>
</maml:description>
<dev:type> Add .NET Framework type... </dev:type>
</command:parameter>
</command:parameters>

8. Para cada nodo Parámetro, agregue el valor predeterminado del parámetro. La


siguiente frase se agrega a la descripción del parámetro cuando se muestra el
contenido: DefaultValue es el valor predeterminado.
Este es un ejemplo del valor predeterminado del parámetro que se agrega al nodo
Parámetro.

XML

<command:parameters>
<command:parameter required="true" globbing="true"
pipelineInput="false" position="named">
<maml:name> Add parameter name... </maml:name>
<maml:description>
<maml:para> Add parameter description... </maml:para>
</maml:description>
<dev:type> Add .NET Framework type... </dev:type>
<dev:defaultvalue> Add default value...</dev:defaultvalue>
</command:parameter>
</command:parameters>

9. Para cada parámetro que tenga varios valores, agregue un nodo possibleValues.

Este es un ejemplo de de un nodo possibleValues que define dos valores posibles


para el parámetro .

XML

<dev:possibleValues>
<dev:possibleValue>
<dev:value>Unknown</dev:value>
<maml:description>
<maml:para></maml:para>
</maml:description>
</dev:possibleValue>
<dev:possibleValue>
<dev:value>String</dev:value>
<maml:description>
<maml:para></maml:para>
</maml:description>
</dev:possibleValue>
</dev:possibleValues>

Estos son algunos aspectos que debe recordar al agregar parámetros.

Los atributos del parámetro no se muestran en todas las vistas del tema de Ayuda
del cmdlet. Sin embargo, se muestran en una tabla que sigue a la descripción del
parámetro cuando el usuario solicita la vista Full ( ) o Get-Help <cmdletname> -Full
Parameter ( ) Get-Help <cmdletname> -Parameter del tema.

La descripción del parámetro es una de las partes más importantes de un tema de


Ayuda del cmdlet. La descripción debe ser breve, así como exhaustiva. Además,
recuerde que si la descripción del parámetro es demasiado larga, como cuando
dos parámetros interactúan entre sí, puede agregar más contenido en la sección
NOTES del tema de Ayuda del cmdlet.

La descripción del parámetro proporciona dos tipos de información.

Qué hace el cmdlet cuando se usa el parámetro .

Qué valor legal es para el parámetro .

Dado que los valores de parámetro se expresan como objetos .NET, los usuarios
necesitan más información sobre estos valores que en una Ayuda de línea de
comandos tradicional. Diga al usuario qué tipo de datos está diseñado para
aceptar el parámetro e incluya ejemplos.

El valor predeterminado del parámetro es el valor que se usa si el parámetro no se


especifica en la línea de comandos. Tenga en cuenta que el valor predeterminado es
opcional y no es necesario para algunos parámetros, como los parámetros necesarios.
Sin embargo, debe especificar un valor predeterminado para la mayoría de los
parámetros opcionales.

El valor predeterminado ayuda al usuario a comprender el efecto de no usar el


parámetro . Describa el valor predeterminado muy específicamente, como "Directorio
actual" o "Directorio de instalación de PowerShell ( )" para $PSHOME una ruta de acceso
opcional. También puede escribir una frase que describa el valor predeterminado, como
la siguiente frase usada para el parámetro PassThru: "Si no se especifica PassThru, el
cmdlet no pasa objetos por la canalización". Además, dado que el valor se muestra
frente al nombre de campo Valor predeterminado, no es necesario incluir el término
"valor predeterminado" en la entrada.

El valor predeterminado del parámetro no se muestra en todas las vistas del tema de
Ayuda del cmdlet. Sin embargo, se muestra en una tabla (junto con los atributos de
parámetro) después de la descripción del parámetro cuando el usuario solicita la vista
Full ( ) o Get-Help <cmdletname> -Full Parameter ( ) Get-Help <cmdletname> -Parameter
del tema.

El código XML siguiente muestra un par de <dev:defaultValue> etiquetas agregadas al


<command:parameter> nodo. Observe que el valor predeterminado sigue inmediatamente

después de la etiqueta de cierre (cuando se especifica el valor del parámetro) o la


etiqueta de cierre </command:parameterValue> de la descripción del </maml:description>
parámetro. nombre.

XML
<command:parameters>
<command:parameter required="true" globbing="true"
pipelineInput="false" position="named">
<maml:name> Parameter name </maml:name>
<maml:description>
<maml:para> Parameter Description </maml:para>
</maml:description>
<command:parameterValue required="true">
Value
</command:parameterValue>
<dev:defaultValue> Default parameter value </dev:defaultValue>
</command:parameter>
</command:parameters>

Agregar valores para tipos enumerados

Si el parámetro tiene varios valores o valores de un tipo enumerado, puede usar un


nodo <dev:possibleValues> opcional. Este nodo permite especificar un nombre y una
descripción para varios valores.

Tenga en cuenta que las descripciones de los valores enumerados no aparecen en


ninguna de las vistas de Ayuda predeterminadas que muestra el cmdlet, pero otros
visores de Ayuda pueden mostrar este contenido en sus Get-Help vistas.

El código XML siguiente muestra <dev:possibleValues> un nodo con dos valores


especificados.

XML

<command:parameters>
<command:parameter required="true" globbing="true"
pipelineInput="false" position="named">
<maml:name> Parameter name </maml:name>
<maml:description>
<maml:para> Parameter Description </maml:para>
</maml:description>
<command:parameterValue required="true">
Value
</command:parameterValue>
<dev:defaultValue> Default parameter value </dev:defaultValue>
<dev:possibleValues>
<dev:possibleValue>
<dev:value> Value 1 </dev:value>
<maml:description>
<maml:para> Description 1 </maml:para>
</maml:description>
<dev:possibleValue>
<dev:possibleValue>
<dev:value> Value 2 </dev:value>
<maml:description>
<maml:para> Description 2 </maml:para>
</maml:description>
<dev:possibleValue>
</dev:possibleValues>
</command:parameter>
</command:parameters>
Cómo agregar tipos de entrada a un
tema de Ayuda del cmdlet
Artículo • 25/09/2021

En esta sección se describe cómo agregar una sección INPUTS a un tema de Ayuda del
cmdlet de PowerShell. En la sección INPUTS se enumeran las clases .NET de objetos que
el cmdlet acepta como entrada de la canalización, ya sea por valor o por nombre de
propiedad.

No hay ningún límite en el número de clases que se pueden agregar a una sección
INPUTS. Los tipos de entrada se incluyen en un <command:inputTypes> nodo, con cada
clase incluida en un <command:inputType> elemento .

El esquema incluye dos <maml:description> elementos en cada <command:inputType>


elemento. Sin embargo, Get-Help el cmdlet muestra solo el contenido del
<command:inputType>/<maml:description> elemento.

A partir de PowerShell 3.0, el Get-Help cmdlet muestra el contenido del <maml:uri>


elemento. Este elemento le permite dirigir a los usuarios a temas que describen la clase
.NET.

El siguiente XML muestra el <maml:inputTypes> nodo.

XML

<command:inputTypes>
<command:inputType>
<dev:type>
<maml:name> Class name </maml:name>
<maml:uri> URI of a topic that describes the class </maml:uri>
<maml:description/>
</dev:type>
<maml:description>
<maml:para> Brief description </maml:para>
</maml:description>
</command:inputType>
</command:inputTypes>

En el xml siguiente se muestra un ejemplo de uso del <maml:inputTypes> nodo para


documentar un tipo de entrada.

XML
<command:inputTypes>
<command:inputType>
<dev:type>
<maml:name>System.DateTime</maml:name>

<maml:uri>https://docs.microsoft.com/dotnet/api/system.datetime</maml:uri>
<maml:description/>
</dev:type>
<maml:description>
<maml:para> You can pipe a date to the Set-Date cmdlet. <maml:para>
<maml:description>
</command:inputType>
</command:inputTypes>
Cómo agregar valores devueltos a un
tema de Ayuda del cmdlet
Artículo • 25/09/2021

En esta sección se describe cómo agregar una sección OUTPUTS a un tema de Ayuda
del cmdlet de PowerShell. En la sección OUTPUTS se enumeran las clases .NET de
objetos que el cmdlet devuelve o pasa por la canalización.

No hay ningún límite en el número de clases que puede agregar a la sección OUTPUTS.
Los tipos de valor devueltos de un cmdlet se incluyen en un nodo, con
<command:returnValues> cada clase incluida en un elemento <command:returnValue> .

Si un cmdlet no genera ninguna salida, use esta sección para indicar que no hay
ninguna salida. Por ejemplo, en lugar del nombre de clase, escriba None y proporcione
una breve explicación. Si el cmdlet genera la salida de forma condicional, use este nodo
para explicar las condiciones y describir la salida condicional.

El esquema incluye dos <maml:description> elementos en cada <command:returnValue>


elemento. Sin embargo, Get-Help el cmdlet muestra solo el contenido del
<command:returnValue>/<maml:description> elemento.

A partir de PowerShell 3.0, el Get-Help cmdlet muestra el contenido del <maml:uri>


elemento. Este elemento le permite dirigir a los usuarios a temas que describen la clase
.NET.

El siguiente XML muestra el <maml:returnValues> nodo.

XML

<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name> Class Name </maml:name>
<maml:uri> URI of a topic that describes the class </maml:uri>
<maml:description/>
</dev:type>
<maml:description>
<maml:para> Brief description <maml:para>

</maml:description>
</command: returnValue>
</command: returnValues>
En el xml siguiente se muestra un ejemplo del uso del <maml:returnValues> nodo para
documentar un tipo de salida.

XML

<command:returnValues>
<command:returnValue>
<dev:type>
<maml:name> System.DateTime </maml:name>
<maml:uri> https://docs.microsoft.com/dotnet/api/system.datetime
</maml:uri>
<maml:description/>
</dev:type>
<maml:description>
<maml:para> Get-Date returns a DateTime object. <maml:para>
</maml:description>
</command: returnValue>
</command: returnValues>
Cómo agregar notas a un tema de
Ayuda del cmdlet
Artículo • 25/09/2021

En esta sección se describe cómo agregar una sección NOTAS a un tema de Ayuda del
cmdlet de PowerShell. La sección NOTAS se usa para explicar aquellos detalles que no
encajan fácilmente en las otras secciones estructuradas, como una explicación más
detallada de un parámetro. Este contenido podría incluir comentarios sobre cómo
funciona el cmdlet con un proveedor específico, algunos usos únicos pero importantes
del cmdlet o formas de evitar posibles condiciones de error.

La sección NOTAS se define mediante un solo nodo <maml:alertset> . No existe ningún


límite en cuanto al número de notas que puede agregar a una sección Notas. Para cada
nota, agregue un par de etiquetas <maml:alert> al nodo <maml:alertset> . El contenido
de cada nota se agrega dentro de un conjunto de etiquetas <maml:para> . Use etiquetas
<maml:para> en blanco para el espaciado.

XML

<maml:alertSet>
<maml:title>Optional title for Note</maml:title>
<maml:alert>
<maml:para>Note 1</maml:para>
<maml:para>Note a</maml:para>
</maml:alert>
<maml:alert>
<maml:para>Note 2</maml:para>
</maml:alert>
</maml:alertSet>
Cómo agregar ejemplos a un tema de
Ayuda del cmdlet
Artículo • 25/09/2021

Aspectos que debe saber sobre los ejemplos de


la Ayuda de cmdlets
Enumera todos los nombres de parámetro en el comando, incluso cuando los
nombres de parámetro son opcionales. Esto ayuda al usuario a interpretar el
comando fácilmente.

Evite los alias y los nombres de parámetros parciales, aunque funcionen en


PowerShell.

En la descripción del ejemplo, explique la lógica para la construcción del comando.


Explique por qué eligió parámetros y valores concretos y cómo usar variables.

Si el comando usa expresiones, explíquelas en detalle.

Si el comando usa propiedades y métodos de objetos, especialmente las


propiedades que no aparecen en la pantalla predeterminada, use el ejemplo como
una oportunidad para que el usuario le informe sobre el objeto.

Vistas de Ayuda que muestran ejemplos


Los ejemplos solo aparecen en las vistas Detallada y Completa de la Ayuda del cmdlet.

Agregar un nodo de ejemplos


En el siguiente xml se muestra cómo agregar un nodo Examples que contiene un único
nodo de ejemplo. Agregue nodos de ejemplo adicionales para cada ejemplo que quiera
incluir en el tema.

XML

<command:examples>
<command:example>
</command:example>
</command:examples>
Agregar un título de ejemplo
En el siguiente XML se muestra cómo agregar un título para el ejemplo. El título se usa
para establecer el ejemplo aparte de otros ejemplos. PowerShell usa un encabezado
estándar que incluye un número de ejemplo secuencial.

XML

<command:examples>
<command:example>
<maml:title>---------- EXAMPLE 1 ----------</maml:title>
</command:example>
</command:examples>

Agregar caracteres anteriores


En el siguiente código XML se muestra cómo agregar caracteres, como el símbolo del
sistema Windows PowerShell, que se muestran inmediatamente antes del comando de
ejemplo (sin espacios que intervendrá). PowerShell usa el símbolo Windows PowerShell:
C:\PS> .

XML

<command:examples>
<command:example>
<maml:title>---------- EXAMPLE 1 ----------</maml:title>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
</command:example>
</command:examples>

Agregar el comando
El siguiente código XML muestra cómo agregar el comando real del ejemplo. Al agregar
el comando, escriba el nombre completo (no use alias) de cmdlets y parámetros.
Además, use caracteres en minúscula siempre que sea posible.

XML

<command:examples>
<command:example>
<maml:title>---------- EXAMPLE 1 ----------</maml:title>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
<dev:code> command </dev:code>
</command:example>
</command:examples>

Agregar una descripción


En el xml siguiente se muestra cómo agregar una descripción para el ejemplo.
PowerShell usa un único conjunto de <maml:para> etiquetas para la descripción, aunque
se pueden usar varias <maml:para> etiquetas.

XML

<command:examples>
<command:example>
<maml:title>---------- EXAMPLE 1 ----------</maml:title>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
<dev:code> command </dev:code>
<dev:remarks>
<maml:para> command description </maml:para>
</dev:remarks>
</command:example>
</command:examples>

Agregar salida de ejemplo


En el siguiente XML se muestra cómo agregar la salida del comando. La información de
los resultados del comando es opcional, pero en algunos casos resulta útil demostrar el
efecto de usar parámetros específicos. PowerShell usa dos conjuntos de etiquetas en
<maml:para> blanco para separar la salida del comando.

XML

<command:examples>
<command:example>
<maml:title>---------- EXAMPLE 1 ----------</maml:title>
<maml:Introduction>
<maml:paragraph>C:\PS></maml:paragraph>
</maml:Introduction>
<dev:code> command </dev:code>
<dev:remarks>
<maml:para> command description </maml:para>
<maml:para></maml:para>
<maml:para></maml:para>
<maml:para> command output </maml:para>
</dev:remarks>
</command:example>
</command:examples>
Cómo agregar vínculos relacionados a
un tema de Ayuda del cmdlet
Artículo • 25/09/2021

En esta sección se describe cómo agregar referencias a otro contenido relacionado con
un tema de Ayuda del cmdlet de PowerShell. Dado que estas referencias aparecen en
una ventana de comandos, no se vinculan directamente al contenido al que se hace
referencia.

En los temas de Ayuda del cmdlet que se incluyen en PowerShell, estos vínculos hacen
referencia a otros cmdlets, contenido conceptual ( ) y otros documentos y archivos de
Ayuda que no están relacionados about_ con PowerShell.

En el xml siguiente se muestra cómo agregar un nodo RelatedLinks que contiene dos
referencias a temas relacionados.

XML

<maml:relatedLinks>
<maml:navigationLink>
<maml:linkText>Topic-name</maml:linkText>
</maml:navigationLink>
<maml:navigationLink>
<maml:linkText>Topic-name</maml:linkText>
</maml:navigationLink>
</ maml:relatedLinks >
Escritura de la ayuda de los módulos de
PowerShell
Artículo • 25/09/2021

Los módulos de PowerShell pueden incluir temas de Ayuda sobre el módulo y sobre los
miembros del módulo, como cmdlets, proveedores, funciones y scripts. El cmdlet
muestra los temas de Ayuda del módulo en el mismo formato que muestra ayuda para
otros elementos de PowerShell, y los usuarios usan comandos estándar para Get-Help
obtener los temas de Get-Help Ayuda.

En este documento se explica el formato y la ubicación correcta de los temas de Ayuda


del módulo, y se sugieren directrices para el contenido de ayuda del módulo.

Tipos de Ayuda del módulo


Un módulo puede incluir los siguientes tipos de Ayuda.

Ayuda del cmdlet. Los temas de Ayuda que describen los cmdlets de un módulo
son archivos XML que usan el esquema de ayuda del comando

Ayuda del proveedor. Los temas de Ayuda que describen los proveedores de un
módulo son archivos XML que usan el esquema de ayuda del proveedor.

Ayuda de la función. Los temas de Ayuda que describen las funciones de un


módulo pueden ser archivos XML que usan el esquema de ayuda de comandos o
temas de Ayuda basados en comentarios dentro de la función, o el módulo script
o script.

Script de ayuda. Los temas de Ayuda que describen los scripts de un módulo
pueden ser archivos XML que usan el esquema de ayuda de comandos o temas de
Ayuda basados en comentarios en el módulo de script o script.

Ayuda conceptual ("Acerca de"). Puede usar un tema de Ayuda conceptual


("about") para describir el módulo y sus miembros y explicar cómo se pueden usar
juntos los miembros para realizar tareas. Los temas de ayuda conceptual son
archivos de texto con codificación Unicode (UTF-8). El nombre de archivo debe
usar about_<name>.help.txt el formato , como about_MyModule.help.txt . De
forma predeterminada, PowerShell incluye más de 100 de estos temas
conceptuales acerca de la Ayuda y tienen un formato como el del ejemplo
siguiente.
Output

TOPIC
about_<subject or module name>

SHORT DESCRIPTION
A short, one-line description of the topic contents.

LONG DESCRIPTION
A detailed, full description of the subject or purpose of the
module.

EXAMPLES
Examples of how to use the module or how the subject feature works
in practice.

KEYWORDS
Terms or titles on which you might expect your users to search for
the information in this topic.

SEE ALSO
Text-only references for further reading. Hyperlinks cannot work in
the PowerShell console.

Todos los archivos de esquema se pueden encontrar en la $PSHOME\Schemas\PSMaml


carpeta .

Colocación de la Ayuda del módulo


El Get-Help cmdlet busca archivos de temas de ayuda del módulo en subdirectorios
específicos del lenguaje del directorio del módulo.

Por ejemplo, el siguiente diagrama de estructura de directorios muestra la ubicación de


los temas de Ayuda para el módulo SampleModule.

<ModulePath>
\SampleModule
\<en-US>
\about_SampleModule.help.txt
\SampleModule.dll-help.xml
\SampleNestedModule.dll-help.xml
\<fr-FR>
\about_SampleModule.help.txt
\SampleModule.dll-help.xml
\SampleNestedModule.dll-help.xml
7 Nota

En el ejemplo, el marcador de posición representa una de las rutas de acceso de la


variable de entorno, como , o una ruta de acceso personalizada que <ModulePath>
PSModulePath el usuario $HOME\Documents\Modules $PSHOME\Modules especifica.

Obtener ayuda del módulo


Cuando un usuario importa un módulo en una sesión, los temas de Ayuda de ese
módulo se importan en la sesión junto con el módulo. Puede enumerar los archivos de
temas de Ayuda en el valor de la clave FileList en el manifiesto del módulo, pero el
cmdlet no afecta a los temas de Export-ModuleMember Ayuda.

Puede proporcionar temas de Ayuda del módulo en distintos idiomas. El cmdlet muestra
automáticamente los temas de Ayuda del módulo en el idioma especificado para el
usuario actual en el elemento Opciones regionales y de idioma Get-Help de Panel de
control. En Windows Vista y versiones posteriores de Windows, busca los temas de
Ayuda en subdirectorios específicos del lenguaje del directorio del módulo de acuerdo
con los estándares de reserva de idioma establecidos Get-Help para Windows.

A partir de PowerShell 3.0, la ejecución de un comando para un cmdlet o una función


desencadena la Get-Help importación automática del módulo. El Get-Help cmdlet
muestra inmediatamente el contenido de los temas de ayuda del módulo.

Si el módulo no contiene temas de ayuda y no hay temas de ayuda para los comandos
del módulo en el equipo del usuario, muestra la ayuda Get-Help generada
automáticamente. La ayuda generada automáticamente incluye la sintaxis de comandos,
los parámetros y los tipos de entrada y salida, pero no incluye ninguna descripción. La
ayuda generada automáticamente incluye texto que dirige al usuario a intentar usar el
cmdlet para descargar ayuda para el comando desde Internet o un Update-Help recurso
compartido de archivos. También recomienda usar el parámetro Online del Get-Help
cmdlet para obtener la versión en línea del tema de ayuda.

Compatibilidad con la Ayuda actualizable


Los usuarios de PowerShell 3.0 y versiones posteriores de PowerShell pueden descargar
e instalar archivos de ayuda actualizados para un módulo desde Internet o desde un
recurso compartido de archivos local. Los Update-Help Save-Help cmdlets y ocultan los
detalles de administración al usuario. Los usuarios ejecutan el cmdlet y, a continuación,
usan el cmdlet para leer los archivos de ayuda más nuevos del módulo Update-Help en
el símbolo del sistema de Get-Help PowerShell. Los usuarios no necesitan reiniciar
Windows o PowerShell.

Los usuarios que están detrás de los firewalls y los que no tienen acceso a Internet
también pueden usar la Ayuda actualizable. Los administradores con acceso a Internet
usan el cmdlet para descargar e instalar los archivos de ayuda más nuevos Save-Help en
un recurso compartido de archivos. A continuación, los usuarios usan el parámetro Path
del Update-Help cmdlet para obtener los archivos de ayuda más nuevos del recurso
compartido de archivos.

Los autores de módulos pueden incluir archivos de ayuda en el módulo y usar la Ayuda
actualizable para actualizar los archivos de ayuda, u omitir los archivos de ayuda del
módulo y usar la Ayuda actualizable para instalarlos y actualizarlos.

Para obtener más información sobre la Ayuda actualizable, vea Supporting Updatable
Help.

Compatibilidad con la Ayuda en línea


Los usuarios que no pueden o no instalan archivos de ayuda actualizados en sus
equipos suelen confiar en la versión en línea de los temas de ayuda del módulo. El
parámetro Online del cmdlet abre la versión en línea de un cmdlet o tema de ayuda de
función avanzada para el usuario en su explorador de Internet Get-Help
predeterminado.

El Get-Help cmdlet usa el valor de la propiedad HelpUri del cmdlet o la función para
buscar la versión en línea del tema de ayuda.

A partir de PowerShell 3.0, puede ayudar a los usuarios a encontrar la versión en línea
de los temas de ayuda de cmdlets y funciones mediante la definición del atributo
HelpUri en la clase de cmdlet o la propiedad HelpUri del atributo CmdletBinding. El
valor del atributo es el valor de la propiedad HelpUri del cmdlet o la función.

Para obtener más información, vea Supporting Online Help.

Consulte también
Escritura de un módulo de PowerShell

Compatibilidad con la Ayuda actualizable


Compatibilidad con la Ayuda en línea
Asignación de un nombre a los archivos
de ayuda
Artículo • 25/09/2021

En este tema se explica cómo dar nombre a un archivo de ayuda basado en XML para
que el cmdlet Get-Help pueda encontrarlo. Los requisitos de nombre difieren para cada
tipo de comando.

Archivos de ayuda de cmdlets


El archivo de ayuda de un cmdlet de C# debe tener el nombre del ensamblado en el que
se define el cmdlet. Use el siguiente formato de nombre de archivo:

<AssemblyName>.dll-help.xml

El formato de nombre de ensamblado es necesario incluso cuando el ensamblado es un


módulo anidado.

Por ejemplo, el cmdlet Get-WinEvent se define en el Microsoft.PowerShell.Diagnostics.dll


ensamblado. El Get-Help cmdlet busca un tema de ayuda para el cmdlet solo en el
archivo del directorio del Get-WinEvent Microsoft.PowerShell.Diagnostics.dll-help.xml
módulo.

Archivos de Ayuda del proveedor


El archivo de ayuda de un proveedor de PowerShell debe tener el nombre del
ensamblado en el que se define el proveedor. Use el siguiente formato de nombre de
archivo:

<AssemblyName>.dll-help.xml

El formato de nombre de ensamblado es necesario incluso cuando el ensamblado es un


módulo anidado.

Por ejemplo, el proveedor de certificados se define en el


Microsoft.PowerShell.Security.dll ensamblado. El Get-Help cmdlet busca un tema de

ayuda para el proveedor de certificados solo en el archivo del directorio del


Microsoft.PowerShell.Security.dll-help.xml módulo.
Archivos de Ayuda de función
Las funciones se pueden documentar mediante ayuda basada en comentarios o
documentadas en un archivo de ayuda XML. Cuando la función se documenta en un
archivo XML, la función debe tener una palabra clave comment que asocie la función
.ExternalHelp al archivo XML. De lo contrario, Get-Help el cmdlet no puede encontrar

el archivo de ayuda.

No hay ningún requisito técnico para el nombre de un archivo de ayuda de función. Sin
embargo, un procedimiento recomendado es dar nombre al archivo de ayuda para el
módulo de script en el que se define la función. Por ejemplo, la siguiente función se
define en el MyModule.psm1 archivo .

C#

#.ExternalHelp MyModule.psm1-help.xml
function Test-Function { ... }

Archivos de ayuda del comando CIM


El archivo de ayuda de un comando CIM debe tener el nombre del archivo CDXML en el
que se define el comando CIM. Use el siguiente formato de nombre de archivo:

<FileName>.cdxml-help.xml

Los comandos CIM se definen en archivos CDXML que se pueden incluir en módulos
como módulos anidados. Cuando el comando CIM se importa en la sesión como una
función, PowerShell agrega una palabra clave comment a la definición de función que
asocia la función a un archivo de ayuda XML denominado para el archivo CDXML en el
que se define el .ExternalHelp comando CIM.

Archivos de ayuda de flujo de trabajo de script


Los flujos de trabajo de script que se incluyen en los módulos se pueden documentar en
archivos de ayuda basados en XML. No hay ningún requisito técnico para el nombre del
archivo de ayuda. Sin embargo, un procedimiento recomendado es dar nombre al
archivo de ayuda para el módulo de script en el que se define el flujo de trabajo de
script. Por ejemplo:

<ScriptModule>.psm1-help.xml
A diferencia de otros comandos con script, los flujos de trabajo de script no requieren
una palabra .ExternalHelp clave comment para asociarlos a un archivo de ayuda. En su
lugar, PowerShell busca archivos de ayuda basados en XML en los subdirectorios
específicos de ui-Culture del directorio del módulo y busca ayuda para el flujo de
trabajo de script en todos los archivos. .ExternalHelp Se omite la palabra clave
comment.

Dado que la palabra clave comment se omite, el cmdlet puede encontrar ayuda para los
flujos de trabajo de script solo .ExternalHelp cuando se incluyen en los Get-Help
módulos.
Compatibilidad con la Ayuda
actualizable
Artículo • 25/09/2021

El sistema Ayuda actualizable de Windows PowerShell, introducido en Windows 8 y


Windows Server 2012, está diseñado para garantizar que los usuarios siempre tengan
los temas de ayuda más recientes en el símbolo del sistema en su equipo local. Junto
con la ayuda en línea de Windows PowerShell, la Ayuda actualizable proporciona una
solución de ayuda completa para los usuarios. En esta sección se describe el sistema
Ayuda actualizable y se explica la forma que tienen los autores de módulos de admitirlo
en estos.

Esta sección incluye los temas siguientes.

Información general acerca de la Ayuda actualizable

Creación de la Ayuda actualizable: paso a paso

Cómo funciona la Ayuda actualizable

Cómo crear un archivo HelpInfo XML

Cómo preparar archivos CAB de Ayuda actualizables

Cómo actualizar los archivos de Ayuda

Cómo probar la Ayuda actualizable

Vea también
Compatibilidad con la Ayuda en línea

Tabla de estado de la Ayuda actualizable


Información general acerca de la Ayuda
actualizable
Artículo • 25/09/2021

En este documento se proporciona una introducción básica al diseño y el


funcionamiento de la característica ayuda actualizable de PowerShell. Está diseñado para
los autores de módulos y otros usuarios que ofrecen Windows PowerShell temas de
ayuda a los usuarios.

Introducción
Los temas de ayuda de PowerShell son una parte integral de la experiencia de
PowerShell. Al igual que los módulos de PowerShell, los autores y las contribuciones de
la comunidad de usuarios de PowerShell actualizan y mejoran continuamente los temas
de ayuda.

La característica Ayuda actualizable, introducida en Windows PowerShell 3.0, garantiza


que los usuarios tengan las versiones más recientes de los temas de ayuda en el
símbolo del sistema, incluso para los comandos de PowerShell integrados, sin descargar
nuevos módulos ni ejecutar Windows Update. La Ayuda actualizable facilita la
actualización proporcionando cmdlets que descargan las versiones más recientes de los
temas de ayuda de Internet e instállas en los subdirectorios correctos del equipo local
del usuario. Incluso los usuarios que están detrás de firewalls pueden usar los nuevos
cmdlets para obtener ayuda actualizada de un recurso compartido de archivos interno.

La Ayuda actualizable es totalmente compatible con todos los módulos Windows


PowerShell de Windows 8 y Windows Server 2012, y sus características están disponibles
para todos los Windows PowerShell de módulos. La Ayuda actualizable solo admite
archivos de ayuda basados en XML. No admite ayuda basada en comentarios.

La Ayuda actualizable incluye las siguientes características.

El cmdlet Update-Help, que determina si los usuarios tienen los archivos de ayuda
más recientes para un módulo y, si no, descarga los archivos de ayuda más
recientes de Internet, los desempaquete y los instala en los subdirectorios de
módulo correctos en el equipo del usuario. Los usuarios pueden usar el cmdlet
Get-Help para ver inmediatamente los temas de ayuda recién instalados. No es
necesario reiniciar PowerShell.
El cmdlet Save-Help, que descarga los archivos de ayuda más recientes de Internet
y los guarda en un directorio del sistema de archivos. Los usuarios pueden usar el
cmdlet para obtener archivos de ayuda del directorio del sistema de archivos y
desempaquetarlos e instalarlos en los subdirectorios del módulo en el Update-Help
equipo del usuario. El cmdlet está diseñado para los usuarios que tienen acceso
limitado o no a Internet y para las empresas Save-Help que prefieren limitar el
acceso a Internet.

Ayuda para un módulo. Los archivos de ayuda de un módulo se administran y


entregan como una unidad, para que los usuarios puedan obtener todos los
archivos de ayuda de los módulos que usan. La ayuda actualizable solo se admite
para módulos, no para Windows PowerShell complementos.

La versión admite. La Ayuda actualizable usa cuatro posiciones estándar (N1. N2.
N3. N4) números de versión. La Ayuda actualizable descarga archivos de ayuda
cuando el número de versión de los archivos de ayuda en el equipo del usuario (o
en el directorio) es inferior al número de versión de los archivos de ayuda en la
ubicación Save-Help de Internet.

Compatibilidad con varios idiomas. La Ayuda actualizable admite archivos de


ayuda de módulo en varias referencia culturales de interfaz de usuario. Los
nombres de archivo de Ayuda actualizables incluyen códigos de idioma estándar,
como "en-US" y "ja-JP", y los cmdlets y colocarán los archivos de ayuda en
subdirectorios específicos del idioma del directorio del Update-Help Save-Help
módulo.

Ayuda generada automáticamente. El cmdlet Get-Help muestra ayuda básica para


los comandos que no tienen archivos de ayuda. La ayuda generada
automáticamente incluye la sintaxis y los alias de los comandos, así como
instrucciones para usar la ayuda en línea y la Ayuda actualizable.

Ayuda mejorada en línea. El acceso sencillo a la ayuda en línea ya no requiere


archivos de ayuda. El parámetro Online del cmdlet ahora obtiene la dirección URL
de un tema de ayuda en línea del valor de la propiedad HelpUri de cualquier
comando, si no encuentra la dirección URL de ayuda en línea en un archivo Get-
Help de ayuda. Puede rellenar la propiedad HelpUri agregando un atributo
HelpUri al código de cmdlets, funciones y comandos CIM, o mediante . Vincular
directiva de ayuda basada en comentarios en flujos de trabajo y scripts.

Para que nuestros archivos de ayuda se puedan actualizando, los módulos de


Windows PowerShell en Windows 8 y Windows Server vNext no incluyen archivos
de ayuda. Los usuarios pueden usar la Ayuda actualizable para instalar archivos de
ayuda y actualizarlos. Los autores de otros módulos pueden incluir archivos de
ayuda en módulos u omitirlos. La compatibilidad con la Ayuda actualizable es
opcional, pero se recomienda.
Creación de la Ayuda actualizable: paso
a paso
Artículo • 25/09/2021

En este documento se enumeran los pasos del proceso de creación de la Ayuda


actualizable.

Creación de ayuda actualizable: Paso a paso


La Ayuda actualizable está diseñada para los usuarios finales, pero también proporciona
importantes ventajas a los autores de módulos y escritores de ayuda, incluida la
capacidad de agregar contenido, corregir errores, entregar varias culturas de interfaz de
usuario y responder a las solicitudes y comentarios de los usuarios, mucho después de
que se haya enviado el módulo. En este tema se explica cómo empaquetar y cargar
archivos de ayuda para que los usuarios puedan descargarlos e instalarlos mediante los
cmdlets Update-Help y Save-Help.

Los pasos siguientes proporcionan información general sobre el proceso de


compatibilidad con la Ayuda actualizable.

Paso 1: Buscar un sitio de Internet para los archivos de


ayuda
El primer paso para crear ayuda actualizable es buscar una ubicación de Internet para
los archivos de ayuda del módulo. En realidad, puede usar dos ubicaciones diferentes.
Puede mantener el archivo de información de ayuda del módulo (HelpInfo XML , que se
describe a continuación) en una ubicación de Internet y los archivos CAB de contenido
de ayuda en otra ubicación de Internet. Todos los archivos CAB de contenido de ayuda
de un módulo deben estar en la misma ubicación. Puede colocar archivos CAB de
contenido de ayuda para distintos módulos en la misma ubicación.

Paso 2: Agregar una clave HelpInfoURI al manifiesto del


módulo
Agregue una clave HelpInfoURI al manifiesto del módulo. El valor de la clave es el
identificador uniforme de recursos (URI) de la ubicación del archivo de información XML
HelpInfo del módulo. Por motivos de seguridad, la dirección debe comenzar por "http"
o "https". El URI debe especificar una ubicación de Internet, pero no debe incluir el
nombre de archivo XML HelpInfo.

Por ejemplo:

PowerShell

@{
RootModule = TestModule.psm1
ModuleVersion = '2.0'
HelpInfoURI = 'https://go.microsoft.com/fwlink/?LinkID=0123'
}

Paso 3: Crear un archivo XML HelpInfo


El archivo de información XML HelpInfo contiene el URI de la ubicación de Internet de
los archivos de ayuda y los números de versión de los archivos de ayuda más nuevos
para el módulo en cada referencia cultural de la interfaz de usuario admitida. Cada
Windows PowerShell módulo tiene un archivo XML HelpInfo. Al actualizar los archivos
de ayuda, edita o reemplaza el archivo XML HelpInfo; no agrega otro. Para obtener más
información, vea How to Create a HelpInfo XML File.

Paso 4: Crear archivos CAB


Use una herramienta que cree archivos de archivador (), como , para crear un archivo
CAB que contenga los .cab archivos de ayuda del MakeCab.exe módulo. Cree un archivo
CAB independiente para los archivos de ayuda en cada referencia cultural de interfaz de
usuario compatible. Para obtener más información, vea How to Prepare Updatable Help
CAB Files.

Paso 5: Upload los archivos


Para publicar archivos de ayuda nuevos o actualizados, cargue los archivos CAB en la
ubicación de Internet especificada por el elemento HelpContentUri en el archivo XML
HelpInfo. A continuación, cargue el archivo XML HelpInfo en la ubicación de Internet
especificada por el valor de la clave HelpInfoUri en el manifiesto del módulo.
Cómo funciona la Ayuda actualizable
Artículo • 25/09/2021

En este tema se explica cómo la Ayuda actualizable procesa el archivo HELPInfo XML y
los archivos CAB para cada módulo, e instala la ayuda actualizada para los usuarios.

El Update-Help proceso
En la lista siguiente se describen las acciones del cmdlet Update-Help cuando un
usuario ejecuta un comando para actualizar los archivos de ayuda de un módulo en una
referencia cultural de interfaz de usuario determinada.

1. Update-Help obtiene el archivo XML HelpInfo remoto de la ubicación especificada


por el valor de la clave HelpInfoURI en el manifiesto del módulo y valida el archivo
con el esquema. (Para ver el esquema, vea HelpInfo XML Schema).) A Update-Help
continuación, busca un archivo XML HelpInfo local para el módulo en el directorio
del módulo en el equipo del usuario.

2. Update-Help compara el número de versión de los archivos de ayuda para la


referencia cultural de la interfaz de usuario especificada en los archivos XML
HelpInfo remotos y locales del módulo. Si el número de versión del archivo remoto
es mayor que el número de versión del archivo local, o si no hay ningún archivo
XML HelpInfo local para el módulo, se prepara para descargar nuevos archivos de
Update-Help ayuda.

3. Update-Help selecciona el archivo CAB para el módulo en la ubicación especificada


por el elemento HelpContentUri en el archivo XML HelpInfo remoto. Usa el
nombre del módulo, el GUID del módulo y la referencia cultural de la interfaz de
usuario para identificar el archivo CAB.

4. Update-Help descarga el archivo CAB, lo desempaquete, valida los archivos de


contenido de ayuda y guarda los archivos de contenido de ayuda en el
subdirectorio específico del idioma del directorio del módulo en el equipo del
usuario.

5. Update-Help crea un archivo XML HelpInfo local copiando el archivo XML HelpInfo
remoto. Edita el archivo XML HelpInfo local para que incluya elementos solo para
el archivo CAB que instaló. A continuación, guarda el archivo XML HelpInfo local
en el directorio del módulo y concluye la actualización.
El Save-Help proceso
En la lista siguiente se describen las acciones de los cmdlets Save-Help y Update-Help
cuando un usuario ejecuta comandos para actualizar los archivos de ayuda en un
recurso compartido de archivos y, a continuación, los usa para actualizar los archivos de
ayuda en el equipo del usuario.

El cmdlet realiza las siguientes acciones en respuesta a un comando para guardar los
archivos de ayuda de un módulo en un recurso compartido de archivos especificado por
el Save-Help parámetro DestinationPath.

1. Save-Help obtiene el archivo XML HelpInfo remoto de la ubicación especificada


por el valor de la clave HelpInfoURI en el manifiesto del módulo y valida el archivo
con el esquema. (Para ver el esquema, vea HelpInfo XML Schema).) A continuación,
busca un archivo XML HelpInfo local en el directorio especificado por el parámetro
Save-Help DestinationPath en el Save-Help comando .

2. Save-Help compara el número de versión de los archivos de ayuda para la


referencia cultural de la interfaz de usuario especificada en los archivos XML
HelpInfo remotos y locales del módulo. Si el número de versión del archivo remoto
es mayor que el número de versión en el archivo local, o si no hay ningún archivo
XML HelpInfo local para el módulo en el directorio DestinationPath, se prepara
para descargar nuevos archivos de Save-Help ayuda.

3. Save-Help selecciona el archivo CAB para el módulo en la ubicación especificada


por el elemento HelpContentUri en el archivo XML HelpInfo remoto. Usa el
nombre del módulo, el GUID del módulo y la referencia cultural de la interfaz de
usuario para identificar el archivo CAB.

4. Save-Help descarga el archivo CAB y lo guarda en el directorio DestinationPath.


(No crea ningún subdirectorio específico del lenguaje).

5. Save-Help crea un archivo XML HelpInfo local copiando el archivo XML HelpInfo
remoto. Edita el archivo XML HelpInfo local para que incluya elementos solo para
el archivo CAB que guardó. A continuación, guarda el archivo XML HelpInfo local
en el directorio DestinationPath y concluye la actualización.

El cmdlet realiza las siguientes acciones en respuesta a un comando para actualizar


los archivos de ayuda en el equipo de un usuario desde los archivos de un recurso
compartido de archivos especificado por el Update-Help parámetro SourcePath.

6. Update-Help obtiene el archivo XML HelpInfo remoto del directorio SourcePath. A


continuación, busca un archivo XML HelpInfo local en el directorio del módulo en
el equipo del usuario.

7. Update-Help compara el número de versión de los archivos de ayuda para la


referencia cultural de la interfaz de usuario especificada en los archivos XML
HelpInfo remotos y locales del módulo. Si el número de versión del archivo remoto
es mayor que el número de versión en el archivo local, o si no hay ningún archivo
XML HelpInfo local, se prepara para instalar nuevos archivos Update-Help de
ayuda.

8. Update-Help selecciona el archivo CAB para el módulo en el directorio SourcePath.


Usa el nombre del módulo, el GUID del módulo y la referencia cultural de la
interfaz de usuario para identificar el archivo CAB.

9. Update-Help desempaquete el archivo CAB, valida los archivos de contenido de


ayuda y guarda los archivos de contenido de ayuda en el subdirectorio específico
del idioma del directorio del módulo en el equipo del usuario.

10. Update-Help crea un archivo XML HelpInfo local copiando el archivo XML HelpInfo
remoto. Edita el archivo XML HelpInfo local para que incluya elementos solo para
el archivo CAB que instaló. A continuación, guarda el archivo XML HelpInfo local
en el directorio del módulo y concluye la actualización.
Cómo crear un archivo HelpInfo XML
Artículo • 25/09/2021

En este tema de esta sección se explica cómo crear y rellenar un archivo de información
de ayuda, conocido normalmente como "Archivo XML HelpInfo", para la característica
ayuda actualizable de PowerShell.

Información general sobre el archivo XML


HelpInfo
El archivo XML HelpInfo es el origen principal de información sobre la Ayuda
actualizable del módulo. Incluye la ubicación de los archivos de ayuda para los módulos,
las referencia culturales de interfaz de usuario admitidas y los números de versión que la
Ayuda actualizable usa para determinar si el usuario tiene los archivos de ayuda más
nuevos.

Cada módulo tiene un solo archivo HELPInfo XML, incluso si el módulo incluye varios
archivos de ayuda para varias referencia culturales de interfaz de usuario. El autor del
módulo crea el archivo XML HelpInfo y lo coloca en la ubicación de Internet
especificada por la clave HelpInfoUri en el manifiesto del módulo. Cuando se actualizan
y cargan los archivos de ayuda del módulo, el autor del módulo actualiza el archivo XML
HelpInfo y reemplaza el archivo XML HelpInfo original por la nueva versión.

Es fundamental que el archivo XML HelpInfo se mantenga cuidadosamente. Si carga


nuevos archivos, pero olvida incrementar los números de versión, la Ayuda actualizable
no descargará los nuevos archivos en los equipos de los usuarios. Si agrega archivos de
ayuda para una nueva referencia cultural de interfaz de usuario, pero no actualiza el
archivo XML HelpInfo ni lo coloca en la ubicación correcta, la Ayuda actualizable no
descargará los nuevos archivos.

En esta sección
Esta sección incluye los temas siguientes.

Esquema HelpInfo XML

Archivo de ejemplo de HelpInfo XML

Cómo asignar un nombre a un archivo HelpInfo XML

Cómo establecer números de versión de HelpInfo XML


Consulte también
Compatibilidad con la Ayuda actualizable
Esquema HelpInfo XML
Artículo • 26/09/2021

Este tema contiene el esquema XML para los archivos de información de ayuda
actualizables, normalmente conocidos como "archivos HELPINFO XML".

Esquema HelpInfo XML


Los archivos HELPInfo XML se basan en el siguiente esquema XML.

XML

<?xml version="1.0" encoding="utf-8"?>


<schema
targetNamespace="http://schemas.microsoft.com/powershell/help/2010/05"
xmlns="http://www.w3.org/2001/XMLSchema">
<element name="HelpInfo">
<complexType>
<sequence>
<element name="HelpContentURI" type="anyURI" minOccurs="1"
maxOccurs="1" />
<element name="SupportedUICultures" minOccurs="1" maxOccurs="1">
<complexType>
<sequence>
<element name="UICulture" minOccurs="1" maxOccurs="unbounded">
<complexType>
<sequence>
<element name="UICultureName" type="language"
minOccurs="1" maxOccurs="1" />
<element name="UICultureVersion" type="string"
minOccurs="1" maxOccurs="1" />
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</sequence>
</complexType>
</element>
</schema>

Elementos XML HelpInfo


El archivo XML HelpInfo incluye los siguientes elementos.
HelpContentURI: contiene el URI de la ubicación de los archivos CAB de ayuda
para el módulo. El URI debe comenzar por "http" o "https". El URI debe especificar
una ubicación de Internet, pero no debe incluir el nombre de archivo CAB. El valor
helpContentURI puede ser igual o diferente del valor HelpInfoURI.

SupportedUICultures: representa los archivos de ayuda del módulo en todas las


referencia culturales de interfaz de usuario. Contiene elementos UICulture, cada
uno de los cuales representa un conjunto de archivos de ayuda para el módulo en
una referencia cultural de interfaz de usuario especificada.

UICulture: representa un conjunto de archivos de ayuda para el módulo en una


referencia cultural de interfaz de usuario especificada. Agregue un elemento
UICulture para cada referencia cultural de interfaz de usuario en la que se escriben
los archivos de ayuda.

UICultureName: contiene el código de idioma de la referencia cultural de la


interfaz de usuario en la que se escriben los archivos de ayuda.

UICultureVersion: contiene un número de versión de 4 partes en "N1. N2. N3.


Formato N4" que representa la versión del archivo CAB de ayuda en la referencia
cultural de la interfaz de usuario. Incremente este número de versión cada vez que
cargue nuevos archivos CAB de ayuda en la referencia cultural de la interfaz de
usuario especificada por UICultureName. Para obtener más información sobre este
valor, vea Clase de versión.
Archivo de ejemplo de HelpInfo XML
Artículo • 26/09/2021

En este tema se muestra un ejemplo de un archivo de información de ayuda actualizable


bien formado, conocido normalmente como "archivo XML HelpInfo". En este archivo de
ejemplo, los elementos de la referencia cultural de la interfaz de usuario se organizan en
orden alfabético por nombre de referencia cultural de la interfaz de usuario. El orden
alfabético es un procedimiento recomendado, pero no es necesario.

Archivo de ejemplo de HelpInfo XML


XML

<?xml version="1.0" encoding="utf-8"?>


<HelpInfo xmlns="http://schemas.microsoft.com/powershell/help/2010/05">
<HelpContentURI>https://go.microsoft.com/fwlink/?
LinkID=141553</HelpContentURI>
<SupportedUICultures>
<UICulture>
<UICultureName>de-DE</UICultureName>
<UICultureVersion>2.15.0.10</UICultureVersion>
</UICulture>
<UICulture>
<UICultureName>en-US</UICultureName>
<UICultureVersion>3.2.0.7</UICultureVersion>
</UICulture>
<UICulture>
<UICultureName>it-IT</UICultureName>
<UICultureVersion>1.1.0.5</UICultureVersion>
</UICulture>
<UICulture>
<UICultureName>ja-JP</UICultureName>
<UICultureVersion>3.2.0.4</UICultureVersion>
</UICulture>
</SupportedUICultures>
</HelpInfo>
Cómo asignar un nombre a un archivo
HelpInfo XML
Artículo • 25/09/2021

En este tema se explica el formato de nombre necesario para los archivos de


información de ayuda actualizables, normalmente conocidos como archivos XML
HelpInfo.

Cómo asignar un nombre a un archivo HelpInfo


XML
Un archivo XML HelpInfo debe tener un nombre con el formato siguiente.

<ModuleName>_<ModuleGUID>_HelpInfo.xml

Los elementos del nombre son los siguientes.

<ModuleName> - Valor de la propiedad Name del objeto ModuleInfo que devuelve

el cmdlet Get-Module.

<ModuleGUID> : el valor de la clave GUID en el manifiesto del módulo.

Por ejemplo, si el nombre del módulo es "TestModule" y el GUID del módulo es


9cabb9ad-f2ac-4914-a46b-bfc1bebf07f9, el nombre del archivo XML HelpInfo para el
módulo sería:

TestModule_9cabb9ad-f2ac-4914-a46b-bfc1bebf07f9_HelpInfo.xml
Cómo establecer números de versión de
HelpInfo XML
Artículo • 25/09/2021

En este tema se explica cómo establecer y aumentar los números de versión en un


archivo de información de ayuda actualizable, conocido normalmente como "archivo
XML HelpInfo".

Cómo establecer números de versión de


HelpInfo XML
Los números de versión de un archivo XML HelpInfo son fundamentales para el
funcionamiento de la Ayuda actualizable. Los cmdlets Update-Help y Save-Help
descargan nuevos archivos de ayuda solo cuando el número de versión de una
referencia cultural de interfaz de usuario en el archivo XML HelpInfo remoto es mayor
que el número de versión de esa referencia cultural de la interfaz de usuario en el XML
HelpInfo local o no hay ningún archivo XML HelpInfo local.

El archivo XML HelpInfo usa el número de versión de 4 partes que se define en la clase
System.Version de Microsoft .NET Framework. El formato es N1.N2.N3.N4 . Los autores
de módulos pueden usar cualquier esquema de numeración de versiones permitido por
la clase System.Version. La Ayuda actualizable solo requiere que el número de versión
de una referencia cultural de la interfaz de usuario aumente cuando se cargue una
nueva versión del archivo CAB para esa referencia cultural de interfaz de usuario en la
ubicación especificada por el elemento HelpContentURI en el archivo XML HelpInfo.

En el ejemplo siguiente se muestran los elementos del archivo XML HelpInfo para la
referencia cultural de la interfaz de usuario alemana (de-DE) cuando la versión es
2.15.0.10.

XML

<UICulture>
<UICultureName>de-DE</UICultureName>
<UICultureVersion>2.15.0.10</UICultureVersion>
</UICulture>

El número de versión de una referencia cultural de la interfaz de usuario refleja la


versión del archivo CAB para esa referencia cultural de la interfaz de usuario. El número
de versión se aplica a todo el archivo CAB. No se pueden establecer números de versión
diferentes para distintos archivos en el archivo CAB. El número de versión de cada
referencia cultural de la interfaz de usuario se evalúa de forma independiente y no
necesita estar relacionado con los números de versión de otras referencia culturales de
la interfaz de usuario que admite el módulo.
Cómo preparar archivos CAB de Ayuda
actualizables
Artículo • 25/09/2021

En este tema se explica el contenido y el uso de archivos de archivo (1) en Windows


PowerShell ayuda actualizable.

Esta sección incluye los temas siguientes.

Cómo crear y cargar archivos CAB


Cómo asignar un nombre a un archivo CAB de Ayuda actualizable
Tipos de archivo permitidos en un archivo CAB de Ayuda actualizable

Consulte también
Compatibilidad con la Ayuda actualizable
Cómo crear y cargar archivos CAB
Artículo • 25/09/2021

En este tema se explica cómo crear archivos CAB de Ayuda actualizables y cargarlos en
la ubicación donde los cmdlets de Ayuda actualizables pueden encontrarlos.

Cómo crear y crear Upload archivos CAB de


ayuda actualizables
Puede usar la característica Ayuda actualizable para entregar archivos de ayuda nuevos
o actualizados para un módulo en varios idiomas y referencia culturales. Un paquete de
Ayuda actualizable para un módulo consta de un archivo XML HelpInfo y uno o varios
archivos de archivado ( .CAB ). Cada archivo CAB contiene archivos de ayuda para el
módulo en una referencia cultural de interfaz de usuario. Use el procedimiento siguiente
para crear archivos CAB para obtener ayuda actualizable.

1. Organice los archivos de ayuda para el módulo por referencia cultural de la


interfaz de usuario. Cada archivo CAB de Ayuda actualizable contiene los archivos
de ayuda de un módulo en una referencia cultural de interfaz de usuario. Puede
entregar varios archivos CAB de ayuda para el módulo, cada uno para una
referencia cultural de interfaz de usuario diferente.

2. Compruebe que los archivos de ayuda incluyan solo los tipos de archivo
permitidos para la Ayuda actualizable y consúltelos con un esquema de archivo de
ayuda. Si el cmdlet encuentra un archivo que no es válido o no es un tipo
permitido, no instala el archivo no válido y deja de instalar archivos Update-Help
desde cab. Para obtener una lista de los tipos de archivo permitidos, vea Tipos de
archivo permitidos enun archivo CAB de Ayuda actualizable .

3. Firme digitalmente los archivos de ayuda. Las firmas digitales no son necesarias,
pero son un procedimiento recomendado.

4. Incluya todos los archivos de ayuda para el módulo en la referencia cultural de la


interfaz de usuario, no solo los archivos nuevos o que han cambiado. Si el archivo
CAB está incompleto, los usuarios que descarguen archivos de ayuda por primera
vez o no descarguen cada actualización, no tendrán todos los archivos de ayuda
del módulo.

5. Use una utilidad que cree archivos archivadores, como MakeCab.exe . PowerShell
no incluye cmdlets que crean archivos CAB.
6. Asigne un nombre a los archivos CAB. Para obtener más información, vea Cómo
dar nombre a un archivo CAB de ayuda actualizable.

7. Upload los archivos CAB del módulo a la ubicación especificada por el elemento
HelpContentUri en el archivo XML HelpInfo del módulo. Después, cargue el
archivo XML HelpInfo en la ubicación especificada por la clave HelpInfoUri del
manifiesto del módulo. HelpContentUri y HelpInfoUri pueden apuntar a la misma
ubicación.

U Precaución

El valor de la clave HelpInfoUri y del elemento HelpContentUri debe comenzar


por http o https . El valor debe indicar una ubicación de Internet y no debe incluir
un nombre de archivo.
Cómo asignar un nombre a un archivo
CAB de Ayuda actualizable
Artículo • 25/09/2021

En este tema se explica el formato de nombre necesario para los archivos del archivador
de ayuda actualizable ( .CAB ).

Cómo asignar un nombre a un archivo CAB de


Ayuda actualizable
Un archivo de archivador actualizable ( .CAB ) debe tener un nombre con el formato
siguiente.

<ModuleName>_<ModuleGUID>_<UICulture>_HelpContent.cab

Los elementos del nombre son los siguientes.

<ModuleName> -Valor de la propiedad Name del objeto ModuleInfo que devuelve el

cmdlet Get-Module.
<ModuleGUID> : el valor de la clave GUID en el manifiesto del módulo.
<UICulture> : la referencia cultural de la interfaz de usuario de los archivos de

ayuda del archivo CAB. Este valor debe coincidir con el valor de uno de los
elementos UICulture del archivo XML HelpInfo del módulo.

Por ejemplo, si el nombre del módulo es "TestModule", el GUID del módulo es


9cabb9ad-f2ac-4914-a46b-bfc1bebf07f9 y la referencia cultural de la interfaz de usuario
es "en-US", el nombre del archivo CAB sería:

TestModule_9cabb9ad-f2ac-4914-a46b-bfc1bebf07f9_en-US_HelpContent.cab
Tipos de archivo permitidos en un
archivo CAB de Ayuda actualizable
Artículo • 26/09/2021

El contenido del archivo CAB sin comprimir está limitado a 1 GB de forma


predeterminada. Para omitir este límite, los usuarios tienen que usar el parámetro Force
de los cmdlets Update-Help y Save-Help.

Para garantizar la seguridad de los archivos de ayuda que se descargan de Internet, un


archivo CAB de Ayuda actualizable solo puede incluir los tipos de archivo que se
enumeran a continuación. El cmdlet Update-Help valida todos los archivos con los
esquemas del tema de ayuda. Si el cmdlet encuentra un archivo que no es válido o no
es un tipo permitido, no instala el archivo no válido y deja de instalar archivos desde cab
en el equipo Update-Help del usuario.

Temas de ayuda basados en XML para cmdlets.


Temas de ayuda basados en XML para scripts y funciones.
Temas de ayuda basados en XML para proveedores de PowerShell.
Temas de ayuda basados en texto, como Temas acerca de.

Update-Help comprueba el contenido de CAB cuando desempaquete el CAB. Si


encuentra tipos de archivo no compatibles en un archivo CAB de Ayuda actualizable,
genera un error de terminación y Update-Help detiene la operación. No instala ningún
archivo de ayuda desde cab, ni siquiera los de los tipos de archivo compatibles.
Cómo actualizar los archivos de Ayuda
Artículo • 25/09/2021

En este tema se explica cómo actualizar los archivos de ayuda de un módulo que admite
la Ayuda actualizable.

Actualizar archivos de Ayuda


Hay muchas razones para actualizar los archivos de ayuda, como corregir errores, aclarar
un concepto, responder a una pregunta frecuente, agregar nuevos archivos o agregar
ejemplos nuevos y mejores.

Para actualizar un archivo de ayuda:

1. Cambie los archivos.


2. Traducir los archivos a otras referencia culturales de la interfaz de usuario.
3. Recopile todos los archivos de ayuda (nuevos, modificados y sin cambios) para el
módulo en cada referencia cultural de la interfaz de usuario.
4. Valide los archivos con el esquema XML.
5. Recompile los archivos CAB para cada referencia cultural de la interfaz de usuario.
6. En el archivo HELPInfo XML, incremente los números de versión del archivo CAB
para cada referencia cultural de interfaz de usuario.
7. Upload los nuevos archivos CAB a la ubicación especificada por el valor del
elemento HelpContentUri en el archivo XML HelpInfo. Reemplace los archivos CAB
anteriores por los nuevos archivos CAB.
8. Upload el archivo XML HelpInfo actualizado a la ubicación especificada por la clave
HelpInfoUri en el manifiesto del módulo. Reemplace el archivo XML HelpInfo
anterior por el nuevo archivo.
Cómo probar la Ayuda actualizable
Artículo • 25/09/2021

En este tema se describen los enfoques para probar la Ayuda actualizable para un
módulo.

Uso detallado para detectar errores


Después de cargar el archivo XML HelpInfo y los archivos CAB del módulo, pruebe los
archivos mediante la ejecución de un comando Update-Help con el parámetro Verbose.
El parámetro Verbose dirige a notificar los pasos críticos en sus acciones, desde la
lectura de la clave Update-Help HelpInfoUri en el manifiesto del módulo hasta la
validación de los tipos de archivo en el archivo CAB desempaquetar y la colocación de
los archivos en el directorio del módulo específico del lenguaje.

Cuando se resuelvan todos los mensajes detallados, ejecute Update-Help un comando


con el parámetro Debug. Este parámetro debe detectar los problemas restantes con los
archivos de Ayuda actualizables.
Compatibilidad con la Ayuda en línea
Artículo • 25/09/2021

A partir de PowerShell 3.0, hay dos maneras de admitir la característica Get-Help En


línea para comandos de PowerShell. En este tema se explica cómo implementar esta
característica para diferentes tipos de comandos.

Acerca de la Ayuda en línea


La ayuda en línea siempre ha sido una parte fundamental de PowerShell. Aunque el
cmdlet muestra temas de ayuda en el símbolo del sistema, muchos usuarios prefieren la
experiencia de lectura en línea, incluida la codificación de colores, hipervínculos y el uso
compartido de ideas en contenido de Community y documentos basados en Get-Help
wikis. Lo más importante es que antes de la llegada de la Ayuda actualizable, la ayuda
en línea proporcionaba la versión más actualizada de los archivos de ayuda.

Con la llegada de la Ayuda actualizable en PowerShell 3.0, la ayuda en línea sigue


desempeñando un papel fundamental. Además de la experiencia de usuario flexible, la
ayuda en línea proporciona ayuda a los usuarios que no usan o no pueden usar la
Ayuda actualizable para descargar temas de ayuda.

Funcionamiento Get-Help -Online


Para ayudar a los usuarios a encontrar los temas de ayuda en línea de los comandos, el
comando tiene un parámetro Online que abre la versión en línea del tema de ayuda
para un comando en el explorador de Internet predeterminado Get-Help del usuario.

Por ejemplo, el comando siguiente abre el tema de ayuda en línea para el Invoke-
Command cmdlet .

PowerShell

Get-Help Invoke-Command -Online

Para implementar , el cmdlet busca un identificador uniforme de recursos (URI) para el


tema de ayuda de la versión en Get-Help -Online línea en las ubicaciones Get-Help
siguientes.

Primer vínculo de la sección Vínculos relacionados del tema de ayuda del


comando. El tema de ayuda debe instalarse en el equipo del usuario. Esta
característica se introdujo en PowerShell 2.0.

Propiedad HelpUri de cualquier comando. La propiedad HelpUri es accesible


incluso cuando el tema de ayuda del comando no está instalado en el equipo del
usuario. Esta característica se introdujo en PowerShell 3.0.

Get-Help busca un URI en la primera entrada de la sección Vínculos relacionados

antes de obtener el valor de la propiedad HelpUri. Si el valor de la propiedad es


incorrecto o ha cambiado, puede invalidarlo si escribe otro valor en el primer
vínculo relacionado. Sin embargo, el primer vínculo relacionado solo funciona
cuando los temas de ayuda están instalados en el equipo del usuario.

Agregar un URI al primer vínculo relacionado


de un tema de ayuda de comandos
Puede admitir cualquier comando agregando un URI válido a la primera entrada de la
sección Vínculos relacionados del tema de ayuda basado Get-Help -Online en XML para
el comando. Esta opción solo es válida en los temas de ayuda basados en XML y solo
funciona cuando el tema de ayuda está instalado en el equipo del usuario. Cuando se
instala el tema de ayuda y se rellena el URI, este valor tiene prioridad sobre la
propiedad HelpUri del comando.

Para admitir esta característica, el URI debe aparecer en el maml:uri elemento bajo el
primer elemento del elemento maml:relatedLinks/maml:navigationLink
maml:relatedLinks .

En el xml siguiente se muestra la ubicación correcta del URI. El Online version: texto
del elemento es un procedimiento maml:linkText recomendado, pero no es necesario.

XML

<maml:relatedLinks>
<maml:navigationLink>
<maml:linkText>Online version:</maml:linkText>
<maml:uri>https://go.microsoft.com/fwlink/?LinkID=113279</maml:uri>
</maml:navigationLink>
<maml:navigationLink>
<maml:linkText>about_History</maml:linkText>
<maml:uri/>
</maml:navigationLink>
</maml:relatedLinks>
Agregar la propiedad HelpUri a un comando
En esta sección se muestra cómo agregar la propiedad HelpUri a comandos de distintos
tipos.

Agregar una propiedad HelpUri a un cmdlet


Para los cmdlets escritos en C#, agregue un atributo HelpUri a la clase Cmdlet. El valor
del atributo debe ser un URI que comience por http o https .

El código siguiente muestra el atributo HelpUri de la Get-History clase de cmdlet.

C#

[Cmdlet(VerbsCommon.Get, "History", HelpUri =


"https://go.microsoft.com/fwlink/?LinkID=001122")]

Agregar una propiedad HelpUri a una función avanzada


Para las funciones avanzadas, agregue una propiedad HelpUri al atributo
CmdletBinding. El valor de la propiedad debe ser un URI que comience por "http" o
"https".

En el código siguiente se muestra el atributo HelpUri de la New-Calendar función.

PowerShell

function New-Calendar {
[CmdletBinding(SupportsShouldProcess=$true,
HelpURI="https://go.microsoft.com/fwlink/?LinkID=01122")]

Agregar un atributo HelpUri a un comando CIM


Para los comandos CIM, agregue un atributo HelpUri al elemento CmdletMetadata en
el archivo CDXML. El valor del atributo debe ser un URI que comience por http o https
.

En el código siguiente se muestra el atributo HelpUri del Start-Debug comando CIM.

XML

<CmdletMetadata Verb="Debug" HelpUri="https://go.microsoft.com/fwlink/?


LinkID=001122"/>
Agregar un atributo HelpUri a un flujo de trabajo
Para los flujos de trabajo escritos en el lenguaje de PowerShell, agregue . Directiva de
comentario ExternalHelp para el código de flujo de trabajo. El valor de la directiva debe
ser un URI que comience por http o https .

7 Nota

La propiedad HelpUri no se admite para flujos de trabajo basados en XAML en


PowerShell.

En el código siguiente se muestra . Directiva ExternalHelp en un archivo de flujo de


trabajo.

PowerShell

# .ExternalHelp "https://go.microsoft.com/fwlink/?LinkID=138338"
Cómo agregar parámetros dinámicos a
un tema de Ayuda de proveedor
Artículo • 26/09/2021

En esta sección se explica cómo rellenar la sección PARÁMETROS DINÁMICOs de un


tema de ayuda del proveedor.

Los parámetros dinámicos son parámetros de un cmdlet o una función que solo están
disponibles en condiciones especificadas.

Los parámetros dinámicos que se documentan en un tema de ayuda del proveedor son
los parámetros dinámicos que el proveedor agrega al cmdlet o función cuando se usa el
cmdlet o la función en la unidad del proveedor.

Los parámetros dinámicos también se pueden documentar en la ayuda del cmdlet


personalizado para un proveedor. Al escribir ayuda del proveedor y ayuda de cmdlet
personalizado para un proveedor, incluya la documentación de parámetros dinámicos
en ambos documentos.

Si un proveedor no implementa ningún parámetro dinámico, el tema de ayuda del


proveedor contiene un elemento DynamicParameters vacío.

Para agregar parámetros dinámicos


1. En el <AssemblyName>.dll-help.xml archivo , dentro del elemento , agregue un
elemento providerHelp DynamicParameters . El DynamicParameters elemento debe
aparecer después del elemento y antes del elemento Tasks RelatedLinks .

Por ejemplo:

XML

<providerHelp>
<Tasks>
</Tasks>
<DynamicParameters>
</DynamicParameters>
<RelatedLinks>
</RelatedLinks>
</providerHelp>
Si el proveedor no implementa ningún parámetro dinámico, DynamicParameters el
elemento puede estar vacío.

2. Dentro del DynamicParameters elemento , para cada parámetro dinámico, agregue


un elemento DynamicParameter .

Por ejemplo:

XML

<DynamicParameters/>
<DynamicParameter>
</DynamicParameter>
</DynamicParameters>

3. En cada DynamicParameter elemento, agregue un Name elemento y


CmdletSupported .

Nombre: especifica el nombre del parámetro.


CmdletSupported: especifica los cmdlets en los que el parámetro es válido.
Escriba una lista separada por comas de nombres de cmdlet.

Por ejemplo, el siguiente xml documenta el parámetro dinámico que el proveedor


Windows PowerShell FileSystem agrega a Encoding Add-Content los Get-Content
cmdlets , Set-Content y .

XML

<DynamicParameters/>
<DynamicParameter>
<Name> Encoding </Name>
<CmdletSupported> Add-Content, Get-Content, Set-Content
</CmdletSupported>
</DynamicParameters>

4. En cada DynamicParameter elemento, agregue un Type elemento . El Type


elemento es un contenedor para el elemento que contiene el tipo Name .NET del
valor del parámetro dinámico.

Por ejemplo, el siguiente XML muestra que el tipo .NET del parámetro dinámico es
la Encoding enumeración FileSystemCmdletProviderEncoding.

XML
<DynamicParameters/>
<DynamicParameter>
<Name> Encoding </Name>
<CmdletSupported> Add-Content, Get-Content, Set-Content
</CmdletSupported>
<Type>
<Name>
Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding </Name>
<Type>
...
</DynamicParameters>

5. Agregue el Description elemento , que contiene una breve descripción del


parámetro dinámico. Al crear la descripción, use las instrucciones prescritas para
todos los parámetros de cmdlet en How to Add Parameter Information.

Por ejemplo, el siguiente XML incluye la descripción del Encoding parámetro


dinámico.

XML

<DynamicParameters/>
<DynamicParameter>
<Name> Encoding </Name>
<CmdletSupported> Add-Content, Get-Content, Set-Content
</CmdletSupported>
<Type>
<Name>
Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding </Name>
<Type>
<Description> Specifies the encoding of the output file that
contains the content. </Description>
...
</DynamicParameters>

6. Agregue el PossibleValues elemento y sus elementos secundarios. Juntos, estos


elementos describen los valores del parámetro dinámico. Este elemento está
diseñado para valores enumerados. Si el parámetro dinámico no toma un valor,
como es el caso de un parámetro switch o no se pueden enumerar los valores,
agregue un elemento PossibleValues vacío.

En la tabla siguiente se enumeran y describen el PossibleValues elemento y sus


elementos secundarios.

PossibleValues: este elemento es un contenedor. A continuación se describen


sus elementos secundarios. Agregue un PossibleValues elemento a cada
tema de ayuda del proveedor. El elemento puede estar vacío.
PossibleValue: este elemento es un contenedor. A continuación se describen
sus elementos secundarios. Agregue un PossibleValue elemento para cada
valor del parámetro dinámico.
Valor: especifica el nombre del valor.
Descripción: este elemento contiene un Para elemento . El texto del Para
elemento describe el valor que se denomina en el elemento Value .

Por ejemplo, el siguiente XML muestra un PossibleValue elemento del Encoding


parámetro dinámico.

XML

<DynamicParameters/>
<DynamicParameter>
...
<Description> Specifies the encoding of the output file that
contains the content. </Description>
<PossibleValues>
<PossibleValue>
<Value> ASCII </Value>
<Description>
<para> Uses the encoding for the ASCII (7-bit)
character set. </para>
</Description>
</PossibleValue>
...
</PossibleValues>
</DynamicParameters>

Ejemplo
En el ejemplo siguiente se muestra DynamicParameters el elemento del parámetro
Encoding dinámico.

XML

<DynamicParameters/>
<DynamicParameter>
<Name> Encoding </Name>
<CmdletSupported> Add-Content, Get-Content, Set-Content
</CmdletSupported>
<Type>
<Name>
Microsoft.PowerShell.Commands.FileSystemCmdletProviderEncoding </Name>
<Type>
<Description> Specifies the encoding of the output file that
contains the content. </Description>
<PossibleValues>
<PossibleValue>
<Value> ASCII </Value>
<Description>
<para> Uses the encoding for the ASCII (7-bit) character
set. </para>
</Description>
</PossibleValue>
<PossibleValue>
<Value> Unicode </Value>
<Description>
<para> Encodes in UTF-16 format using the little-endian
byte order. </para>
</Description>
</PossibleValue>
</PossibleValues>
</DynamicParameters>
Cómo agregar una sección Consulte
también a un tema de Ayuda de
proveedor
Artículo • 26/09/2021

En esta sección se explica cómo rellenar la sección SEE ALSO de un tema de ayuda del
proveedor.

La sección VER TAMBIÉN consta de una lista de temas relacionados con el proveedor o
que pueden ayudar al usuario a comprender y usar mejor el proveedor. La lista de temas
puede incluir ayuda de cmdlets, ayuda del proveedor y temas de ayuda conceptuales
("acerca de") en Windows PowerShell. También puede incluir referencias a libros,
artículos y temas en línea, incluida una versión en línea del tema de ayuda del
proveedor actual.

Cuando haga referencia a temas en línea, proporcione el URI o un término de búsqueda


en texto sin formato. El Get-Help cmdlet no vincula ni redirige a ninguno de los temas
de la lista. Además, el Online parámetro del cmdlet no funciona con la ayuda del Get-
Help proveedor.

La sección Ver también se crea a partir del elemento y las RelatedLinks etiquetas que
contiene. En el siguiente XML se muestra cómo agregar las etiquetas.

Para agregar temas DE VER TAMBIÉN


1. En el <AssemblyName>.dll-help.xml archivo , dentro del elemento , agregue un
elemento providerHelp RelatedLinks . El RelatedLinks elemento debe ser el
último elemento del elemento providerHelp . Solo se RelatedLinks permite un
elemento en cada tema de ayuda del proveedor.

Por ejemplo:

XML

<providerHelp>
<RelatedLinks>
</RelatedLinks>
</providerHelp>
2. Para cada tema de la sección VEA TAMBIÉN, en RelatedLinks el elemento ,
agregue un elemento navigationLink . A continuación, navigationLink dentro de
cada elemento, agregue un elemento linkText y un uri elemento. Si no usa el
elemento uri , puede agregarlo como un elemento vacío ( <uri/> ).

Por ejemplo:

XML

<providerHelp>
<RelatedLinks>
<navigationLink>
<linkText> </linkText>
<uri> </uri>
</navigationLink>
</RelatedLinks>
</providerHelp>

3. Escriba el nombre del tema entre las linkText etiquetas. Si va a proporcionar un


URI, escriba entre las uri etiquetas. Para indicar la versión en línea del tema de
ayuda del proveedor actual, entre las linkText etiquetas, escriba "Versión en
línea:" en lugar del nombre del tema. Normalmente, el vínculo "Versión en línea:"
es el primer tema de la lista DE TEMAS VER TAMBIÉN.

En el ejemplo siguiente se incluyen tres temas DE VER TAMBIÉN. La primera hace


referencia a la versión en línea del tema actual. El segundo hace referencia a un
tema Windows PowerShell ayuda del cmdlet. El tercero hace referencia a otro tema
en línea.

XML

<providerHelp>
<RelatedLinks>
<navigationLink>
<linkText> Online version: </linkText>
<uri>http://www.fabrikam.com/help/myFunction.htm</uri>
</navigationLink>
<navigationLink>
<linkText> about_functions </linkText>
<uri/>
</navigationLink>
<navigationLink>
<linkText> Windows PowerShell Getting Started Guide
</linkText>
<uri>https://go.microsoft.com/fwlink/?LinkID=89597<uri/>
</navigationLink>
</RelatedLinks>
</providerHelp>
Introducción al sistema de tipos
extendidos
Artículo • 24/09/2021

PowerShell usa su objeto PSObject para ampliar los tipos de objetos de dos maneras.
En primer lugar, el objeto PSObject proporciona una manera de mostrar diferentes
vistas de tipos de objetos específicos. Esto se conoce como la visualización de una vista
adaptada de un objeto. En segundo lugar, el objeto PSObject proporciona una manera
de agregar miembros al objeto existente. Juntos, al encapsular un objeto existente,
denominado objeto base, el objeto PSObject proporciona un sistema de tipos
extendido (ETS) que los desarrolladores de scripts y cmdlets pueden usar para
manipular objetos .NET dentro del shell.

Problemas de desarrollo de cmdlets y scripts


ETS resuelve dos problemas fundamentales:

En primer lugar, algunos objetos .NET no tienen el comportamiento predeterminado


necesario para actuar como los datos entre cmdlets.

Algunos objetos .NET son objetos "meta" (por ejemplo, objetos WMI, objetos ADO
y objetos XML) cuyos miembros describen los datos que contienen. Sin embargo,
en un entorno de scripting son los datos contenidos los más interesantes, no la
descripción de los datos contenidos. ETS resuelve este problema mediante la
introducción de la noción de adaptadores que adaptan el objeto subyacente de
.NET para que tenga la semántica predeterminada esperada.
Algunos miembros del objeto .NET tienen un nombre incoherente, proporcionan
un conjunto insuficiente de miembros públicos o proporcionan una funcionalidad
insuficiente. ETS resuelve este problema mediante la introducción de la capacidad
de ampliar el objeto de .NET con miembros adicionales.

En segundo lugar, el lenguaje de scripting de PowerShell no tiene tipo, ya que no es


necesario declarar una variable de un tipo determinado. Es decir, las variables que crea
un desarrollador de scripts son por naturaleza sin tipo. Sin embargo, el sistema de
PowerShell está "controlado por tipos", ya que depende de tener un nombre de tipo
con el que trabajar para operaciones básicas, como la salida de resultados o la
ordenación.

Por lo tanto, un desarrollador de scripts debe tener la capacidad de establecer el tipo de


una de sus variables y crear su propio conjunto de "objetos" con tipo dinámico que
contienen propiedades y métodos y pueden participar en el sistema controlado por
tipos. ETS resuelve este problema proporcionando un objeto común para el lenguaje de
scripting que tiene la capacidad de establecer su tipo dinámicamente y agregar
miembros dinámicamente.

Fundamentalmente, ETS resuelve el problema mencionado anteriormente


proporcionando el objeto PSObject, que actúa como base de todo el acceso a objetos
desde el lenguaje de scripting y proporciona una abstracción estándar para el
desarrollador de cmdlets.

Desarrolladores de cmdlets
Para los desarrolladores de cmdlets, ETS proporciona la siguiente compatibilidad:

Abstracciones para trabajar con objetos de forma genérica mediante el objeto


PSObject. ETS también proporciona la capacidad de explorar en profundidad estas
abstracciones si es necesario.
Mecanismos para crear un comportamiento predeterminado para aplicar formato,
ordenación, serialización y otras manipulaciones del sistema de su tipo de objeto
mediante un conjunto conocido de miembros extendidos.
El medio para operar con cualquier objeto utilizando la misma semántica que el
lenguaje de script mediante un objeto LanguagePrimitives.
Significa "escribir" dinámicamente una tabla hash para que el resto del sistema
pueda operar con ella de forma eficaz.

Desarrolladores de scripts
Para los desarrolladores de scripts, ETS proporciona la siguiente compatibilidad:

La capacidad de hacer referencia a cualquier tipo de objeto subyacente con la


misma sintaxis ( $a.x ).
La capacidad de acceder más allá de la abstracción proporcionada por el objeto
PSObject (por ejemplo, acceder solo a miembros adaptados o acceder al propio
objeto base).
La capacidad de definir miembros conocidos que controlan el formato, la
ordenación, la serialización y otras manipulaciones de una instancia o tipo de
objeto.
el medio para dar nombre a un objeto como un tipo específico y, por tanto,
controlar la herencia de sus miembros basados en tipos.
La capacidad de agregar, quitar y modificar miembros extendidos.
La capacidad de manipular el propio objeto PSObject si es necesario.
La clase PSObject
El objeto PSObject es la base de todo el acceso a objetos desde el lenguaje de scripting
y proporciona una abstracción estándar para el desarrollador del cmdlet. Contiene un
objeto base (un objeto .NET) y cualquier miembro de instancia (miembros,
específicamente miembros extendidos, que están presentes en una instancia de objeto
determinada, pero no necesariamente en otros objetos del mismo tipo). Según el tipo
del objeto base, el objeto PSObject también podría proporcionar acceso implícito y
explícito a los miembros adaptados, así como a cualquier miembro extendido basado en
tipos.

El objeto PSObject proporciona los siguientes mecanismos:

La capacidad de construir un PSObject con o sin un objeto base.


La capacidad de acceder a todos los miembros de cada objeto PSObject
construido a través de un algoritmo de búsqueda común y la capacidad de
invalidar ese algoritmo cuando sea necesario.
La capacidad de obtener y establecer los nombres de tipo de los objetos PSObject
construidos para que los scripts y cmdlets puedan hacer referencia a objetos
PSObject similares por el mismo nombre de tipo, independientemente del tipo de
su objeto base.

Cómo construir un PSObject


En la lista siguiente se describen maneras de crear un objeto PSObject:

Al llamar al constructor .#ctor PSObject se crea un nuevo objeto PSObject con un


objeto base de PSCustomObject. Un objeto base de este tipo indica que el objeto
PSObject no tiene ningún objeto base significativo. Sin embargo, un objeto
PSObject con este tipo de objeto base proporciona un bolsa de propiedades que
los desarrolladores de cmdlets pueden encontrar útil mediante la adición de
miembros extendidos.

Los desarrolladores también pueden especificar el nombre de tipo de objeto, lo que


permite que este objeto comparta sus miembros extendidos con otros objetos PSObject
del mismo nombre de tipo.

Al llamar al constructor .#ctor(System.Object) de PSObject, se crea un nuevo


objeto PSObject con un objeto base de tipo System.Object.

En este caso, el nombre de tipo del objeto creado es una colección de la jerarquía
de derivación del objeto base. Por ejemplo, el nombre de tipo para el PSObject
que contiene un objeto base ProcessInfo incluiría los nombres siguientes:
System.Diagnostics.Process
System.ComponentModel.Component
System.MarshalByRefObject
System.Object

Llamar a PSObject . El método AsPSObject(System.Object) crea un nuevo objeto


PSObject basado en un objeto proporcionado.

Si el objeto proporcionado es de tipo System.Object, el objeto proporcionado se


usa como objeto base para el nuevo objeto PSObject. Si el objeto proporcionado
ya es un objeto PSObject, el objeto proporcionado se devuelve tal y como está.

Miembros base, adaptados y extendidos


Conceptualmente, ETS usa los términos siguientes para mostrar la relación entre los
miembros originales del objeto base y los miembros agregados por PowerShell. Para
obtener más información sobre los tipos específicos de miembros que usa el objeto
PSObject, vea Clase PSObject.

Miembros de objeto base


Si se especifica el objeto base al construir los objetos PSObject, los miembros del objeto
base estarán disponibles a través de la propiedad Members.

Miembros adaptados

Cuando un objeto base es un metaobjeto, que contiene datos de forma genérica cuyas
propiedades "describen" sus datos contenidos, ETS adapta esos objetos a una vista que
permite el acceso directo a los datos a través de miembros adaptados del objeto
PSObject. Se accede a los miembros adaptados y a los miembros de objeto base a
través de la propiedad Members.

Miembros extendidos
Además de los miembros disponibles desde el objeto base o los miembros adaptados
creados por PowerShell, un PSObject también puede definir miembros extendidos que
extienden el objeto base original con información adicional que es útil en el entorno de
scripting.

Por ejemplo, todos los cmdlets principales proporcionados por PowerShell, como los
cmdlets Get-Content y Set-Content, toman un parámetro path. Para asegurarse de que
estos cmdlets, y otros, pueden funcionar con objetos de tipos diferentes, se puede
agregar un miembro Path a esos objetos para que todos den su información de una
manera común. Este miembro path extendido garantiza que los cmdlets pueden
funcionar con todos esos tipos, aunque es posible que la clase base no tenga un
miembro Path.

Se accede a los miembros extendidos, a los miembros adaptados y a los miembros de


objeto base a través de la propiedad Members.
Miembros de clase del sistema de tipos
extendidos
Artículo • 24/09/2021

ETS hace referencia a una serie de tipos diferentes de miembros cuyos tipos se definen
mediante la enumeración PSMemberTypes. Estos tipos de miembros incluyen
propiedades, métodos, miembros y conjuntos de miembros definidos por su propio tipo
CLR. Por ejemplo, NoteProperty se define mediante su propio tipo PSNoteProperty.
Estos tipos CLR individuales tienen sus propias propiedades únicas y propiedades
comunes que se heredan de la clase PSMemberInfo.

La clase PSMemberInfo
La clase PSMemberInfo actúa como una clase base para todos los tipos de miembro
ets. Esta clase proporciona las siguientes propiedades base a todos los tipos clr de
miembro.

Propiedad Name: el nombre del miembro. Este nombre se puede definir mediante
el objeto base o mediante PowerShell cuando se exponen miembros adaptados o
miembros extendidos.
Propiedad Value: valor devuelto por el miembro determinado. Cada tipo de
miembro define cómo controla su valor de miembro.
Propiedad TypeNameOfValue: es el nombre del tipo CLR del valor devuelto por la
propiedad Value.

Acceso a miembros
Se puede acceder a las colecciones de miembros a través de las propiedades Members,
Methods y Properties del objeto PSObject.

Propiedades de ETS
Las propiedades ets son miembros que se pueden tratar como una propiedad.
Básicamente, pueden aparecer en el lado izquierdo de una expresión. Incluyen
propiedades de alias, propiedades de código, propiedades de PowerShell, propiedades
de nota y propiedades de script. Para obtener más información sobre estos tipos de
propiedades, vea Propiedades de ETS.
Métodos de ETS
Los métodos ETS son miembros que pueden tomar argumentos, pueden devolver
resultados y no pueden aparecer en el lado izquierdo de una expresión. Incluyen
métodos de código, métodos de PowerShell y métodos de script. Para obtener más
información sobre estos tipos de métodos, vea Métodos ETS.
Conjuntos de miembros de ETS
Artículo • 24/09/2021

Los conjuntos de miembros permiten particionar los miembros del objeto PSObject en
dos subconjuntos para que se pueda hacer referencia a los miembros de los
subconjuntos juntos por su nombre de subconjunto. Los dos tipos de subconjuntos
incluyen conjuntos de propiedades y conjuntos de miembros. Por ejemplo, de cómo
PowerShell usa conjuntos de miembros, hay un conjunto de propiedades específico
denominado DefaultDisplayPropertySet que se usa para determinar, en tiempo de
ejecución, qué propiedades se mostrarán para un objeto PSObject determinado.

Conjuntos de propiedades
Los conjuntos de propiedades pueden incluir cualquier número de propiedades de un
tipo PSObject. En general, se puede usar un conjunto de propiedades siempre que se
necesite una colección de propiedades (del mismo tipo). El conjunto de propiedades se
crea llamando al constructor con el nombre del conjunto de
PSPropertySet(System.String,System.Collections.Generic.IEnumerable{System.String})
propiedades y los nombres de las propiedades a las que se hace referencia. El objeto
PSPropertySet creado se puede usar como alias que apunta a las propiedades del
conjunto. La clase PSPropertySet tiene las siguientes propiedades y métodos.

Propiedad IsInstance: obtiene un valor booleano que indica el origen de la


propiedad.
Propiedad MemberType: obtiene el tipo de propiedades del conjunto de
propiedades.
Propiedad Name: obtiene el nombre del conjunto de propiedades.
Propiedad ReferencedPropertyNames: obtiene los nombres de las propiedades
del conjunto de propiedades.
Propiedad TypeNameOfValue: obtiene una constante de enumeración
PropertySet que define este conjunto como un conjunto de propiedades.
Propiedad Value: obtiene o establece el objeto PSPropertySet.
PSPropertySet.Copy method: realiza una copia exacta del objeto PSPropertySet.

PSMemberSet.ToString method: convierte el objeto PSPropertySet en una cadena.

Conjuntos de miembros
Los conjuntos de miembros pueden incluir cualquier número de miembros extendidos
de cualquier tipo. El conjunto de miembros se crea mediante una llamada a
PSMemberSet(System.String,System.Collections.Generic.IEnumerable{System.Management.

Automation.PSMemberInfo}) constructor con el nombre del conjunto de miembros y los


nombres de los miembros a los que se hace referencia. A continuación, el objeto
PSPropertySet creado se puede usar como alias que apunta a los miembros del
conjunto. La clase PSMemberSet tiene las siguientes propiedades y métodos.

Propiedad IsInstance: obtiene un valor booleano que indica el origen del


miembro.
Propiedad Members: obtiene todos los miembros del conjunto de miembros.
Propiedad MemberType: obtiene una constante de enumeración MemberSet que
define este conjunto como un conjunto de miembros.
Propiedad Methods: obtiene los métodos incluidos en el conjunto de miembros.
Propiedad Properties: obtiene las propiedades incluidas en el conjunto de
miembros.
Propiedad TypeNameOfValue: obtiene una constante de enumeración
MemberSet que define este conjunto como un conjunto de miembros.
Propiedad Value: obtiene el objeto PSMemberSet.
PSMemberSet.Copy method: realiza una copia exacta del objeto PSMemberSet.
PSMemberSet.ToString method: convierte el objeto PSMemberSet en una cadena.
Propiedades de ETS
Artículo • 24/09/2021

Las propiedades son miembros que se pueden tratar como una propiedad. Básicamente,
pueden aparecer en el lado izquierdo de una expresión. Las propiedades que están
disponibles incluyen propiedades de alias, código, nota y script.

Propiedad alias
Una propiedad de alias es una propiedad que hace referencia a otra propiedad que
contiene el objeto PSObject. Se usa principalmente para cambiar el nombre de la
propiedad a la que se hace referencia. Sin embargo, también se puede usar para
convertir el valor de la propiedad a la que se hace referencia en otro tipo. Con respecto
a ETS, este tipo de propiedad siempre es un miembro extendido y se define mediante la
clase PSAliasProperty. La clase incluye las siguientes propiedades.

Propiedad ConversionType: tipo CLR utilizado para convertir el valor del miembro
al que se hace referencia.
Propiedad IsGettable: indica si se puede recuperar el valor de la propiedad a la
que se hace referencia. Esta propiedad se determina dinámicamente mediante el
examen de la propiedad IsGettable de la propiedad a la que se hace referencia.
Propiedad IsSettable: indica si se puede establecer el valor de la propiedad a la
que se hace referencia. Esta propiedad se determina dinámicamente mediante el
examen de la propiedad IsSettable de la propiedad a la que se hace referencia.
Propiedad MemberType: constante de enumeración AliasProperty que define
esta propiedad como una propiedad de alias.
Propiedad ReferencedMemberName: nombre de la propiedad a la que hace
referencia este alias.
Propiedad TypeNameOfValue: nombre completo del tipo CLR del valor de la
propiedad a la que se hace referencia.
Propiedad Value: el valor de la propiedad a la que se hace referencia.

Propiedad Code
Una propiedad de código es una propiedad que es un getter y un setter que se define
en un lenguaje CLR. Para que una propiedad de código esté disponible, un desarrollador
debe escribir la propiedad en algún lenguaje CLR, compilar y enviar el ensamblado
resultante. Este ensamblado debe estar disponible en el espacio de ejecución donde se
desea la propiedad de código. Con respecto a ETS, este tipo de propiedad siempre es
un miembro extendido y se define mediante la clase PSCodeProperty. La clase incluye
las siguientes propiedades.

Propiedad GetterCodeReference: método utilizado para obtener el valor de la


propiedad code.
Propiedad IsGettable: indica si se puede recuperar el valor de la propiedad code,
que la propiedad SetterCodeReference: el método utilizado para establecer el
valor de la propiedad code.
Propiedad IsSettable: indica si se puede establecer el valor de la propiedad code,
que la propiedad SetterCodeReference no es NULL.
Propiedad MemberType: constante de enumeración CodeProperty que define
esta propiedad como una propiedad de código.
Propiedad SetterCodeReference: método que se usa para obtener el valor de la
propiedad code.
Propiedad TypeNameOfValue: tipo CLR del valor de propiedad de código
devuelto por la operación get de propiedades.
Propiedad Value: el valor de la propiedad de código. Cuando se recupera esta
propiedad, se invoca el código de getter de la propiedad GetterCodeReference,
pasando el objeto PSObject actual y devolviendo el valor devuelto por la
invocación. Cuando se establece esta propiedad, se invoca el código establecedor
de la propiedad SetterCodeReference, pasando el objeto PSObject actual como
primer argumento y el objeto utilizado para establecer el valor como segundo
argumento.

Nota(Propiedad)
Una propiedad Note es una propiedad que tiene un emparejamiento nombre-valor. Con
respecto a ETS, este tipo de propiedad siempre es un miembro extendido y se define
mediante la clase PSNoteProperty. La clase incluye las siguientes propiedades.

Propiedad IsGettable: indica si se puede recuperar el valor de la propiedad note.


Propiedad IsSettable: indica si se puede establecer el valor de la propiedad note.
Propiedad MemberType: constante de enumeración NoteProperty que define
esta propiedad como una propiedad de nota.
Propiedad TypeNameOfValue: nombre de tipo completo del objeto devuelto por
la operación get de la propiedad note.
Valor: el valor de la propiedad note.

Propiedad de PowerShell
Una propiedad de PowerShell es una propiedad definida en el objeto base o una
propiedad que está disponible a través de un adaptador. Puede hacer referencia tanto a
los campos CLR como a las propiedades de CLR. Con respecto a ETS, este tipo de
propiedad puede ser un miembro base o un miembro de adaptador y se define
mediante la clase PSProperty. La clase incluye las siguientes propiedades.

Propiedad IsGettable: indica si se puede recuperar el valor de la propiedad base o


adaptada.
Propiedad IsSettable: indica si se puede establecer el valor de la propiedad base o
adaptada.
Propiedad MemberType: constante de enumeración Property que define esta
propiedad como una propiedad de PowerShell.
Propiedad TypeNameOfValue: nombre completo del tipo de valor de propiedad.
Por ejemplo, para una propiedad cuyo valor es una cadena, su tipo de valor de
propiedad es System.String.
Propiedad Value: el valor de la propiedad. Si se llama a la operación get o set en
una propiedad que no admite esa operación, se produce una excepción
GetValueException o SetValueException.

Propiedad Script de PowerShell


Una propiedad Script es una propiedad que tiene scripts de getter y setter. Con
respecto a ETS, este tipo de propiedad siempre es un miembro extendido y se define
mediante la clase PSScriptProperty. La clase incluye las siguientes propiedades.

Propiedad GetterScript: script que se usa para recuperar el valor de la propiedad


de script.
Propiedad IsGettable: indica si la propiedad GetterScript expone un bloque de
script.
Propiedad IsSettable: indica si la propiedad SetterScript expone un bloque de
script.
Propiedad MemberType: constante de enumeración ScriptProperty que identifica
esta propiedad como una propiedad de script.
Propiedad SetterScript: script que se usa para establecer el valor de la propiedad
script.
Propiedad TypeNameOfValue: nombre de tipo completo del objeto devuelto por
el script de getter. En este caso, siempre se devuelve System.Object.
Propiedad Value: el valor de la propiedad de script. Get invoca el script de getter y
devuelve el valor proporcionado. Un conjunto invoca el script de establecedor.
Métodos de clase ETS
Artículo • 24/09/2021

Los métodos ETS son miembros que pueden tomar argumentos, pueden devolver
resultados y no pueden aparecer en el lado izquierdo de una expresión. Los métodos
que están disponibles en ETS incluyen código, Windows PowerShell y métodos de script.

7 Nota

Desde scripts, se accede a los métodos con la misma sintaxis que otros miembros
con la adición de paréntesis al final del nombre del método.

Métodos de código
Un método de código es un miembro extendido que se define en un lenguaje CLR.
Proporciona una funcionalidad similar a un método definido en un objeto base; sin
embargo, un método de código se puede agregar dinámicamente a un objeto
PSObject. Para que un método de código esté disponible, un desarrollador debe escribir
la propiedad en algún lenguaje CLR, compilar y enviar el ensamblado resultante. Este
ensamblado debe estar disponible en el espacio de ejecución donde se desea el
método de código. Tenga en cuenta que una implementación de método de código
debe ser segura para subprocesos. El acceso a estos métodos se realiza a través de
objetos PSCodeMethod que proporcionan los siguientes métodos y propiedades
públicos.

PSCodeMethod.Copy method: realiza una copia exacta del objeto PSCodeMethod.


PSCodeMethod.Invoke(System.Object[]) method: invoca el método de código

subyacente.
PSCodeMethod.ToString method: convierte el objeto PSCodeMethod en una

cadena.
PSCodeMethod.CodeReference property: obtiene el método subyacente en el que se
basa el método de código.
Propiedad PSMemberInfo.IsInstance: obtiene un valor booleano que indica el
origen del miembro.
Propiedad PSCodeMethod.MemberType: obtiene una constante de enumeración
PSMemberTypes.CodeMethod que identifica este método como un método de
código.
PSMemberInfo.Name propiedad: obtiene el nombre del método de código
subyacente.
Propiedad PSCodeMethod.OverloadDefinitions: obtiene una definición de todas
las sobrecargas del método de código subyacente.
Propiedad PSCodeMethod.TypeNameOfValue: obtiene el nombre completo del
método de código.
Propiedad PSMemberInfo.Value: obtiene el objeto PSCodeMethod.

Windows PowerShell Métodos


Un método de PowerShell es un método CLR definido en el objeto base o accesible a
través de un adaptador. El acceso a estos métodos se realiza a través de objetos
PSMethod que proporcionan los siguientes métodos y propiedades públicos.

PSMethod.Copy method: realiza una copia exacta del objeto PSMethod.

PSMethod.Invoke(System.Object[]) method: invoca el método subyacente.


PSMethod.ToString method: convierte el objeto PSMethod en una cadena.

Propiedad PSMemberInfo.IsInstance: obtiene un valor booleano que indica el


origen del miembro.
Propiedad PSMethod.MemberType: obtiene una constante de enumeración
PSMemberTypes.Method que identifica este método como un método de
PowerShell.
PSMemberInfo.Name propiedad: obtiene el nombre del método subyacente.
Propiedad PSMethod.OverloadDefinitions: obtiene las definiciones de todas las
sobrecargas del método subyacente.
Propiedad PSMethod.TypeNameOfValue: obtiene el tipo ETS de este método.
Propiedad PSMemberInfo.Value: obtiene el objeto PSMethod.

Métodos de script
Un método de script es un miembro extendido que se define en el lenguaje de
PowerShell. Proporciona una funcionalidad similar a un método definido en un objeto
base; sin embargo, un método de script se puede agregar dinámicamente a un objeto
PSObject. El acceso a estos métodos se realiza a través de objetos PSScriptMethod que
proporcionan los siguientes métodos y propiedades públicos.

PSScriptMethod.Copy method: realiza una copia exacta del objeto PSScriptMethod.

PSScriptMethod.Invoke(System.Object[]) method: invoca el método de script

subyacente.
PSScriptMethod.ToString method: convierte el objeto PSScriptMethod en una

cadena.
Propiedad PSMemberInfo.IsInstance: obtiene un valor booleano que indica el
origen del miembro.
Propiedad PSScriptMethod.MemberType: obtiene una constante de enumeración
PSMemberTypes.ScriptMethod que identifica este método como un método de
script.
PSMemberInfo.Name propiedad: obtiene el nombre del método de código
subyacente.
Propiedad PSScriptMethod.OverloadDefinitions: obtiene las definiciones de todas
las sobrecargas del método de script subyacente.
Propiedad PSScriptMethod.TypeNameOfValue: obtiene el tipo ETS de este
método.
Propiedad PSScriptMethod.Script: obtiene el script utilizado para invocar el
método .
Propiedad PSMemberInfo.Value: obtiene el objeto PSScriptMethod.
Convertidores de tipos de ETS
Artículo • 24/09/2021

ETS usa dos tipos básicos de convertidores de tipos cuando se realiza una llamada al
LanguagePrimitives.ConvertTo(System.Object, System.Type) método . Cuando se llama

a este método, PowerShell intenta realizar la conversión de tipos mediante sus


convertidores de lenguaje estándar de PowerShell o un convertidor personalizado. Si
PowerShell no puede realizar la conversión, produce una excepción
PSInvalidCastException.

Convertidores de Windows PowerShell


estándar
Estas conversiones estándar se comprueban antes que las conversiones personalizadas y
no se pueden invalidar. En la tabla siguiente se enumeran las conversiones de tipos
realizadas por PowerShell cuando se ConvertTo(System.Object, System.Type) llama al
método . Tenga en cuenta que las referencias a los parámetros valueToConvert y
resultType hacen referencia a los parámetros del ConvertTo(System.Object,System.Type)
método .

From To Devoluciones
(valueToConvert) (resultType)

Null String ""

Null Char '\0'

Null Numeric 0 del tipo especificado en el parámetro resultType.

Null Boolean Resultados de la llamada al IsTrue(System.Object)(Null)


método .

Null PSObject Nuevo objeto de tipo PSObject.

Null Tipo que no NULL.


es de valor

Null T que acepta NULL.


< valores
NULL>

Clase derivada Clase base valueToConvert

Nada Void AutomationNull.Value


From To Devoluciones
(valueToConvert) (resultType)

Nada String Mecanismo ToString de llamadas.

Nada Boolean IsTrue(System.Object) (valueToConvert)

Nada PSObject Resultados de la llamada al AsPSObject(System.Object)


(valueToConvert) método .

Nada Documento Convierte valueToConvert en cadena y, a continuación, llama


Xml al constructor XMLDocument.

Array Array Intenta convertir cada elemento de la matriz.

Singleton Array Array[0] es igual a valueToConvert que se convierte al tipo


de elemento de la matriz.

IDictionary Tabla hash Resultados de la llamada a Hashtable(valueToConvert).

String Char[] valueToConvert.ToCharArray

String RegEx Resultados de la llamada a Regx(valueToConvert) .

String Tipo Devuelve el tipo adecuado mediante el parámetro


valueToConvert para buscar
RunspaceConfiguration.Assemblies.

String Numeric Si valueToConvert es "", devuelve 0 el valor de resultType.


De lo contrario, la referencia cultural "culture invariant" se
usa para generar un valor numérico.

Entero System.Enum Convierte el entero en la constante si la enumeración define


el entero. Si no se define el entero, se produce una
excepción PSInvalidCastException.

Conversiones personalizadas
Si PowerShell no puede convertir el tipo mediante un convertidor de lenguaje de
PowerShell estándar, comprueba si hay convertidores personalizados. PowerShell busca
varios tipos de convertidores personalizados en el orden descrito en esta sección. Tenga
en cuenta que las referencias a los parámetros valueToConvert y resultType hacen
referencia a los parámetros del ConvertTo(System.Object, System.Type) método . Si un
convertidor personalizado produce una excepción, no se realiza ningún otro intento de
convertir el objeto y esa excepción se encapsula en una excepción
PSInvalidCastException que se inicia a continuación.
Convertidor de tipos de PowerShell
Los convertidores de tipos de PowerShell se usan para convertir un tipo único o una
familia de tipos, como todos los tipos que derivan de la clase System.Enum. Para crear
un convertidor de tipos de PowerShell, debe implementar una clase PSTypeConverter y
asociar esa implementación a la clase de destino. Hay dos maneras de asociar el
convertidor de tipos de PowerShell a su clase de destino.

A través del archivo de configuración de tipo


Aplicando el atributo TypeConverterAttribute a la clase de destino

Los convertidores de tipos de PowerShell, derivados de la clase abstracta


PSTypeConverter, proporcionan métodos para convertir un objeto a un tipo específico o
a partir de un tipo específico. Si el parámetro valueToConvert contiene un objeto que
tiene asociado un convertidor de tipos de PowerShell, PowerShell llama a
PSTypeConverter.ConvertTo(System.Object, System.Type,System.IFormatProvider,

System.Boolean) Método del convertidor asociado para convertir el objeto al tipo


especificado por el parámetro resultType. Si el parámetro resultType hace referencia a
un tipo que tiene asociado un convertidor de tipos de PowerShell, PowerShell llama a
PSTypeConverter.ConvertFrom(System.Object,System.Type, System.IFormatProvider,

System.Boolean) Método del convertidor asociado para convertir el objeto del tipo

especificado por el parámetro resultType.

Convertidor de tipos de sistema


Los convertidores de tipos de sistema se usan para convertir una clase de destino
específica. Este tipo de convertidor no se puede usar para convertir una familia de
clases. Para crear un convertidor de tipos de sistema, debe implementar una clase
TypeConverter y asociar esa implementación a la clase de destino. Hay dos maneras de
asociar el convertidor de tipos del sistema a su clase de destino.

A través del archivo de configuración de tipo


Aplicando el atributo TypeConverterAttribute a la clase de destino

Convertidor de análisis
Si el parámetro valueToConvert es una cadena y el tipo de objeto del parámetro
resultType tiene un método , se llama al método Parse para convertir la Parse cadena.

Convertidor de constructores
Si el tipo de objeto del parámetro resultType tiene un constructor que tiene un único
parámetro que es el mismo tipo que el objeto del parámetro valueToConvert, se llama a
este constructor.

Convertidor de operadores de conversión


implícito
Si el parámetro valueToConvert tiene un operador de conversión implícito que se
convierte en resultType, se llama a su operador de conversión. Si el parámetro
resultType tiene un operador de conversión implícito que convierte desde
valueToConvert, se llama a su operador de conversión.

Convertidor de operadores de conversión


explícito
Si el parámetro valueToConvert tiene un operador de conversión explícito que se
convierte en resultType, se llama a su operador de conversión. Si el parámetro
resultType tiene un operador de conversión explícito que convierte de valueToConvert,
se llama a su operador de conversión.
Errores y excepciones en el sistema de
tipos extendidos
Artículo • 24/09/2021

Los errores pueden producirse en ETS durante la inicialización de datos de tipo y al


obtener acceso a un miembro de un objeto PSObject o al usar una de las clases de
utilidad como LanguagePrimitives.

Errores de tiempo de ejecución


Con una excepción, al convertir, todas las excepciones producidas desde ETS durante el
tiempo de ejecución son una excepción ExtendedTypeSystemException o una
excepción derivada de la clase ExtendedTypeSystemException. Esto permite a los
desarrolladores de scripts capturar estas excepciones mediante Trap la instrucción en su
script.

Errores al obtener valores de miembro


Todos los errores que se producen al obtener el valor de un miembro ets (propiedad,
método o propiedad parametrizada) hacen que se produzca una excepción
GetValueException o GetValueInvocationException. Cuando ETS reconoce que se ha
producido un error, se produce una excepción GetValueException. Cuando el
obtienedor subyacente de un miembro al que se hace referencia reconoce que se ha
producido un error, se produce una excepción GetValueInvocationException que puede
incluir o no la excepción interna que produjo el error de invocación get.

Errores al establecer valores de miembro


Todos los errores que se producen al establecer el valor de una propiedad ETS hacen
que se produzca una excepción SetValueException o SetValueInvocationException.
Cuando ETS reconoce que se ha producido un error, se produce una excepción
SetValueException. Cuando el establecedor subyacente de una propiedad a la que se
hace referencia reconoce que se ha producido un error, se produce una excepción
SetValueInvocationException que puede incluir o no la excepción interna que produjo
el error de invocación de conjunto.

Errores al invocar un método


Todos los errores que se producen al invocar un método ETS hacen que se produzca
una excepción MethodException o MethodInvocationException. Cuando ETS reconoce
que se ha producido un error, se produce una excepción MethodException. Cuando el
método al que se hace referencia reconoce que se ha producido un error, se produce
una excepción MethodInvocationException que puede incluir o no la excepción interna
que produjo el error de invocación.

Errores de conversión
Cuando se intenta realizar una conversión no válida, se produce una excepción
PSInvalidCastException. Dado que esta excepción se deriva de
System.InvalidCastException, no se puede extraer directamente del script. Tenga en
cuenta que la entidad que intenta la conversión tendría que encapsular
PSInvalidCastException en una PSRuntimeException para que los scripts puedan
capturarlo. Si se intenta establecer el valor de PSPropertySet, PSMemberSet,
PSMethodInfo o un miembro de ReadOnlyPSMemberInfoCollection'1, se produce una
excepción NotSupportedException.

Errores comunes en tiempo de ejecución


Cualquier otro error común en tiempo de ejecución que se produzca es de tipo
ExtendedTypeSystemException excepción sin tipos de excepción específicos
adicionales.

Errores de inicialización
Pueden producirse errores al inicializar types.ps1xml . Normalmente, estos errores se
muestran cuando se inicia el tiempo de ejecución de PowerShell. Sin embargo, también
se pueden mostrar cuando se carga un módulo.
Windows PowerShell Guía'del
programador
Artículo • 24/09/2021

Esta guía del programador está dirigida a desarrolladores que están interesados en
proporcionar un entorno de administración de línea de comandos para los
administradores del sistema. Windows PowerShell proporciona una manera sencilla de
compilar comandos de administración que exponen objetos .NET, al tiempo que
permite que Windows PowerShell realice la mayor parte del trabajo por usted.

En el desarrollo de comandos tradicionales, es necesario escribir un analizador de


parámetros, un enlazador de parámetros, filtros y todas las demás funcionalidades
expuestas por cada comando. Windows PowerShell proporciona lo siguiente para
facilitar la escritura de comandos:

Un eficaz Windows PowerShell de ejecución (motor de ejecución) con su propio


analizador y un mecanismo para enlazar automáticamente los parámetros de
comando.

Utilidades para dar formato y mostrar resultados de comandos mediante un


intérprete de línea de comandos (CLI).

Compatibilidad con altos niveles de funcionalidad (a través de Windows


PowerShell de datos) que facilita el acceso a los datos almacenados.

Con poco costo, puede representar un objeto .NET mediante un comando


enriquecido o un conjunto de comandos que ofrecerán una experiencia de línea
de comandos completa al administrador.

En la sección siguiente se tratan los conceptos Windows PowerShell conceptos y


términos clave. Familiarícese con estos conceptos y términos antes de comenzar el
desarrollo.

Acerca de Windows PowerShell


Windows PowerShell define varios tipos de comandos que puede usar en el desarrollo.
Estos comandos incluyen: funciones, filtros, scripts, alias y ejecutables (aplicaciones). El
tipo de comando principal que se describe en esta guía es un comando simple y
pequeño denominado "cmdlet". Windows PowerShell ofrece un conjunto de cmdlets y
admite totalmente la personalización de cmdlets para adaptarse a su entorno. El
Windows PowerShell tiempo de ejecución procesa todos los tipos de comandos igual
que los cmdlets, mediante canalizaciones.

Además de los comandos, Windows PowerShell admite varios proveedores de Windows


PowerShell personalizables que hacen que estén disponibles conjuntos específicos de
cmdlets. El shell funciona dentro de la aplicación host proporcionada por Windows
PowerShell (Windows PowerShell.exe), pero es igualmente accesible desde una
aplicación host personalizada que puede desarrollar para satisfacer requisitos
específicos. Para obtener más información, vea How Windows PowerShell Works .

Cmdlets de Windows PowerShell


Un cmdlet es un comando ligero que se usa en Windows PowerShell entorno. El runtime
Windows PowerShell invoca estos cmdlets en el contexto de los scripts de
automatización que se proporcionan en la línea de comandos, y el tiempo de ejecución
de Windows PowerShell también los invoca mediante programación a través de
Windows PowerShell API.

Para obtener más información sobre los cmdlets, vea Escribir un cmdlet Windows
PowerShell .

Windows PowerShell Proveedores


Al realizar tareas administrativas, es posible que el usuario tenga que examinar los datos
almacenados en un almacén de datos (por ejemplo, el sistema de archivos, Windows
Registry o un almacén de certificados). Para facilitar estas operaciones, Windows
PowerShell un módulo denominado proveedor de Windows PowerShell que se puede
usar para acceder a un almacén de datos específico, como Windows Registry. Cada
proveedor admite un conjunto de cmdlets relacionados para proporcionar al usuario
una vista simétrica de los datos del almacén.

Windows PowerShell proporciona varios proveedores de Windows PowerShell


predeterminados. Por ejemplo, el proveedor del Registro admite la navegación y la
manipulación de Windows Registry. Las claves del Registro se representan como
elementos y los valores del Registro se tratan como propiedades.

Si expone un almacén de datos al que el usuario necesitará acceder, es posible que


tenga que escribir su propio proveedor de Windows PowerShell, tal y como se describe
en Creación de Windows PowerShell proveedores. Para obtener más información sobre
los proveedores de PowerShell de Windows, vea How Windows PowerShell Works .
Aplicación de host
Windows PowerShell incluye la aplicación host predeterminada powershell.exe, que es
una aplicación de consola que interactúa con el usuario y hospeda el entorno de
ejecución de Windows PowerShell mediante una ventana de consola.

En raras ocasiones tendrá que escribir su propia aplicación host para Windows
PowerShell, aunque se admite la personalización. Un caso en el que es posible que
necesite su propia aplicación es cuando tiene un requisito para una interfaz gráfica de
usuario que es más completa que la interfaz proporcionada por la aplicación host
predeterminada. Es posible que también quiera una aplicación personalizada al basar la
GUI en la línea de comandos. Para obtener más información, vea How to Create a
Windows PowerShell Host Application.

Windows PowerShell Ejecución


El Windows PowerShell de ejecución es el motor de ejecución que implementa el
procesamiento de comandos. Incluye las clases que proporcionan la interfaz entre la
aplicación host y Windows PowerShell comandos y proveedores. El Windows PowerShell
de ejecución se implementa como un objeto de espacio de ejecución para la sesión
Windows PowerShell actual, que es el entorno operativo en el que se ejecutan el shell y
los comandos. Para obtener detalles operativos, vea How Windows PowerShell Works .

Windows PowerShell Lengua


El Windows PowerShell proporciona funciones de scripting y mecanismos para invocar
comandos. Para obtener información de scripting completa, consulte la referencia
Windows PowerShell lenguaje incluido con Windows PowerShell.

Sistema de tipos extendidos (ETS)


Windows PowerShell proporciona acceso a una variedad de objetos diferentes, como
objetos .NET y XML. Como consecuencia, para presentar una abstracción común para
todos los tipos de objeto, el shell usa su sistema de tipos extendido (ETS). La mayoría de
la funcionalidad de ETS es transparente para el usuario, pero el script o el desarrollador
de .NET la usan para los siguientes fines:

Ver un subconjunto de los miembros de objetos específicos. Windows PowerShell


proporciona una vista "adaptada" de varios tipos de objetos específicos.

Agregar miembros a objetos existentes.


Acceso a objetos serializados.

Escribir objetos personalizados.

Con ETS, puede crear nuevos "tipos" flexibles que sean compatibles con el
Windows PowerShell usuario. Si es un desarrollador de .NET, puede trabajar con
objetos con la misma semántica que el lenguaje Windows PowerShell se aplica al
scripting, por ejemplo, para determinar si un objeto se evalúa como true .

Para obtener más información sobre ETS y Windows PowerShell utiliza objetos, vea
Windows PowerShell Object Concepts.

Programación para Windows PowerShell


Windows PowerShell define su código para comandos, proveedores y otros módulos de
programa mediante el .NET Framework. No se limita al uso de Microsoft Visual Studio
en la creación de módulos personalizados para Windows PowerShell, aunque se sabe
que los ejemplos proporcionados en esta guía se ejecutan en esta herramienta. Puede
usar cualquier lenguaje .NET que admita la herencia de clases y el uso de atributos. En
algunos casos, Windows PowerShell API requieren que el lenguaje de programación
pueda acceder a tipos genéricos.

Referencia del programador


Para obtener referencia al desarrollar para Windows PowerShell, consulte el SDK
Windows PowerShell.

Tareas iniciales uso de Windows PowerShell


Para obtener más información sobre cómo empezar a usar el shell Windows PowerShell,
consulte el Tareas iniciales con Windows PowerShell incluido con Windows PowerShell.
También se proporciona un documento triplicador de referencia rápida como base para
el uso de cmdlets.

Contenido de esta guía


Tema Definición
Tema Definición

Cómo crear un En esta sección se describe cómo crear un proveedor Windows PowerShell
proveedor de para Windows PowerShell.
Windows
PowerShell

Cómo crear una En esta sección se describe cómo escribir una aplicación host que
aplicación Windows manipula un espacio de ejecución y cómo escribir una aplicación host que
PowerShell host implementa su propio host personalizado.

Cómo crear un En esta sección se describe cómo crear un complemento que se usa para
complemento de registrar todos los cmdlets y proveedores en un ensamblado y cómo crear
Windows un complemento personalizado.
PowerShell

Cómo crear un shell En esta sección se describe cómo crear un shell de consola que no sea
de la consola extensible.

Conceptos de Esta sección contiene información conceptual que le ayudará a


Windows comprender Windows PowerShell desde el punto de vista de un
PowerShell desarrollador.

Consulte también
Windows PowerShell SDK
Cómo crear un proveedor de Windows
PowerShell
Artículo • 27/09/2021

En esta sección se describe cómo compilar un proveedor Windows PowerShell datos. Un


Windows PowerShell proveedor de recursos se puede considerar de dos maneras. Para
el usuario, el proveedor representa un conjunto de datos almacenados. Por ejemplo, los
datos almacenados pueden ser la metabase de Internet Information Services (IIS),
microsoft Windows Registry, el sistema de archivos Windows, Active Directory y los
datos de variables y alias almacenados por Windows PowerShell.

Para el desarrollador, el Windows PowerShell es la interfaz entre el usuario y los datos a


los que el usuario necesita acceder. Desde esta perspectiva, cada tipo de proveedor
descrito en esta sección admite un conjunto de clases base e interfaces específicas que
permiten al tiempo de ejecución de Windows PowerShell exponer determinados
cmdlets al usuario de una manera común.

Proveedores proporcionados por Windows


PowerShell
Windows PowerShell proporciona varios proveedores (como el proveedor FileSystem, el
proveedor del Registro y el proveedor de alias) que se usan para acceder a almacenes
de datos conocidos. Para obtener más información sobre los proveedores
proporcionados por Windows PowerShell, use el siguiente comando para acceder a la
Ayuda en línea:

Ps>get-help about_providers

Acceso a los datos almacenados mediante rutas


Windows PowerShell de acceso
Windows PowerShell los proveedores son accesibles para Windows PowerShell runtime
y comandos mediante programación mediante el uso de rutas Windows PowerShell de
acceso. La mayoría de las veces, estas rutas de acceso se usan para acceder
directamente a los datos a través del proveedor. Sin embargo, algunas rutas de acceso
se pueden resolver en rutas de acceso internas del proveedor que permiten a un cmdlet
usar interfaces de programación de aplicaciones (API) que no son de Windows
PowerShell para acceder a los datos. Para obtener más información sobre cómo
funcionan Windows PowerShell en Windows PowerShell, vea How Windows PowerShell
Works.

Exposición de cmdlets de proveedor mediante


Windows PowerShell virtuales
Un Windows PowerShell expone sus cmdlets admitidos mediante unidades Windows
PowerShell virtuales. Windows PowerShell aplica las siguientes reglas para una Windows
PowerShell disco:

El nombre de una unidad puede ser cualquier secuencia alfanumérica.


Se puede especificar una unidad en cualquier punto válido de una ruta de acceso,
denominada "raíz".
Se puede implementar una unidad para cualquier dato almacenado, no solo para
el sistema de archivos.
Cada unidad mantiene su propia ubicación de trabajo actual, lo que permite al
usuario conservar el contexto al desplazarse entre unidades.

En esta sección
En la tabla siguiente se enumeran los temas que incluyen ejemplos de código que se
compilan entre sí. A partir del segundo tema, el runtime de Windows PowerShell puede
inicializar y desinicializar el proveedor de Windows PowerShell básico, el tema siguiente
agrega funcionalidad para acceder a los datos, el siguiente tema agrega funcionalidad
para manipular los datos (los elementos de los datos almacenados), y así sucesivamente.

Tema Definición

Diseño del proveedor En este tema se deberán tener en cuenta los aspectos que debe tener en
de Windows cuenta antes de implementar Windows PowerShell proveedor. Resume
PowerShell las interfaces Windows PowerShell base del proveedor que se usan.

Diseño de un En este tema se muestra cómo crear un proveedor Windows PowerShell


proveedor de que permite que el entorno de ejecución de Windows PowerShell
Windows PowerShell inicialice y desinicialice el proveedor.
básico

Creación de un En este tema se muestra cómo crear un proveedor Windows PowerShell


proveedor de unidad que permita al usuario acceder a un almacén de datos a través de una
de Windows Windows PowerShell datos.
PowerShell
Tema Definición

Creación de un En este tema se muestra cómo crear un Windows PowerShell que


proveedor de permite al usuario manipular los elementos de un almacén de datos.
elementos de
Windows PowerShell

Creación de un En este tema se muestra cómo crear un Windows PowerShell que


proveedor de permite al usuario trabajar en almacenes de datos multicapa.
contenedores de
Windows PowerShell

Creación de un En este tema se muestra cómo crear un proveedor Windows PowerShell


proveedor de que permite al usuario navegar por los elementos de un almacén de
navegación de datos de forma jerárquica.
Windows PowerShell

Creación de un En este tema se muestra cómo crear un proveedor Windows PowerShell


proveedor de que permite al usuario manipular el contenido de los elementos de un
contenido de almacén de datos.
Windows PowerShell

Creación de un En este tema se muestra cómo crear un Windows PowerShell que


proveedor de permite al usuario manipular las propiedades de los elementos de un
propiedades de almacén de datos.
Windows PowerShell

Consulte también
Funcionamiento de Windows PowerShell

Windows PowerShell SDK

Guía del programador de Windows PowerShell


Diseño del proveedor de Windows
PowerShell
Artículo • 25/09/2021

Debe implementar un proveedor de Windows PowerShell si el producto o la


configuración expone un conjunto de datos almacenados, como una base de datos que
el usuario querrá navegar o examinar. Además, si el producto proporciona un
contenedor, incluso si no es un contenedor de varios niveles, tiene sentido implementar
un Windows PowerShell proveedor. Por ejemplo, es posible que quiera implementar un
proveedor de contenedores de Windows PowerShell si el verbo del cmdlet Copy, Move,
Rename, New o Remove tiene sentido como una operación en los datos de producto o
configuración.

Windows PowerShell Rutas de acceso para


identificar al proveedor
El Windows PowerShell de ejecución usa Windows PowerShell rutas de acceso para
acceder al proveedor Windows PowerShell adecuado. Cuando un cmdlet especifica una
de estas rutas de acceso, el tiempo de ejecución sabe qué proveedor usar para acceder
al almacén de datos asociado. Estas rutas de acceso incluyen rutas de acceso calificadas
por unidad, rutas de acceso calificadas por el proveedor, rutas de acceso directas del
proveedor y rutas de acceso internas del proveedor. Cada Windows PowerShell debe
admitir una o varias de estas rutas de acceso.

Para obtener más información sobre Windows PowerShell rutas de acceso, vea How
Windows PowerShell Works.

Definición de una Drive-Qualified de acceso


Para permitir que el usuario acceda a los datos ubicados en una unidad física, el
proveedor de Windows PowerShell debe admitir una ruta de acceso completa a la
unidad. Esta ruta de acceso comienza con el nombre de unidad seguido de dos puntos
(:), por ejemplo, mydrive:\abc\bar.

Definición de una Provider-Qualified de acceso


Para permitir que Windows PowerShell tiempo de ejecución inicialice y desinicialice el
proveedor, el proveedor de Windows PowerShell debe admitir una ruta de acceso
completa del proveedor. Por ejemplo, FileSystem:: \uncshare\abc\bar es la ruta de
acceso completa del proveedor del sistema de archivos que \ Windows PowerShell.

Definición de una Provider-Direct de acceso


Para permitir el acceso remoto al proveedor de Windows PowerShell, debe admitir una
ruta de acceso directa del proveedor para pasar directamente al proveedor de Windows
PowerShell para la ubicación actual. Por ejemplo, el proveedor Windows PowerShell
registro puede usar \ \server\regkeypath como ruta de acceso directa del proveedor.

Definición de una Provider-Internal de acceso


Para permitir que el cmdlet del proveedor acceda a los datos mediante interfaces de
programación de aplicaciones (API) que no son de Windows PowerShell, el proveedor
de Windows PowerShell debe admitir una ruta de acceso interna del proveedor. Esta
ruta de acceso se indica después de "::" en la ruta de acceso calificada por el proveedor.
Por ejemplo, la ruta de acceso interna del proveedor para el Windows PowerShell de
archivos es \ \uncshare\abc\bar.

Cambiar los datos almacenados


Al reemplazar métodos que modifican el almacén de datos subyacente, llame siempre al
método System.Management.Automation.Provider.Cmdletprovider.Writeitemobject*
con la versión más actualizada del elemento modificada por ese método. La
infraestructura del proveedor determina si el objeto de elemento debe pasarse a la
canalización, por ejemplo, cuando el usuario especifica el parámetro -PassThru. Si
recuperar el elemento más actualizado es una operación costosa (en cuanto al
rendimiento), puede probar la propiedad Context.PassThru para determinar si realmente
necesita escribir el elemento resultante.

Elegir una clase base para el proveedor


Windows PowerShell proporciona una serie de clases base que puede usar para
implementar su propio proveedor Windows PowerShell datos. Al diseñar un proveedor,
elija la clase base, que se describe en esta sección, más adecuada para sus requisitos.

Cada Windows PowerShell base del proveedor pone a disposición un conjunto de


cmdlets. En esta sección se describen los cmdlets, pero no se describen sus parámetros.
Con el estado de sesión, Windows PowerShell runtime hace que varios cmdlets de
ubicación estén disponibles para determinados proveedores de Windows PowerShell,
como los Get-Location cmdlets , Set-Location , y Pop-Location Push-Location . Puede
usar el Get-Help cmdlet para obtener información sobre estos cmdlets de ubicación.

CmdletProvider (clase base)


La clase System.Management.Automation.Provider.Cmdletprovider define un proveedor
Windows PowerShell básico. Esta clase admite la declaración de proveedor y
proporciona una serie de propiedades y métodos que están disponibles para todos los
Windows PowerShell proveedores. El cmdlet invoca la clase Get-PSProvider para
enumerar todos los proveedores disponibles para una sesión. La implementación de
este cmdlet se realiza mediante el estado de sesión.

7 Nota

Windows PowerShell están disponibles para todos los Windows PowerShell de


lenguaje.

Clase base DriveCmdletProvider


La clase System.Management.Automation.Provider.Drivecmdletprovider define un
proveedor de unidades Windows PowerShell que admite operaciones para agregar
nuevas unidades, quitar unidades existentes e inicializar unidades predeterminadas. Por
ejemplo, el proveedor FileSystem proporcionado por Windows PowerShell inicializa
unidades para todos los volúmenes montados, como unidades de disco duro y unidades
de dispositivo cd/DVD.

Esta clase se deriva de la clase base


System.Management.Automation.Provider.Cmdletprovider. En la tabla siguiente se
enumeran los cmdlets expuestos por esta clase. Además de los enumerados, el cmdlet
(expuesto por el estado de sesión) es un cmdlet relacionado que se Get-PSDrive usa
para recuperar las unidades disponibles.

Cmdlet Definición

New-PSDrive Crea una nueva unidad para la sesión y transmite información de la unidad.

Remove-PSDrive Quita una unidad de la sesión.


Clase base ItemCmdletProvider
La clase System.Management.Automation.Provider.Itemcmdletprovider define un
proveedor de elementos Windows PowerShell que realiza operaciones en los elementos
individuales del almacén de datos y no supone ninguna funcionalidad de navegación o
contenedor. Esta clase se deriva de la clase base
System.Management.Automation.Provider.Drivecmdletprovider. En la tabla siguiente se
enumeran los cmdlets expuestos por esta clase.

Cmdlet Definición

Clear- Borra el contenido actual de los elementos en la ubicación especificada y lo reemplaza


Item por el valor "clear" especificado por el proveedor. Este cmdlet no pasa un objeto de
salida a través de la canalización a menos que PassThru se especifique su parámetro .

Get- Recupera los elementos de la ubicación especificada y transmite los objetos


Item resultantes.

Invoke- Invoca la acción predeterminada para el elemento en la ruta de acceso especificada.


Item

Set- Establece un elemento en la ubicación especificada con el valor indicado. Este cmdlet
Item no pasa un objeto de salida a través de la canalización a menos que PassThru se
especifique su parámetro .

Resolve- Resuelve los caracteres comodín de una ruta Windows PowerShell ruta de acceso y
Path transmite la información de la ruta de acceso.

Test- Comprueba la ruta de acceso especificada y devuelve si existe y, de true lo false


Path contrario, devuelve . Este cmdlet se implementa para admitir el parámetro para el
método IsContainer
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject*.

Clase base ContainerCmdletProvider


La clase System.Management.Automation.Provider.Containercmdletprovider define un
proveedor de contenedores Windows PowerShell que expone un contenedor, para los
elementos del almacén de datos, al usuario. Tenga en cuenta que Windows PowerShell
proveedor de contenedores solo se puede usar cuando hay un contenedor (sin
contenedores anidados) con elementos en él. Si hay contenedores anidados, debe
implementar un proveedor de Windows PowerShell de navegación .

Esta clase se deriva de la clase base


System.Management.Automation.Provider.Itemcmdletprovider. En la tabla siguiente se
definen los cmdlets implementados por esta clase.
Cmdlet Definición

Copy- Copia los elementos de una ubicación a otra. Este cmdlet no pasa un objeto de salida
Item a través de la canalización a menos que PassThru se especifique su parámetro .

Get- Recupera los elementos secundarios en la ubicación especificada y los transmite


Childitem como objetos.

New-Item Crea nuevos elementos en la ubicación especificada y transmite el objeto resultante.

Remove- Quita los elementos de la ubicación especificada.


Item

Rename- Cambia el nombre de un elemento en la ubicación especificada. Este cmdlet no pasa


Item un objeto de salida a través de la canalización a menos que PassThru se especifique
su parámetro .

Clase base NavigationCmdletProvider


La clase System.Management.Automation.Provider.Navigationcmdletprovider define un
proveedor de navegación Windows PowerShell que realiza operaciones para los
elementos que usan más de un contenedor. Esta clase se deriva de la clase base
System.Management.Automation.Provider.Containercmdletprovider. En la tabla
siguiente se enumeran los cmdlets expuestos por esta clase.

Cmdlet Definición

Combine- Combina dos rutas de acceso en una única ruta de acceso, mediante un delimitador
Path específico del proveedor entre las rutas de acceso. Este cmdlet transmite cadenas.

Move- Mueve los elementos a la ubicación especificada. Este cmdlet no pasa un objeto de
Item salida a través de la canalización a menos que PassThru se especifique su parámetro .

Un cmdlet relacionado es el cmdlet Parse-Path básico que Windows PowerShell. Este


cmdlet se puede usar para analizar una ruta de acceso Windows PowerShell para admitir
el Parent parámetro . Transmite la cadena de ruta de acceso primaria.

Seleccionar interfaces de proveedor para


admitir
Además de derivarse de una de las clases base de Windows PowerShell, el proveedor de
Windows PowerShell puede admitir otra funcionalidad derivando de una o varias de las
interfaces de proveedor siguientes. En esta sección se definen esas interfaces y los
cmdlets admitidos por cada una de ellas. No describe los parámetros de los cmdlets
compatibles con la interfaz. La información de los parámetros del cmdlet está disponible
en línea mediante Get-Command Get-Help los cmdlets y .

IContentCmdletProvider
La interfaz System.Management.Automation.Provider.Icontentcmdletprovider define un
proveedor de contenido que realiza operaciones en el contenido de un elemento de
datos. En la tabla siguiente se enumeran los cmdlets expuestos por esta interfaz.

Cmdlet Definición

Add- Anexa las longitudes de valor indicadas al contenido del elemento especificado. Este
Content cmdlet no pasa un objeto de salida a través de la canalización a menos que PassThru
se especifique su parámetro .

Clear- Establece el contenido del elemento especificado en el valor "clear". Este cmdlet no
Content pasa un objeto de salida a través de la canalización a menos que PassThru se
especifique su parámetro .

Get- Recupera el contenido de los elementos especificados y transmite los objetos


Content resultantes.

Set- Reemplaza el contenido existente para los elementos especificados. Este cmdlet no
Content pasa un objeto de salida a través de la canalización a menos que PassThru se
especifique su parámetro .

IPropertyCmdletProvider
La interfaz System.Management.Automation.Provider.Ipropertycmdletprovider define
una propiedad Windows PowerShell proveedor que realiza operaciones en las
propiedades de los elementos del almacén de datos. En la tabla siguiente se enumeran
los cmdlets expuestos por esta interfaz.

7 Nota

El parámetro de estos cmdlets indica una ruta de acceso Path a un elemento en


lugar de identificar una propiedad.

Cmdlet Definición

Clear- Establece las propiedades de los elementos especificados en el valor "clear". Este
ItemProperty cmdlet no pasa un objeto de salida a través de la canalización a menos que
PassThru se especifique su parámetro .
Cmdlet Definición

Get- Recupera las propiedades de los elementos especificados y transmite los objetos
ItemProperty resultantes.

Set- Establece las propiedades de los elementos especificados con los valores
ItemProperty indicados. Este cmdlet no pasa un objeto de salida a través de la canalización a
menos que PassThru se especifique su parámetro .

IDynamicPropertyCmdletProvider
La interfaz System.Management.Automation.Provider.Idynamicpropertycmdletprovider,
derivada de System.Management.Automation.Provider.Ipropertycmdletprovider,define
un proveedor que especifica parámetros dinámicos para sus cmdlets admitidos. Este
tipo de proveedor controla las operaciones para las que se pueden definir propiedades
en tiempo de ejecución, por ejemplo, una nueva operación de propiedad. Estas
operaciones no son posibles en los elementos que tienen propiedades definidas
estáticamente. En la tabla siguiente se enumeran los cmdlets expuestos por esta
interfaz.

Cmdlet Definición

Copy- Copia una propiedad del elemento especificado en otro elemento. Este cmdlet no
ItemProperty pasa un objeto de salida a través de la canalización a menos que PassThru se
especifique su parámetro .

Move- Mueve una propiedad del elemento especificado a otro elemento. Este cmdlet no
ItemProperty pasa un objeto de salida a través de la canalización a menos que PassThru se
especifique su parámetro .

New- Crea una propiedad en los elementos especificados y transmite los objetos
ItemProperty resultantes.

Remove- Quita una propiedad para los elementos especificados.


ItemProperty

Rename- Cambia el nombre de una propiedad de los elementos especificados. Este cmdlet
ItemProperty no pasa un objeto de salida a través de la canalización a menos que PassThru se
especifique su parámetro .

ISecurityDescriptorCmdletProvider
La interfaz System.Management.Automation.Provider.Isecuritydescriptorcmdletprovider
agrega la funcionalidad de descriptor de seguridad a un proveedor. Esta interfaz
permite al usuario obtener y establecer información del descriptor de seguridad de un
elemento en el almacén de datos. En la tabla siguiente se enumeran los cmdlets
expuestos por esta interfaz.

Cmdlet Definición

Get- Recupera la información contenida en una lista de control de acceso (ACL), que forma
Acl parte de un descriptor de seguridad que se usa para proteger los recursos del sistema
operativo, por ejemplo, un archivo o un objeto.

Set- Establece la información de una ACL. Tiene el formato de una instancia de


Acl System.Security.Accesscontrol.Objectsecurity en los elementos designados para la ruta
de acceso especificada. Este cmdlet puede establecer información sobre archivos,
claves y subclaves en el Registro, o cualquier otro elemento de proveedor, si el
proveedor Windows PowerShell admite la configuración de la información de
seguridad.

Consulte también
Creación de Windows PowerShell proveedores

Funcionamiento de Windows PowerShell

Windows PowerShell SDK


Diseño de un proveedor de Windows
PowerShell básico
Artículo • 27/09/2021

Este tema es el punto de partida para aprender a crear un Windows PowerShell de


trabajo. El proveedor básico que se describe aquí proporciona métodos para iniciar y
detener el proveedor y, aunque este proveedor no proporciona un medio para acceder
a un almacén de datos o para obtener o establecer los datos en el almacén de datos,
proporciona la funcionalidad básica necesaria para todos los proveedores.

Como se mencionó anteriormente, el proveedor básico descrito aquí implementa


métodos para iniciar y detener el proveedor. El Windows PowerShell tiempo de
ejecución llama a estos métodos para inicializar y desinicializar el proveedor.

7 Nota

Puede encontrar un ejemplo de este proveedor en el archivo


AccessDBSampleProvider01.cs proporcionado por Windows PowerShell.

Definición de la Windows PowerShell provider


El primer paso para crear un proveedor Windows PowerShell es definir su clase .NET.
Este proveedor básico define una clase denominada que deriva de la clase
AccessDBProvider base System.Management.Automation.Provider.Cmdletprovider.

Se recomienda colocar las clases de proveedor en un espacio de nombres del espacio


de nombres de api, por Providers ejemplo, xxx.PowerShell.Providers. Este proveedor
usa el espacio de nombres , en el que se ejecutan
Microsoft.Samples.PowerShell.Provider Windows PowerShell ejemplos de proveedores.

7 Nota

La clase para un proveedor Windows PowerShell debe marcarse explícitamente


como pública. Las clases no marcadas como públicas serán internas de forma
predeterminada y no las encontrará el entorno Windows PowerShell tiempo de
ejecución.

Esta es la definición de clase para este proveedor básico:


C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : CmdletProvider

Justo antes de la definición de clase, debe declarar el atributo


System.Management.Automation.Provider.Cmdletproviderattribute, con la sintaxis
[CmdletProvider()].

Puede establecer palabras clave de atributo para declarar aún más la clase si es
necesario. Observe que el atributo
System.Management.Automation.Provider.Cmdletproviderattribute declarado aquí
incluye dos parámetros. El primer parámetro de atributo especifica el nombre
descriptivo predeterminado para el proveedor, que el usuario puede modificar más
adelante. El segundo parámetro especifica las Windows PowerShell definidas por el
proveedor que el proveedor expone al entorno Windows PowerShell tiempo de
ejecución durante el procesamiento de comandos. Los valores posibles para las
funcionalidades del proveedor se definen mediante la enumeración
System.Management.Automation.Provider.Providercapabilities. Dado que se trata de un
proveedor base, no admite funcionalidades.

7 Nota

El nombre completo del proveedor de Windows PowerShell incluye el nombre del


ensamblado y otros atributos determinados por Windows PowerShell tras el
registro del proveedor.

Definición de Provider-Specific información de


estado
La clase base System.Management.Automation.Provider.Cmdletprovider y todas las
clases derivadas se consideran sin estado porque el tiempo de ejecución de Windows
PowerShell crea instancias de proveedor solo según sea necesario. Por lo tanto, si el
proveedor requiere control total y mantenimiento de estado para los datos específicos
del proveedor, debe derivar una clase de la clase
System.Management.Automation.Providerinfo. La clase derivada debe definir los
miembros necesarios para mantener el estado de modo que se pueda acceder a los
datos específicos del proveedor cuando el tiempo de ejecución de Windows PowerShell
llame al método System.Management.Automation.Provider.Cmdletprovider.Start* para
inicializar el proveedor.
Un Windows PowerShell de conexión también puede mantener el estado basado en la
conexión. Para obtener más información sobre cómo mantener el estado de conexión,
vea Creación de un proveedor de unidades de PowerShell.

Inicialización del proveedor


Para inicializar el proveedor, Windows PowerShell tiempo de ejecución llama al método
System.Management.Automation.Provider.Cmdletprovider.Start* cuando Windows
PowerShell se inicia. En su mayor parte, el proveedor puede usar la implementación
predeterminada de este método, que simplemente devuelve el objeto
System.Management.Automation.Providerinfo que describe el proveedor. Sin embargo,
en el caso de que desee agregar información de inicialización adicional, debe
implementar su propio método
System.Management.Automation.Provider.Cmdletprovider.Start* que devuelve una
versión modificada del objeto System.Management.Automation.Providerinfo que se
pasa al proveedor. En general, este método debe devolver el objeto
System.Management.Automation.Providerinfo proporcionado pasado a él o un objeto
System.Management.Automation.Providerinfo modificado que contiene otra
información de inicialización.

Este proveedor básico no invalida este método. Sin embargo, el código siguiente
muestra la implementación predeterminada de este método:

El proveedor puede mantener el estado de la información específica del proveedor


como se describe en Definición del estado de datos específico del proveedor. En este
caso, la implementación debe invalidar el método
System.Management.Automation.Provider.Cmdletprovider.Start* para devolver una
instancia de la clase derivada.

Iniciar parámetros dinámicos


La implementación del proveedor del método
System.Management.Automation.Provider.Cmdletprovider.Start* puede requerir
parámetros adicionales. En este caso, el proveedor debe invalidar el método
System.Management.Automation.Provider.Cmdletprovider.Startdynamicparameters* y
devolver un objeto que tenga propiedades y campos con atributos de análisis similares
a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary.

Este proveedor básico no invalida este método. Sin embargo, el código siguiente
muestra la implementación predeterminada de este método:
Desinicializar el proveedor
Para liberar recursos que el Windows PowerShell usa, el proveedor debe implementar su
propio método System.Management.Automation.Provider.Cmdletprovider.Stop*. El
tiempo de ejecución de Windows PowerShell llama a este método para desinicializar el
proveedor al cierre de una sesión.

Este proveedor básico no invalida este método. Sin embargo, el código siguiente
muestra la implementación predeterminada de este método:

Ejemplo de código
Para obtener código de ejemplo completo, vea Ejemplo de código
AccessDbProviderSample01.

Probar el proveedor de Windows PowerShell de


prueba
Una vez Windows PowerShell el proveedor de Windows PowerShell, puede probarlo
ejecutando los cmdlets admitidos en la línea de comandos. Para este proveedor básico,
ejecute el nuevo shell y use el cmdlet para recuperar la lista de proveedores y
asegurarse de que el Get-PSProvider proveedor AccessDb está presente.

PowerShell

Get-PSProvider

Se mostrará la siguiente salida:

Output

Name Capabilities Drives


---- ------------ ------
AccessDb None {}
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess {C, Z}
Function ShouldProcess {function}
Registry ShouldProcess {HKLM, HKCU}

Consulte también
Creación de Windows PowerShell proveedores

Diseño del proveedor de Windows PowerShell


Creación de un proveedor de unidad de
Windows PowerShell
Artículo • 25/09/2021

En este tema se describe cómo crear un proveedor de Windows PowerShell que


proporciona una manera de acceder a un almacén de datos a través de una Windows
PowerShell datos. Este tipo de proveedor también se conoce como proveedor Windows
PowerShell de unidad. Las Windows PowerShell que usa el proveedor proporcionan los
medios para conectarse al almacén de datos.

El Windows PowerShell unidad de disco que se describe aquí proporciona acceso a una
base de datos de Microsoft Access. Para este proveedor, la unidad Windows PowerShell
representa la base de datos (es posible agregar cualquier número de unidades a un
proveedor de unidades), los contenedores de nivel superior de la unidad representan las
tablas de la base de datos y los elementos de los contenedores representan las filas de
las tablas.

Definir la clase Windows PowerShell proveedor


de recursos
El proveedor de unidades debe definir una clase .NET que se derive de la clase base
System.Management.Automation.Provider.Drivecmdletprovider. Esta es la definición de
clase para este proveedor de unidades:

C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : DriveCmdletProvider

Observe que en este ejemplo, el atributo


System.Management.Automation.Provider.Cmdletproviderattribute especifica un
nombre descriptivo para el proveedor y las funcionalidades específicas de Windows
PowerShell que el proveedor expone al runtime de Windows PowerShell durante el
procesamiento de comandos. Los valores posibles para las funcionalidades del
proveedor se definen mediante la enumeración
System.Management.Automation.Provider.Providercapabilities. Este proveedor de
unidades no admite ninguna de estas funcionalidades.
Definición de la funcionalidad base
Como se describe en Diseño del proveedor de Windows PowerShell,la clase
System.Management.Automation.Provider.Drivecmdletprovider se deriva de la clase
base System.Management.Automation.Provider.Cmdletprovider que define los métodos
necesarios para inicializar y desinicializar el proveedor. Para implementar la
funcionalidad para agregar información de inicialización específica de la sesión y para
liberar los recursos que usa el proveedor, vea Creating a Basic Windows PowerShell
Provider. Sin embargo, la mayoría de los proveedores (incluido el proveedor descrito
aquí) pueden usar la implementación predeterminada de esta funcionalidad
proporcionada por Windows PowerShell.

Crear información de estado de unidad


Todos los Windows PowerShell se consideran sin estado, lo que significa que el
proveedor de unidades debe crear cualquier información de estado necesaria para el
entorno de ejecución de Windows PowerShell cuando llama al proveedor.

Para este proveedor de unidades, la información de estado incluye la conexión a la base


de datos que se mantiene como parte de la información de la unidad. Este es el código
que muestra cómo se almacena esta información en el objeto
System.Management.Automation.PSDriveinfo que describe la unidad:

C#

internal class AccessDBPSDriveInfo : PSDriveInfo


{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo
Creación de una unidad
Para permitir que Windows PowerShell runtime cree una unidad, el proveedor de
unidades debe implementar el método
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive*. El código
siguiente muestra la implementación del método
System.Management.Automation.Provider.Drivecmdletprovider.Newdrive* para este
proveedor de unidades:

C#

protected override PSDriveInfo NewDrive(PSDriveInfo drive)


{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();
builder.Driver = "Microsoft Access Driver (*.mdb)";
builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

La invalidación de este método debe hacer lo siguiente:

Compruebe que el miembro System.Management.Automation.PSDriveinfo.Root*


existe y que se puede establecer una conexión con el almacén de datos.

Cree una unidad y rellene el miembro de conexión, para admitir el New-PSDrive


cmdlet .

Valide el objeto System.Management.Automation.PSDriveinfo para la unidad


propuesta.

Modifique el objeto System.Management.Automation.PSDriveinfo que describe la


unidad con cualquier información de rendimiento o confiabilidad necesaria, o
proporcione datos adicionales para los llamadores que usan la unidad.

Controle los errores mediante el método


System.Management.Automation.Provider.Cmdletprovider.WriteError y, a
continuación, devuelva null .

Este método devuelve la información de unidad que se pasó al método o una


versión específica del proveedor.

Adjuntar parámetros dinámicos a NewDrive


El New-PSDrive cmdlet admitido por el proveedor de unidades puede requerir
parámetros adicionales. Para adjuntar estos parámetros dinámicos al cmdlet , el
proveedor implementa el método
System.Management.Automation.Provider.Drivecmdletprovider.Newdrivedynamicparam
eters*. Este método devuelve un objeto que tiene propiedades y campos con atributos
de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary.

Este proveedor de unidades no invalida este método. Sin embargo, el código siguiente
muestra la implementación predeterminada de este método:
Quitar una unidad
Para cerrar la conexión de base de datos, el proveedor de unidades debe implementar el
método System.Management.Automation.Provider.Drivecmdletprovider.Removedrive*.
Este método cierra la conexión a la unidad después de limpiar cualquier información
específica del proveedor.

El código siguiente muestra la implementación del método


System.Management.Automation.Provider.Drivecmdletprovider.Removedrive* para este
proveedor de unidades:

C#

protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)


{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

Si se puede quitar la unidad, el método debe devolver la información que se pasa al


método a través del drive parámetro . Si no se puede quitar la unidad, el método debe
escribir una excepción y, a continuación, devolver null . Si el proveedor no invalida este
método, la implementación predeterminada de este método solo devuelve la
información de unidad pasada como entrada.

Inicialización de unidades predeterminadas


El proveedor de unidades implementa el método
System.Management.Automation.Provider.Drivecmdletprovider.Initializedefaultdrives*
para montar unidades. Por ejemplo, el proveedor Active Directory podría montar una
unidad para el contexto de nomenclatura predeterminado si el equipo está unido a un
dominio.

Este método devuelve una colección de información de unidad sobre las unidades
inicializadas o una colección vacía. La llamada a este método se realiza después de que
Windows PowerShell runtime llame al método
System.Management.Automation.Provider.Cmdletprovider.Start* para inicializar el
proveedor.

Este proveedor de unidades no invalida el método


System.Management.Automation.Provider.Drivecmdletprovider.Initializedefaultdrives*.
Sin embargo, el código siguiente muestra la implementación predeterminada, que
devuelve una colección de unidades vacías:

Cosas que debe recordar sobre la implementación de


InitializeDefaultDrives
Todos los proveedores de unidades deben montar una unidad raíz para ayudar al
usuario con la detectabilidad. La unidad raíz podría enumerar las ubicaciones que sirven
como raíces para otras unidades montadas. Por ejemplo, el proveedor de Active
Directory podría crear una unidad que enumera los contextos de nomenclatura que se
encuentran en los atributos del entorno de sistema distribuido namingContext (DSE) raíz.
Esto ayuda a los usuarios a detectar puntos de montaje para otras unidades.

Ejemplo de código
Para obtener código de ejemplo completo, vea Ejemplo de código
AccessDbProviderSample02.

Probar el proveedor Windows PowerShell


unidad de disco
Cuando el proveedor Windows PowerShell se haya registrado con Windows PowerShell,
puede probarlo ejecutando los cmdlets admitidos en la línea de comandos, incluidos los
cmdlets que estén disponibles mediante derivación. Vamos a probar el proveedor de
unidades de ejemplo.
1. Ejecute el Get-PSProvider cmdlet para recuperar la lista de proveedores para
asegurarse de que el proveedor de la unidad AccessDB está presente:

PS> Get-PSProvider

Se mostrará la siguiente salida:

Output

Name Capabilities Drives


---- ------------ ------
AccessDB None {}
Alias ShouldProcess {Alias}
Environment ShouldProcess {Env}
FileSystem Filter, ShouldProcess {C, Z}
Function ShouldProcess {function}
Registry ShouldProcess {HKLM, HKCU}

2. Asegúrese de que existe un nombre de servidor de base de datos (DSN) para la


base de datos accediendo a la parte Orígenes de datos de las Herramientas
administrativas del sistema operativo. En la tabla DSN de usuario, haga doble clic
en Base de datos de MS Access y agregue la ruta de acceso de la unidad
C:\ps\northwind.mdb .

3. Cree una nueva unidad con el proveedor de unidades de ejemplo:

PowerShell

new-psdrive -name mydb -root c:\ps\northwind.mdb -psprovider AccessDb`

Se mostrará la siguiente salida:

Output

Name Provider Root CurrentLocation


---- -------- ---- ---------------
mydb AccessDB c:\ps\northwind.mdb

4. Valide la conexión. Dado que la conexión se define como miembro de la unidad,


puede comprobarla mediante el cmdlet Get-PDDrive.

7 Nota

El usuario todavía no puede interactuar con el proveedor como una unidad,


ya que el proveedor necesita funcionalidad de contenedor para esa
interacción. Para obtener más información, vea Creating a Windows
PowerShell Container Provider.

PS> (get-psdrive mydb).connection

Se mostrará la siguiente salida:

Output

ConnectionString : Driver={Microsoft Access Driver


(*.mdb)};DBQ=c:\ps\northwind.mdb
ConnectionTimeout : 15
Database : c:\ps\northwind
DataSource : ACCESS
ServerVersion : 04.00.0000
Driver : odbcjt32.dll
State : Open
Site :
Container :

5. Quite la unidad y salga del shell:

PowerShell

PS> remove-psdrive mydb


PS> exit

Consulte también
Creación de Windows PowerShell proveedores de recursos

Diseñar el proveedor de Windows PowerShell personalizado

Diseño de un proveedor de Windows PowerShell básico


Creación de un proveedor de elementos
de Windows PowerShell
Artículo • 13/05/2022

En este tema se describe cómo crear un proveedor de Windows PowerShell que pueda
manipular los datos de un almacén de datos. En este tema, los elementos de los datos
del almacén se conocen como "elementos" del almacén de datos. Como consecuencia,
un proveedor que puede manipular los datos del almacén se conoce como proveedor
de elementos Windows PowerShell.

7 Nota

Puede descargar el archivo de código fuente de C# ( AccessDBSampleProvider03.cs )


para este proveedor mediante el Kit de desarrollo de software de Microsoft
Windows para Windows Vista y componentes en tiempo de ejecución de .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte Instalación de
Windows PowerShell y Descarga del SDK de Windows PowerShell. Los archivos de
origen descargados están disponibles en el PowerShell Samples directorio . Para
obtener más información sobre otras implementaciones del proveedor de Windows
PowerShell, consulte Diseño del proveedor de Windows PowerShell.

El proveedor de elementos de Windows PowerShell descrito en este tema obtiene


elementos de datos de una base de datos de Access. En este caso, un "elemento" es una
tabla de la base de datos de Access o una fila de una tabla.

Definición de la clase de proveedor de


elementos Windows PowerShell
Un proveedor de elementos Windows PowerShell debe definir una clase .NET que derive
de la clase base System.Management.Automation.Provider.ItemCmdletProvider. A
continuación se muestra la definición de clase para el proveedor de elementos descrito
en esta sección.

C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]

public class AccessDBProvider : ItemCmdletProvider


Tenga en cuenta que en esta definición de clase, el atributo
System.Management.Automation.Provider.CmdletProviderAttribute incluye dos
parámetros. El primer parámetro especifica un nombre descriptivo para el proveedor
que usa Windows PowerShell. El segundo parámetro especifica el Windows PowerShell
funcionalidades específicas que el proveedor expone al tiempo de ejecución de
Windows PowerShell durante el procesamiento de comandos. Para este proveedor, no
se han agregado Windows PowerShell funcionalidades específicas.

Definición de la funcionalidad base


Tal y como se describe en Design Your Windows PowerShell Provider, la clase
System.Management.Automation.Provider.DriveCmdletProvider se deriva de otras clases
que proporcionan diferentes funcionalidades de proveedor. Por lo tanto, un proveedor
de elementos Windows PowerShell debe definir toda la funcionalidad proporcionada
por esas clases.

Para obtener más información sobre cómo implementar la funcionalidad para agregar
información de inicialización específica de la sesión y para liberar recursos usados por el
proveedor, consulte Creación de un proveedor de Windows PowerShell básico. Sin
embargo, la mayoría de los proveedores, incluido el proveedor descrito aquí, pueden
usar la implementación predeterminada de esta funcionalidad que proporciona
Windows PowerShell.

Antes de que el proveedor de elementos de Windows PowerShell pueda manipular los


elementos del almacén, debe implementar los métodos de la clase base
System.Management.Automation.Provider.DriveCmdletProvider para acceder al almacén
de datos. Para obtener más información sobre cómo implementar esta clase, vea
Creating a Windows PowerShell Drive Provider.

Comprobación de la validez de la ruta de


acceso
Al buscar un elemento de datos, el entorno de ejecución de Windows PowerShell
proporciona una ruta de acceso de Windows PowerShell al proveedor, tal como se
define en la sección "Conceptos de PSPath" de Cómo funciona Windows PowerShell. Un
proveedor de elementos de Windows PowerShell debe comprobar la validez sintáctica y
semántica de cualquier ruta de acceso que se le haya pasado mediante la
implementación del método
System.Management.Automation.Provider.ItemCmdletProvider.IsValidPath. Este método
devuelve true si la ruta de acceso es válida y false , de lo contrario, . Tenga en cuenta
que la implementación de este método no debe comprobar la existencia del elemento
en la ruta de acceso, sino solo que la ruta de acceso es sintáctica y semánticamente
correcta.

Esta es la implementación del método


System.Management.Automation.Provider.ItemCmdletProvider.IsValidPath para este
proveedor. Tenga en cuenta que esta implementación llama a un método auxiliar
NormalizePath para convertir todos los separadores de la ruta de acceso a uno
uniforme.

C#

protected override bool IsValidPath(string path)


{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

Determinar si existe un elemento


Después de comprobar la ruta de acceso, el tiempo de ejecución de Windows
PowerShell debe determinar si existe un elemento de datos en esa ruta de acceso. Para
admitir este tipo de consulta, el proveedor de elementos de Windows PowerShell
implementa el método
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists. Este método
devuelve true un elemento que se encuentra en la ruta de acceso especificada y false
(valor predeterminado) en caso contrario.
Esta es la implementación del método
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists para este
proveedor. Tenga en cuenta que este método llama a los métodos auxiliares
PathIsDrive, ChunkPath y GetTable , y usa un objeto DatabaseTableInfo definido por el
proveedor.

C#

protected override bool ItemExists(string path)


{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo should
// exist for the table and then specified row number must be within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

Cosas que hay que recordar sobre la implementación de ItemExists


Las condiciones siguientes pueden aplicarse a la implementación de
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists:

Al definir la clase de proveedor, un proveedor de elementos de Windows


PowerShell puede declarar funcionalidades de proveedor de ExpandWildcards ,
Filter , Include o Exclude , desde la enumeración

System.Management.Automation.Provider.ProviderCapabilities. En estos casos, la


implementación del método
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists debe
asegurarse de que la ruta de acceso que se pasa al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.CmdletProvider.Exclude y
System.Management.Automation.Provider.CmdletProvider.Include.
La implementación de este método debe controlar cualquier forma de acceso al
elemento que pueda hacer que el elemento sea visible para el usuario. Por
ejemplo, si un usuario tiene acceso de escritura a un archivo a través del proveedor
FileSystem (proporcionado por Windows PowerShell), pero no el acceso de lectura,
el archivo sigue existiendo y
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists devuelve
true . La implementación puede requerir comprobar un elemento primario para

ver si se puede enumerar el elemento secundario.

Asociación de parámetros dinámicos al cmdlet


Test-Path
A veces, el Test-Path cmdlet que llama a
System.Management.Automation.Provider.ItemCmdletProvider.ItemExists requiere
parámetros adicionales que se especifican dinámicamente en tiempo de ejecución. Para
proporcionar estos parámetros dinámicos, el proveedor de elementos de Windows
PowerShell debe implementar el método
System.Management.Automation.Provider.ItemCmdletProvider.ItemExistsDynamicParam
eters. Este método recupera los parámetros dinámicos del elemento en la ruta de
acceso indicada y devuelve un objeto que tiene propiedades y campos con atributos de
análisis similares a una clase de cmdlet o a un objeto
System.Management.Automation.RuntimeDefinedParameterDictionary. El tiempo de
ejecución de Windows PowerShell usa el objeto devuelto para agregar los parámetros al
Test-Path cmdlet .
Este proveedor de elementos Windows PowerShell no implementa este método. Sin
embargo, el código siguiente es la implementación predeterminada de este método.

Recuperación de un elemento
Para recuperar un elemento, el proveedor de elementos Windows PowerShell debe
invalidar el método
System.Management.Automation.Provider.ItemCmdletProvider.GetItem para admitir
llamadas desde el Get-Item cmdlet. Este método escribe el elemento mediante el
método System.Management.Automation.Provider.CmdletProvider.WriteItemObject.

Esta es la implementación del método


System.Management.Automation.Provider.ItemCmdletProvider.GetItem para este
proveedor. Tenga en cuenta que este método usa los métodos auxiliares GetTable y
GetRow para recuperar elementos que son tablas de la base de datos de Access o filas
de una tabla de datos.

C#

protected override void GetItem(string path)


{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // GetItem

Cosas que hay que recordar sobre la implementación de GetItem


Las condiciones siguientes pueden aplicarse a una implementación de
System.Management.Automation.Provider.ItemCmdletProvider.GetItem:

Al definir la clase de proveedor, un proveedor de elementos de Windows


PowerShell puede declarar funcionalidades de proveedor de ExpandWildcards ,
Filter , Include o Exclude , desde la enumeración
System.Management.Automation.Provider.ProviderCapabilities. En estos casos, la
implementación de
System.Management.Automation.Provider.ItemCmdletProvider.GetItem debe
asegurarse de que la ruta de acceso pasada al método cumple esos requisitos.
Para ello, el método debe tener acceso a la propiedad adecuada, por ejemplo, las
propiedades System.Management.Automation.Provider.CmdletProvider.Exclude y
System.Management.Automation.Provider.CmdletProvider.Include.

De forma predeterminada, las invalidaciones de este método no deben recuperar


objetos que generalmente están ocultos del usuario a menos que la propiedad
System.Management.Automation.Provider.CmdletProvider.Force esté establecida
true en . Por ejemplo, el método

System.Management.Automation.Provider.ItemCmdletProvider.GetItem del
proveedor FileSystem comprueba la propiedad
System.Management.Automation.Provider.CmdletProvider.Force antes de intentar
llamar a
System.Management.Automation.Provider.CmdletProvider.WriteItemObject en
busca de archivos ocultos o del sistema.

Asociación de parámetros dinámicos al cmdlet


Get-Item
A veces, el Get-Item cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de elementos de Windows PowerShell debe implementar el método
System.Management.Automation.Provider.ItemCmdletProvider.GetItemDynamicParamet
ers. Este método recupera los parámetros dinámicos del elemento en la ruta de acceso
indicada y devuelve un objeto que tiene propiedades y campos con atributos de análisis
similares a una clase de cmdlet o a un objeto
System.Management.Automation.RuntimeDefinedParameterDictionary. El tiempo de
ejecución de Windows PowerShell usa el objeto devuelto para agregar los parámetros al
Get-Item cmdlet .

Este proveedor no implementa este método. Sin embargo, el código siguiente es la


implementación predeterminada de este método.

Establecer un elemento
Para establecer un elemento, el proveedor de elementos de Windows PowerShell debe
invalidar el método
System.Management.Automation.Provider.ItemCmdletProvider.SetItem para admitir
llamadas desde el Set-Item cmdlet . Este método establece el valor del elemento en la
ruta de acceso especificada.

Este proveedor no proporciona una invalidación para el método


System.Management.Automation.Provider.ItemCmdletProvider.SetItem. Sin embargo, lo
siguiente es la implementación predeterminada de este método.

Cosas que hay que recordar sobre la implementación de SetItem

Las condiciones siguientes pueden aplicarse a la implementación de


System.Management.Automation.Provider.ItemCmdletProvider.SetItem:

Al definir la clase de proveedor, un proveedor de elementos de Windows


PowerShell puede declarar funcionalidades de proveedor de ExpandWildcards ,
Filter , Include o Exclude , desde la enumeración

System.Management.Automation.Provider.ProviderCapabilities. En estos casos, la


implementación de
System.Management.Automation.Provider.ItemCmdletProvider.SetItem debe
asegurarse de que la ruta de acceso pasada al método cumple esos requisitos.
Para ello, el método debe tener acceso a la propiedad adecuada, por ejemplo, las
propiedades System.Management.Automation.Provider.CmdletProvider.Exclude y
System.Management.Automation.Provider.CmdletProvider.Include.

De forma predeterminada, las invalidaciones de este método no deben establecer


ni escribir objetos ocultos para el usuario a menos que la propiedad
System.Management.Automation.Provider.CmdletProvider.Force esté establecida
true en . Se debe enviar un error al método
System.Management.Automation.Provider.CmdletProvider.WriteError si la ruta de
acceso representa un elemento oculto y
System.Management.Automation.Provider.CmdletProvider.Force está establecido
false en .

La implementación del método


System.Management.Automation.Provider.ItemCmdletProvider.SetItem debe
llamar al método
System.Management.Automation.Provider.CmdletProvider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Este método se usa para confirmar la ejecución de una operación cuando se realiza
un cambio en el almacén de datos, por ejemplo, la eliminación de archivos. El
método System.Management.Automation.Provider.CmdletProvider.ShouldProcess
envía el nombre del recurso que se va a cambiar al usuario, con el tiempo de
ejecución de Windows PowerShell teniendo en cuenta cualquier configuración de
línea de comandos o variables de preferencia para determinar qué se debe
mostrar.

Después de llamar al método


System.Management.Automation.Provider.CmdletProvider.ShouldProcess, true el
método System.Management.Automation.Provider.ItemCmdletProvider.SetItem
debe llamar al método
System.Management.Automation.Provider.CmdletProvider.ShouldContinue. Este
método envía un mensaje al usuario para permitir que los comentarios
comprueben si se debe continuar la operación. La llamada a
System.Management.Automation.Provider.CmdletProvider.ShouldContinue
permite una comprobación adicional de las modificaciones del sistema
potencialmente peligrosas.

Recuperación de parámetros dinámicos para


SetItem
A veces, el Set-Item cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de elementos de Windows PowerShell debe implementar el método
System.Management.Automation.Provider.ItemCmdletProvider.SetItemDynamicParamet
ers. Este método recupera los parámetros dinámicos del elemento en la ruta de acceso
indicada y devuelve un objeto que tiene propiedades y campos con atributos de análisis
similares a una clase de cmdlet o a un objeto
System.Management.Automation.RuntimeDefinedParameterDictionary. El tiempo de
ejecución de Windows PowerShell usa el objeto devuelto para agregar los parámetros al
Set-Item cmdlet .
Este proveedor no implementa este método. Sin embargo, el código siguiente es la
implementación predeterminada de este método.

Borrar un elemento
Para borrar un elemento, el proveedor de elementos de Windows PowerShell
implementa el método
System.Management.Automation.Provider.ItemCmdletProvider.ClearItem para admitir
llamadas desde el Clear-Item cmdlet . Este método borra el elemento de datos en la
ruta de acceso especificada.

Este proveedor no implementa este método. Sin embargo, el código siguiente es la


implementación predeterminada de este método.

Cosas que hay que recordar sobre la implementación de ClearItem


Las condiciones siguientes pueden aplicarse a una implementación de
System.Management.Automation.Provider.ItemCmdletProvider.ClearItem:

Al definir la clase de proveedor, un proveedor de elementos de Windows


PowerShell puede declarar funcionalidades de proveedor de ExpandWildcards ,
Filter , Include o Exclude , desde la enumeración
System.Management.Automation.Provider.ProviderCapabilities. En estos casos, la
implementación de
System.Management.Automation.Provider.ItemCmdletProvider.ClearItem debe
asegurarse de que la ruta de acceso que se pasa al método cumple esos requisitos.
Para ello, el método debe tener acceso a la propiedad adecuada, por ejemplo, las
propiedades System.Management.Automation.Provider.CmdletProvider.Exclude y
System.Management.Automation.Provider.CmdletProvider.Include.

De forma predeterminada, las invalidaciones de este método no deben establecer


ni escribir objetos ocultos para el usuario a menos que la propiedad
System.Management.Automation.Provider.CmdletProvider.Force esté establecida
true en . Se debe enviar un error al método

System.Management.Automation.Provider.CmdletProvider.WriteError si la ruta de
acceso representa un elemento que está oculto del usuario y
System.Management.Automation.Provider.CmdletProvider.Force está establecido
false en .

La implementación del método


System.Management.Automation.Provider.ItemCmdletProvider.SetItem debe
llamar al método
System.Management.Automation.Provider.CmdletProvider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Este método se usa para confirmar la ejecución de una operación cuando se realiza
un cambio en el almacén de datos, por ejemplo, la eliminación de archivos. El
método System.Management.Automation.Provider.CmdletProvider.ShouldProcess
envía el nombre del recurso que se va a cambiar al usuario, con el tiempo de
ejecución de Windows PowerShell y controla cualquier configuración de línea de
comandos o variables de preferencia para determinar qué se debe mostrar.

Después de llamar al método


System.Management.Automation.Provider.CmdletProvider.ShouldProcess, true el
método System.Management.Automation.Provider.ItemCmdletProvider.SetItem
debe llamar al método
System.Management.Automation.Provider.CmdletProvider.ShouldContinue. Este
método envía un mensaje al usuario para permitir que los comentarios
comprueben si se debe continuar la operación. La llamada a
System.Management.Automation.Provider.CmdletProvider.ShouldContinue
permite una comprobación adicional de las modificaciones del sistema
potencialmente peligrosas.

Recuperación de parámetros dinámicos para


ClearItem
A veces, el Clear-Item cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de elementos de Windows PowerShell debe implementar el método
System.Management.Automation.Provider.ItemCmdletProvider.ClearItemDynamicParam
eters. Este método recupera los parámetros dinámicos del elemento en la ruta de
acceso indicada y devuelve un objeto que tiene propiedades y campos con atributos de
análisis similares a una clase de cmdlet o a un objeto
System.Management.Automation.RuntimeDefinedParameterDictionary. El tiempo de
ejecución de Windows PowerShell usa el objeto devuelto para agregar los parámetros al
Clear-Item cmdlet .

Este proveedor de elementos no implementa este método. Sin embargo, el código


siguiente es la implementación predeterminada de este método.
Realización de una acción predeterminada para
un elemento
Un proveedor de elementos Windows PowerShell puede implementar el método
System.Management.Automation.Provider.ItemCmdletProvider.InvokeDefaultAction
para admitir llamadas desde el Invoke-Item cmdlet , lo que permite al proveedor
realizar una acción predeterminada para el elemento en la ruta de acceso especificada.
Por ejemplo, el proveedor FileSystem podría usar este método para llamar a
ShellExecute para un elemento específico.

Este proveedor no implementa este método. Sin embargo, el código siguiente es la


implementación predeterminada de este método.

Aspectos que hay que recordar sobre la implementación de


InvokeDefaultAction

Las condiciones siguientes pueden aplicarse a una implementación de


System.Management.Automation.Provider.ItemCmdletProvider.InvokeDefaultAction:

Al definir la clase de proveedor, un proveedor de elementos de Windows


PowerShell puede declarar funcionalidades de proveedor de ExpandWildcards ,
Filter , Include o Exclude , desde la enumeración

System.Management.Automation.Provider.ProviderCapabilities. En estos casos, la


implementación de
System.Management.Automation.Provider.ItemCmdletProvider.InvokeDefaultActio
n debe asegurarse de que la ruta de acceso pasada al método cumple esos
requisitos. Para ello, el método debe tener acceso a la propiedad adecuada, por
ejemplo, las propiedades
System.Management.Automation.Provider.CmdletProvider.Exclude y
System.Management.Automation.Provider.CmdletProvider.Include.

De forma predeterminada, las invalidaciones de este método no deben establecer


ni escribir objetos ocultos del usuario a menos que la propiedad
System.Management.Automation.Provider.CmdletProvider.Force esté establecida
true en . Se debe enviar un error al método

System.Management.Automation.Provider.CmdletProvider.WriteError si la ruta de
acceso representa un elemento que está oculto del usuario y
System.Management.Automation.Provider.CmdletProvider.Force está establecido
false en .
Recuperación de parámetros dinámicos para
InvokeDefaultAction
A veces, el Invoke-Item cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de elementos de Windows PowerShell debe implementar el método
System.Management.Automation.Provider.ItemCmdletProvider.InvokeDefaultActionDyn
amicParameters. Este método recupera los parámetros dinámicos del elemento en la
ruta de acceso indicada y devuelve un objeto que tiene propiedades y campos con
atributos de análisis similares a una clase de cmdlet o a un objeto
System.Management.Automation.RuntimeDefinedParameterDictionary. El tiempo de
ejecución de Windows PowerShell usa el objeto devuelto para agregar los parámetros
dinámicos al Invoke-Item cmdlet .

Este proveedor de elementos no implementa este método. Sin embargo, el código


siguiente es la implementación predeterminada de este método.

Implementación de clases y métodos auxiliares


Este proveedor de elementos implementa varios métodos auxiliares y clases que usan
los métodos de invalidación pública definidos por Windows PowerShell. El código de
estos métodos y clases auxiliares se muestra en la sección Ejemplo de código .

NormalizePath (método)
Este proveedor de elementos implementa un método auxiliar normalizePath para
asegurarse de que la ruta de acceso tenga un formato coherente. El formato
especificado usa una barra diagonal inversa ( \ ) como separador.

Método PathIsDrive
Este proveedor de elementos implementa un método auxiliar PathIsDrive para
determinar si la ruta de acceso especificada es realmente el nombre de la unidad.

Método ChunkPath
Este proveedor de elementos implementa un método auxiliar chunkPath que divide la
ruta de acceso especificada para que el proveedor pueda identificar sus elementos
individuales. Devuelve una matriz compuesta por los elementos de ruta de acceso.
Método GetTable
Este proveedor de elementos implementa el método auxiliar GetTables que devuelve un
objeto DatabaseTableInfo que representa información sobre la tabla especificada en la
llamada.

Método GetRow
El método System.Management.Automation.Provider.ItemCmdletProvider.GetItem de
este proveedor de elementos llama al método auxiliar GetRows. Este método auxiliar
recupera un objeto DatabaseRowInfo que representa información sobre la fila
especificada en la tabla.

Clase DatabaseTableInfo
Este proveedor de elementos define una clase DatabaseTableInfo que representa una
colección de información en una tabla de datos de la base de datos. Esta clase es similar
a la clase System.IO.Directoryinfo .

El proveedor de elementos de ejemplo define un método DatabaseTableInfo.GetTables


que devuelve una colección de objetos de información de tabla que definen las tablas
de la base de datos. Este método incluye un bloque try/catch para asegurarse de que
cualquier error de base de datos se muestra como una fila con cero entradas.

Clase DatabaseRowInfo
Este proveedor de elementos define la clase auxiliar DatabaseRowInfo que representa
una fila de una tabla de la base de datos. Esta clase es similar a la clase
System.IO.FileInfo .

El proveedor de ejemplo define un método DatabaseRowInfo.GetRows para devolver


una colección de objetos de información de fila para la tabla especificada. Este método
incluye un bloque try/catch para interceptar excepciones. Los errores no generarán
ninguna información de fila.

Código de ejemplo
Para obtener código de ejemplo completo, consulte Ejemplo de código
accessDbProviderSample03.
Definición de tipos de objeto y formato
Al escribir un proveedor, puede ser necesario agregar miembros a objetos existentes o
definir nuevos objetos. Cuando termine, cree un archivo Types que Windows PowerShell
pueda usar para identificar los miembros del objeto y un archivo Format que defina
cómo se muestra el objeto. Para obtener más información, vea Extender tipos de objeto
y formato.

Creación del proveedor de Windows


PowerShell
Consulte Registro de cmdlets, proveedores y aplicaciones host.

Prueba del proveedor de Windows PowerShell


Cuando este proveedor de elementos de Windows PowerShell está registrado con
Windows PowerShell, solo puede probar la funcionalidad básica y de unidad del
proveedor. Para probar la manipulación de elementos, también debe implementar la
funcionalidad de contenedor descrita en Implementación de un proveedor de Windows
PowerShell contenedor.

Consulte también
Windows PowerShell SDK
Guía del programador de Windows PowerShell
Creación de proveedores de Windows PowerShell
Diseño del proveedor de Windows PowerShell
Extensión de tipos de objeto y formato
Cómo funciona Windows PowerShell
Creación de un proveedor de Windows PowerShell contenedor
Creación de un proveedor de Windows PowerShell drive
Registro de cmdlets, proveedores y aplicaciones host
Creación de un proveedor de
contenedores de Windows PowerShell
Artículo • 08/11/2021

En este tema se describe cómo crear un proveedor de Windows PowerShell que puede
funcionar en almacenes de datos de varias capas. Para este tipo de almacén de datos, el
nivel superior del almacén contiene los elementos raíz y cada nivel posterior se conoce
como un nodo de elementos secundarios. Al permitir que el usuario trabaje en estos
nodos secundarios, un usuario puede interactuar jerárquicamente a través del almacén
de datos.

Los proveedores que pueden trabajar en almacenes de datos de varios niveles se


conocen como proveedores Windows PowerShell contenedores. Sin embargo, tenga en
cuenta que Windows PowerShell proveedor de contenedores solo se puede usar cuando
hay un contenedor (sin contenedores anidados) con elementos en él. Si hay
contenedores anidados, debe implementar un proveedor de Windows PowerShell
navegación. Para obtener más información sobre cómo implementar Windows
PowerShell de navegación, vea Creating a Windows PowerShell Navigation Provider.

7 Nota

Puede descargar el archivo de origen de C# (AccessDBSampleProvider04.cs) para


este proveedor mediante el Kit de desarrollo de software de Microsoft Windows
para Windows Vista y .NET Framework 3.0 Runtime Components. Para obtener
instrucciones de descarga, consulte How to Install Windows PowerShell and
Download the Windows PowerShell SDK. Los archivos de origen descargados
están disponibles en el <PowerShell Samples> directorio . Para obtener más
información sobre otras implementaciones Windows PowerShell proveedor de
recursos, vea Designing Your Windows PowerShell Provider.

El Windows PowerShell contenedor descrito aquí define la base de datos como su único
contenedor, con las tablas y filas de la base de datos definidas como elementos del
contenedor.

U Precaución

Tenga en cuenta que este diseño supone una base de datos que tiene un campo
con el identificador de nombre y que el tipo del campo es LongInteger.
Definir una clase Windows PowerShell
container provider
Un Windows PowerShell contenedor debe definir una clase .NET que se derive de la
clase base System.Management.Automation.Provider.Containercmdletprovider. Esta es
la definición de clase para el proveedor Windows PowerShell contenedor descrito en
esta sección.

C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : ContainerCmdletProvider

Observe que en esta definición de clase, el atributo


System.Management.Automation.Provider.Cmdletproviderattribute incluye dos
parámetros. El primer parámetro especifica un nombre descriptivo para el proveedor
que usa Windows PowerShell. El segundo parámetro especifica las Windows PowerShell
específicas que el proveedor expone al entorno de ejecución Windows PowerShell
tiempo de ejecución durante el procesamiento de comandos. Para este proveedor, no
hay Windows PowerShell funcionalidades específicas que se agregan.

Definición de la funcionalidad base


Como se describe en Diseño del proveedor de Windows PowerShell, la clase
System.Management.Automation.Provider.Containercmdletprovider se deriva de otras
clases que proporcionan funcionalidad de proveedor diferente. Por Windows PowerShell
proveedor de contenedores, es necesario definir toda la funcionalidad proporcionada
por esas clases.

Para implementar la funcionalidad para agregar información de inicialización específica


de la sesión y para liberar los recursos que usa el proveedor, vea Creating a Basic
Windows PowerShell Provider. Sin embargo, la mayoría de los proveedores (incluido el
proveedor descrito aquí) pueden usar la implementación predeterminada de esta
funcionalidad proporcionada por Windows PowerShell.

Para obtener acceso al almacén de datos, el proveedor debe implementar los métodos
de la clase base System.Management.Automation.Provider.Drivecmdletprovider. Para
obtener más información sobre la implementación de estos métodos, vea Creating an
Windows PowerShell Drive Provider.
Para manipular los elementos de un almacén de datos, como obtener, establecer y
borrar elementos, el proveedor debe implementar los métodos proporcionados por la
clase base System.Management.Automation.Provider.Itemcmdletprovider. Para obtener
más información sobre cómo implementar estos métodos, vea Creating an Windows
PowerShell Item Provider.

Recuperar elementos secundarios


Para recuperar un elemento secundario, el proveedor de contenedores Windows
PowerShell debe invalidar el método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems* para
admitir llamadas desde el Get-ChildItem cmdlet . Este método recupera elementos
secundarios del almacén de datos y los escribe en la canalización como objetos . Si se
especifica el parámetro del cmdlet , el método recupera todos los secundarios
independientemente del recurse nivel en el que se encuentran. Si no recurse se
especifica el parámetro , el método recupera solo un único nivel de secundarios.

Esta es la implementación del método


System.Management.Automation.Provider.Containercmdletprovider.Getchilditems* para
este proveedor. Tenga en cuenta que este método recupera los elementos secundarios
de todas las tablas de base de datos cuando la ruta de acceso indica la base de datos de
Access y recupera los elementos secundarios de las filas de esa tabla si la ruta de acceso
indica una tabla de datos.

C#

protected override void GetChildItems(string path, bool recurse)


{
// If path represented is a drive then the children in the path are
// tables. Hence all tables in the drive represented will have to be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name, recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator + row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row, hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator + row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildItems

Cosas que debe recordar sobre la implementación de


GetChildItems
Se pueden aplicar las condiciones siguientes a la implementación de
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*:

Al definir la clase de proveedor, un proveedor de contenedores de Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

La implementación de este método debe tener en cuenta cualquier forma de


acceso al elemento que pueda hacer que el elemento sea visible para el usuario.
Por ejemplo, si un usuario tiene acceso de escritura a un archivo a través del
proveedor FileSystem (proporcionado por Windows PowerShell), pero no acceso
de lectura, el archivo sigue existiendo y
System.Management.Automation.Provider.Itemcmdletprovider.Itemexists*
devuelve true . La implementación puede requerir la comprobación de un
elemento primario para ver si se puede enumerar el elemento secundario.

Al escribir varios elementos, el método


System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
puede tardar algún tiempo. Puede diseñar el proveedor para escribir los elementos
mediante el método
System.Management.Automation.Provider.Cmdletprovider.Writeitemobject* de
uno en uno. Con esta técnica se presentarán los elementos al usuario en una
secuencia.

La implementación de
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
es responsable de evitar la recursividad infinita cuando hay vínculos circulares y
otros. Se debe crear una excepción de terminación adecuada para reflejar dicha
condición.

Adjuntar parámetros dinámicos al cmdlet Get-


ChildItem.
A veces, el cmdlet que llama a Get-ChildItem
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
requiere parámetros adicionales que se especifican dinámicamente en tiempo de
ejecución. Para proporcionar estos parámetros dinámicos, Windows PowerShell
proveedor de contenedores debe implementar el método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditemsdyna
micparameters*. Este método recupera parámetros dinámicos para el elemento en la
ruta de acceso indicada y devuelve un objeto que tiene propiedades y campos con
atributos de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El Windows
PowerShell tiempo de ejecución usa el objeto devuelto para agregar los parámetros al
Get-ChildItem cmdlet .
Este Windows PowerShell proveedor de contenedores no implementa este método. Sin
embargo, el código siguiente es la implementación predeterminada de este método.

Recuperar nombres de elementos secundarios


Para recuperar los nombres de los elementos secundarios, el proveedor de
contenedores de Windows PowerShell debe invalidar el método
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames*
para admitir llamadas desde el cmdlet cuando se especifica su Get-ChildItem Name
parámetro . Este método recupera los nombres de los elementos secundarios para la
ruta de acceso especificada o los nombres de elementos secundarios para todos los
contenedores si se especifica returnAllContainers el parámetro del cmdlet . Un nombre
secundario es la parte hoja de una ruta de acceso. Por ejemplo, el nombre secundario
de la ruta de acceso c:\windows\system32\abc.dll es "abc.dll". El nombre secundario del
directorio c:\windows\system32 es "system32".

Esta es la implementación del método


System.Management.Automation.Provider.Containercmdletprovider.Getchildnames*
para este proveedor. Observe que el método recupera nombres de tabla si la ruta de
acceso especificada indica los números de fila y base de datos de Access si la ruta de
acceso indica una tabla.

C#

protected override void GetChildNames(string path,


ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row, hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);

WriteItemObject(row.RowNumber, path, false);


}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildNames

Cosas que debe recordar sobre la implementación de


GetChildNames

Se pueden aplicar las condiciones siguientes a la implementación de


System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*:

Al definir la clase de proveedor, un proveedor de contenedores de Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

7 Nota

Se produce una excepción a esta regla returnAllContainers cuando se


especifica el parámetro del cmdlet . En este caso, el método debe recuperar
cualquier nombre secundario para un contenedor, incluso si no coincide con
los valores de las propiedades
System.Management.Automation.Provider.Cmdletprovider.Filter*,
System.Management.Automation.Provider.Cmdletprovider.Include*o
System.Management.Automation.Provider.Cmdletprovider.Exclude*.

De forma predeterminada, las invalidaciones de este método no deben recuperar


nombres de objetos que generalmente están ocultos para el usuario a menos que
se especifique la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force*. Si la ruta de
acceso especificada indica un contenedor, no se requiere la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force*.

La implementación de
System.Management.Automation.Provider.Containercmdletprovider.Getchildnames
* es responsable de evitar la recursividad infinita cuando hay vínculos circulares y
otros. Se debe crear una excepción de terminación adecuada para reflejar dicha
condición.

Adjuntar parámetros dinámicos al cmdlet Get-


ChildItem (nombre)
A Get-ChildItem veces, el cmdlet (con Name el parámetro ) requiere parámetros
adicionales que se especifican dinámicamente en tiempo de ejecución. Para
proporcionar estos parámetros dinámicos, Windows PowerShell proveedor de
contenedores debe implementar el método
System.Management.Automation.Provider.Containercmdletprovider.Getchildnamesdyna
micparameters*. Este método recupera los parámetros dinámicos del elemento en la
ruta de acceso indicada y devuelve un objeto que tiene propiedades y campos con
atributos de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El Windows
PowerShell tiempo de ejecución usa el objeto devuelto para agregar los parámetros al
Get-ChildItem cmdlet .

Este proveedor no implementa este método. Sin embargo, el código siguiente es la


implementación predeterminada de este método.

Cambiar el nombre de los elementos


Para cambiar el nombre de un elemento, un proveedor de contenedores Windows
PowerShell debe invalidar el método
System.Management.Automation.Provider.Containercmdletprovider.Renameitem* para
admitir llamadas desde el Rename-Item cmdlet . Este método cambia el nombre del
elemento en la ruta de acceso especificada al nuevo nombre proporcionado. El nuevo
nombre siempre debe ser relativo al elemento primario (contenedor).

Este proveedor no invalida el método


System.Management.Automation.Provider.Containercmdletprovider.Renameitem*. Sin
embargo, lo siguiente es la implementación predeterminada.

Cosas que debe recordar sobre la implementación de RenameItem

Se pueden aplicar las condiciones siguientes a la implementación de


System.Management.Automation.Provider.Containercmdletprovider.Renameitem*:

Al definir la clase de proveedor, un proveedor de contenedores de Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

El método
System.Management.Automation.Provider.Containercmdletprovider.Renameitem*
está pensado solo para la modificación del nombre de un elemento y no para las
operaciones de movimiento. La implementación del método debe escribir un error
si el parámetro contiene separadores de ruta de acceso o puede provocar que el
elemento cambie newName su ubicación primaria.

De forma predeterminada, las invalidaciones de este método no deben cambiar el


nombre de los objetos a menos que se especifique la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force*. Si la ruta de
acceso especificada indica un contenedor, no se requiere la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force*.

La implementación del método


System.Management.Automation.Provider.Containercmdletprovider.Renameitem*
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Este método se usa para confirmar la ejecución de una operación cuando se realiza
un cambio en el estado del sistema, por ejemplo, cambiar el nombre de los
archivos. System.Management.Automation.Provider.Cmdletprovider.ShouldProcess
envía el nombre del recurso que se va a cambiar al usuario, teniendo en cuenta el
runtime de Windows PowerShell cualquier configuración de línea de comandos o
variables de preferencia para determinar lo que se debe mostrar.

Después de que la llamada a


System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva
, el método true
System.Management.Automation.Provider.Containercmdletprovider.Renameitem*
debe llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue. Este
método envía un mensaje de confirmación al usuario para permitir que los
comentarios adicionales digan si se debe continuar la operación. Un proveedor
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue como
una comprobación adicional de las modificaciones potencialmente peligrosas del
sistema.

Adjuntar parámetros dinámicos al cmdlet


Rename-Item
A veces, Rename-Item el cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
Windows PowerShell proveedor de contenedores debe implementar el método
System.Management.Automation.Provider.Containercmdletprovider.Renameitemdynami
cparameters*. Este método recupera los parámetros del elemento en la ruta de acceso
indicada y devuelve un objeto que tiene propiedades y campos con atributos de análisis
similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El Windows
PowerShell tiempo de ejecución usa el objeto devuelto para agregar los parámetros al
Rename-Item cmdlet .

Este proveedor de contenedores no implementa este método. Sin embargo, el código


siguiente es la implementación predeterminada de este método.
Crear nuevos elementos
Para crear nuevos elementos, un proveedor de contenedores debe implementar el
método System.Management.Automation.Provider.Containercmdletprovider.Newitem*
para admitir llamadas desde el New-Item cmdlet . Este método crea un elemento de
datos ubicado en la ruta de acceso especificada. El type parámetro del cmdlet contiene
el tipo definido por el proveedor para el nuevo elemento. Por ejemplo, el proveedor
FileSystem usa un type parámetro con un valor de "archivo" o "directorio". El
newItemValue parámetro del cmdlet especifica un valor específico del proveedor para el

nuevo elemento.

Esta es la implementación del método


System.Management.Automation.Provider.Containercmdletprovider.Newitem* para este
proveedor.

C#

protected override void NewItem( string path, string type, object


newItemValue )
{
// Create the new item here after
// performing necessary validations
//
// WriteItemObject(newItemValue, path, false);

// Example
//
// if (ShouldProcess(path, "new item"))
// {
// // Create a new item and then call WriteObject
// WriteObject(newItemValue, path, false);
// }

} // NewItem

C#

{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

Cosas que debe recordar sobre la implementación de NewItem


Se pueden aplicar las condiciones siguientes a la implementación de
System.Management.Automation.Provider.Containercmdletprovider.Newitem*:

El método
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
debe realizar una comparación sin diferenciar mayúsculas de minúsculas de la
cadena pasada en el type parámetro . También debe permitir coincidencias menos
ambiguas. Por ejemplo, para los tipos "file" y "directory", solo se requiere la
primera letra para eliminar la ambigüedad. Si el parámetro indica un tipo que el
proveedor no puede crear, el método type
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
debe escribir una excepción ArgumentException con un mensaje que indique los
tipos que puede crear el proveedor.

Para el parámetro , se recomienda la implementación del método newItemValue


System.Management.Automation.Provider.Containercmdletprovider.Newitem*
para aceptar cadenas como mínimo. También debe aceptar el tipo de objeto
recuperado por el método
System.Management.Automation.Provider.Itemcmdletprovider.Getitem* para la
misma ruta de acceso. El método
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
puede usar el método
System.Management.Automation.Languageprimitives.Convertto* para convertir
tipos al tipo deseado.

La implementación del método


System.Management.Automation.Provider.Containercmdletprovider.Newitem*
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Después de que la llamada a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva
true, el método
System.Management.Automation.Provider.Containercmdletprovider.Newitem*
debe llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue como
una comprobación adicional de las modificaciones potencialmente peligrosas del
sistema.

Adjuntar parámetros dinámicos al cmdlet New-


Item
A veces, New-Item el cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de contenedores debe implementar el método
System.Management.Automation.Provider.Containercmdletprovider.Newitemdynamicpa
rameters*. Este método recupera los parámetros del elemento en la ruta de acceso
indicada y devuelve un objeto que tiene propiedades y campos con atributos de análisis
similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El Windows
PowerShell tiempo de ejecución usa el objeto devuelto para agregar los parámetros al
New-Item cmdlet .

Este proveedor no implementa este método. Sin embargo, el código siguiente es la


implementación predeterminada de este método.

Quitar elementos
Para quitar elementos, el proveedor Windows PowerShell debe invalidar el método
System.Management.Automation.Provider.Containercmdletprovider.Removeitem* para
admitir llamadas desde el Remove-Item cmdlet . Este método elimina un elemento del
almacén de datos en la ruta de acceso especificada. Si el parámetro del cmdlet se
establece en , el método quita todos los recurse Remove-Item elementos secundarios
true independientemente de su nivel. Si el parámetro se establece en false , el

método quita solo un elemento en la ruta de acceso especificada.

Este proveedor no admite la eliminación de elementos. Sin embargo, el código siguiente


es la implementación predeterminada de
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*.

Cosas que debe recordar sobre la implementación de RemoveItem


Se pueden aplicar las condiciones siguientes a la implementación de
System.Management.Automation.Provider.Containercmdletprovider.Newitem*:
Al definir la clase de proveedor, un proveedor de contenedores de Windows
PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

De forma predeterminada, las invalidaciones de este método no deben quitar


objetos a menos que la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force* esté establecida
en true. Si la ruta de acceso especificada indica un contenedor, no se requiere la
propiedad System.Management.Automation.Provider.Cmdletprovider.Force*.

La implementación de
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
es responsable de evitar la recursividad infinita cuando hay vínculos circulares y
otros tipos. Se debe crear una excepción de terminación adecuada para reflejar
dicha condición.

La implementación del método


System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Después de que la llamada a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva
, el método true
System.Management.Automation.Provider.Containercmdletprovider.Removeitem*
debe llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue como
una comprobación adicional de las modificaciones potencialmente peligrosas del
sistema.

Adjuntar parámetros dinámicos al cmdlet


Remove-Item
A veces, Remove-Item el cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de contenedores debe implementar el método
System.Management.Automation.Provider.Containercmdletprovider.Removeitemdynami
cparameters* para controlar estos parámetros. Este método recupera los parámetros
dinámicos del elemento en la ruta de acceso indicada y devuelve un objeto que tiene
propiedades y campos con atributos de análisis similares a una clase de cmdlet o un
objeto System.Management.Automation.Runtimedefinedparameterdictionary. El
Windows PowerShell tiempo de ejecución usa el objeto devuelto para agregar los
parámetros al Remove-Item cmdlet .

Este proveedor de contenedores no implementa este método. Sin embargo, el código


siguiente es la implementación predeterminada de
System.Management.Automation.Provider.Containercmdletprovider.Removeitemdynami
cparameters*.

Consulta de elementos secundarios


Para comprobar si existen elementos secundarios en la ruta de acceso especificada, el
proveedor de contenedores de Windows PowerShell debe invalidar el método
System.Management.Automation.Provider.Containercmdletprovider.Haschilditems*. Este
método devuelve true si el elemento tiene elementos secundarios y, de lo false
contrario, devuelve . Para una ruta de acceso nula o vacía, el método considera que los
elementos del almacén de datos son secundarios y devuelve true .

Esta es la invalidación del método


System.Management.Automation.Provider.Containercmdletprovider.Haschilditems*. Si
hay más de dos partes de ruta de acceso creadas por el método auxiliar ChunkPath, el
método devuelve , ya que solo se definen un contenedor de base de datos false y un
contenedor de tablas. Para obtener más información sobre este método auxiliar, vea el
método ChunkPath que se describe en Creación de un Windows PowerShell de
elementos .

C#

protected override bool HasChildItems( string path )


{
return false;
} // HasChildItems

C#
ErrorCategory.InvalidOperation, tableName));
}

return results;

Cosas que debe recordar sobre la implementación de


HasChildItems

Se pueden aplicar las condiciones siguientes a la implementación de


System.Management.Automation.Provider.Containercmdletprovider.Haschilditems*:

Si el proveedor de contenedores expone una raíz que contiene puntos de montaje


interesantes, la implementación del método
System.Management.Automation.Provider.Containercmdletprovider.Haschilditems*
debe devolver cuando se pasa una cadena nula o vacía para la ruta true de
acceso.

Copiar elementos
Para copiar elementos, el proveedor de contenedores debe implementar el método
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem para
admitir llamadas desde el Copy-Item cmdlet . Este método copia un elemento de datos
de la ubicación indicada por el parámetro del cmdlet en la path ubicación indicada por
el parámetro copyPath . Si se recurse especifica el parámetro , el método copia todos
los subcontenedores. Si no se especifica el parámetro , el método copia solo un único
nivel de elementos.

Este proveedor no implementa este método. Sin embargo, el código siguiente es la


implementación predeterminada de
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem.

Cosas que debe recordar sobre la implementación de CopyItem

Se pueden aplicar las condiciones siguientes a la implementación de


System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem:

Al definir la clase de proveedor, un proveedor de contenedores de Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Containercmdletprovider.Getchilditems*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

De forma predeterminada, las invalidaciones de este método no deben copiar


objetos sobre objetos existentes a menos que la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force* esté establecida
en true . Por ejemplo, el proveedor FileSystem no copiará c:\temp\abc.txt sobre
un archivo c:\abc.txt existente a menos que la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force* esté establecida
en true . Si la ruta de acceso especificada en el parámetro existe e indica un
contenedor, no se requiere la propiedad copyPath
System.Management.Automation.Provider.Cmdletprovider.Force*. En este caso,
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
debe copiar el elemento indicado por el parámetro en el contenedor indicado por
el parámetro como path copyPath secundario.

La implementación de
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem es
responsable de evitar la recursividad infinita cuando hay vínculos circulares y otros.
Se debe crear una excepción de terminación adecuada para reflejar dicha
condición.

La implementación del método


System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Después de que la llamada a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva
true, el método
System.Management.Automation.Provider.ContainerCmdletProvider.CopyItem
debe llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue como
una comprobación adicional de las modificaciones potencialmente peligrosas del
sistema. Para obtener más información sobre cómo llamar a estos métodos, vea
Cambiar el nombre de los elementos.
Adjuntar parámetros dinámicos al cmdlet
Copy-Item
A veces, Copy-Item el cmdlet requiere parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de contenedores Windows PowerShell debe implementar el método
System.Management.Automation.Provider.Containercmdletprovider.Copyitemdynamicp
arameters* para controlar estos parámetros. Este método recupera los parámetros del
elemento en la ruta de acceso indicada y devuelve un objeto que tiene propiedades y
campos con atributos de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El Windows
PowerShell tiempo de ejecución usa el objeto devuelto para agregar los parámetros al
Copy-Item cmdlet .

Este proveedor no implementa este método. Sin embargo, el código siguiente es la


implementación predeterminada de
System.Management.Automation.Provider.Containercmdletprovider.Copyitemdynamicp
arameters*.

Ejemplo de código
Para obtener código de ejemplo completo, vea Ejemplo de código
AccessDbProviderSample04.

Compilar el proveedor Windows PowerShell de


datos
Consulte Cómo registrar cmdlets, proveedores y aplicaciones host.

Probar el proveedor Windows PowerShell de


pruebas
Cuando el Windows PowerShell se haya registrado con Windows PowerShell, puede
probarlo ejecutando los cmdlets admitidos en la línea de comandos. Tenga en cuenta
que la siguiente salida de ejemplo usa una base de datos de Access ficticia.

1. Ejecute el Get-ChildItem cmdlet para recuperar la lista de elementos secundarios


de una tabla Customers en la base de datos de Access.
PowerShell

Get-ChildItem mydb:customers

Aparece el siguiente resultado.

Resultados

PSPath : AccessDB::customers
PSDrive : mydb
PSProvider : System.Management.Automation.ProviderInfo
PSIsContainer : True
Data : System.Data.DataRow
Name : Customers
RowCount : 91
Columns :

2. Vuelva a Get-ChildItem ejecutar el cmdlet para recuperar los datos de una tabla.

PowerShell

(Get-ChildItem mydb:customers).data

Aparece el siguiente resultado.

Resultados

TABLE_CAT : c:\PS\northwind
TABLE_SCHEM :
TABLE_NAME : Customers
TABLE_TYPE : TABLE
REMARKS :

3. Ahora use el Get-Item cmdlet para recuperar los elementos de la fila 0 de la tabla
de datos.

PowerShell

Get-Item mydb:\customers\0

Aparece el siguiente resultado.

Resultados

PSPath : AccessDB::customers\0
PSDrive : mydb
PSProvider : System.Management.Automation.ProviderInfo
PSIsContainer : False
Data : System.Data.DataRow
RowNumber : 0

4. Reutilizar Get-Item para recuperar los datos de los elementos de la fila 0.

PowerShell

(Get-Item mydb:\customers\0).data

Aparece el siguiente resultado.

Resultados

CustomerID : 1234
CompanyName : Fabrikam
ContactName : Eric Gruber
ContactTitle : President
Address : 4567 Main Street
City : Buffalo
Region : NY
PostalCode : 98052
Country : USA
Phone : (425) 555-0100
Fax : (425) 555-0101

5. Ahora use el New-Item cmdlet para agregar una fila a una tabla existente. El
parámetro especifica la ruta de acceso completa a la fila y debe indicar un número
de fila mayor que el número existente de filas Path de la tabla. El Type parámetro
indica "row" para especificar el tipo de elemento que se agregará. Por último, el
parámetro especifica una lista delimitada por comas de Value valores de columna
para la fila.

PowerShell

New-Item -Path mydb:\Customers\3 -ItemType "row" -Value


"3,CustomerFirstName,CustomerLastName,CustomerEmailAddress,CustomerTitl
e,CustomerCompany,CustomerPhone,
CustomerAddress,CustomerCity,CustomerState,CustomerZip,CustomerCountry"

6. Compruebe la corrección de la nueva operación de elemento como se muestra a


continuación.

none
PS mydb:\> cd Customers
PS mydb:\Customers> (Get-Item 3).data

Aparece el siguiente resultado.

Resultados

ID : 3
FirstName : Eric
LastName : Gruber
Email : ericgruber@fabrikam.com
Title : President
Company : Fabrikam
WorkPhone : (425) 555-0100
Address : 4567 Main Street
City : Buffalo
State : NY
Zip : 98052
Country : USA

Vea también
Creación de Windows PowerShell proveedores

Diseño del proveedor de Windows PowerShell

Implementar un proveedor de Windows PowerShell elemento

Implementar un proveedor de Windows PowerShell navegación

Cómo registrar cmdlets, proveedores y aplicaciones host

Windows PowerShell SDK

Guía del programador de Windows PowerShell


Creación de un proveedor de
navegación de Windows PowerShell
Artículo • 25/09/2021

En este tema se describe cómo crear un proveedor Windows PowerShell navegación


que pueda navegar por el almacén de datos. Este tipo de proveedor admite comandos
recursivos, contenedores anidados y rutas de acceso relativas.

7 Nota

Puede descargar el archivo de código fuente de C# (AccessDBSampleProvider05.cs)


para este proveedor mediante el Kit de desarrollo de software de Microsoft
Windows para los componentes en tiempo de ejecución de Windows Vista y .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .
Para obtener más información sobre otras implementaciones Windows PowerShell
proveedor, vea Designing Your Windows PowerShell Provider.

El proveedor descrito aquí permite al usuario controlar una base de datos de Access
como una unidad para que el usuario pueda navegar a las tablas de datos de la base de
datos. Al crear su propio proveedor de navegación, puede implementar métodos que
pueden hacer que se requieran rutas de acceso completas para la navegación,
normalizar rutas de acceso relativas, mover elementos del almacén de datos, así como
métodos que obtienen nombres secundarios, obtener la ruta de acceso primaria de un
elemento y probar para identificar si un elemento es un contenedor.

U Precaución

Tenga en cuenta que este diseño supone una base de datos que tiene un campo
con el identificador de nombre y que el tipo del campo es LongInteger.

Definición del Windows PowerShell proveedor


Un Windows PowerShell de navegación debe crear una clase .NET que derive de la clase
base System.Management.Automation.Provider.Navigationcmdletprovider. Esta es la
definición de clase para el proveedor de navegación que se describe en esta sección.
C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider

Tenga en cuenta que en este proveedor, el atributo


System.Management.Automation.Provider.Cmdletproviderattribute incluye dos
parámetros. El primer parámetro especifica un nombre descriptivo para el proveedor
que usa Windows PowerShell. El segundo parámetro especifica las Windows PowerShell
específicas que el proveedor expone al entorno de ejecución Windows PowerShell
durante el procesamiento de comandos. Para este proveedor, no hay Windows
PowerShell funcionalidades específicas que se agregan.

Definición de la funcionalidad base


Como se describe en Diseño del proveedor de PS,la clase base
System.Management.Automation.Provider.Navigationcmdletprovider se deriva de otras
clases que proporcionan funcionalidad de proveedor diferente. Un Windows PowerShell
de navegación, por lo tanto, debe definir toda la funcionalidad proporcionada por esas
clases.

Para implementar la funcionalidad para agregar información de inicialización específica


de la sesión y para liberar los recursos que usa el proveedor, vea Creación de un
proveedor de PS básico. Sin embargo, la mayoría de los proveedores (incluido el
proveedor descrito aquí) pueden usar la implementación predeterminada de esta
funcionalidad proporcionada por Windows PowerShell.

Para obtener acceso al almacén de datos a través de una Windows PowerShell, debe
implementar los métodos de la clase base
System.Management.Automation.Provider.Drivecmdletprovider. Para obtener más
información sobre la implementación de estos métodos, vea Creating a Windows
PowerShell Drive Provider.

Para manipular los elementos de un almacén de datos, como obtener, establecer y


borrar elementos, el proveedor debe implementar los métodos proporcionados por la
clase base System.Management.Automation.Provider.Itemcmdletprovider. Para obtener
más información sobre cómo implementar estos métodos, vea Creating an Windows
PowerShell Item Provider.

Para obtener los elementos secundarios, o sus nombres, del almacén de datos, así como
los métodos que crean, copian, cambia el nombre y quitan elementos, debe
implementar los métodos proporcionados por la clase base
System.Management.Automation.Provider.Containercmdletprovider. Para obtener más
información sobre cómo implementar estos métodos, vea Creating a Windows
PowerShell Container Provider.

Crear una ruta Windows PowerShell de acceso


Windows PowerShell proveedor de navegación usa una ruta de acceso interna Windows
PowerShell proveedor para navegar por los elementos del almacén de datos. Para crear
una ruta de acceso interna del proveedor, el proveedor debe implementar el método
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath* para
que admita llamadas desde el cmdlet Combine-Path. Este método combina una ruta de
acceso primaria y secundaria en una ruta de acceso interna del proveedor, mediante un
separador de rutas de acceso específico del proveedor entre las rutas de acceso
primarias y secundarias.

La implementación predeterminada toma rutas de acceso con "/" o " " como separador
de rutas de acceso, normaliza el separador de rutas de acceso a " ", combina las partes
de ruta de acceso primaria y secundaria con el separador entre ellos y, a continuación,
devuelve una cadena que contiene las rutas de acceso \ \ combinadas.

Este proveedor de navegación no implementa este método. Sin embargo, el código


siguiente es la implementación predeterminada del método
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*.

Cosas que debe recordar sobre la implementación de MakePath

Se pueden aplicar las condiciones siguientes a la implementación de


System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*:

La implementación del método


System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*
no debe validar la ruta de acceso como una ruta de acceso completa legal en el
espacio de nombres del proveedor. Tenga en cuenta que cada parámetro solo
puede representar una parte de una ruta de acceso y es posible que las partes
combinadas no generen una ruta de acceso completa. Por ejemplo, el método
System.Management.Automation.Provider.Navigationcmdletprovider.Makepath*
del proveedor del sistema de archivos podría recibir "windows\system32" en el
parámetro y "abc.dll" en el parent child parámetro . El método une estos valores
con el separador "" y devuelve "windows\system32\abc.dll", que no es una ruta de
acceso completa \ del sistema de archivos.
) Importante

Los elementos de ruta de acceso proporcionados en la llamada a


System.Management.Automation.Provider.Navigationcmdletprovider.Make
path* pueden contener caracteres no permitidos en el espacio de nombres
del proveedor. Estos caracteres se usan probablemente para la expansión de
caracteres comodín y la implementación de este método no debe quitarlos.

Recuperar la ruta de acceso primaria


Windows PowerShell de navegación implementan el método
System.Management.Automation.Provider.Navigationcmdletprovider.Getparentpath*
para recuperar la parte primaria de la ruta de acceso completa o parcial indicada
específica del proveedor. El método quita la parte secundaria de la ruta de acceso y
devuelve la parte de la ruta de acceso primaria. El root parámetro especifica la ruta de
acceso completa a la raíz de una unidad. Este parámetro puede ser null o estar vacío si
una unidad montada no está en uso para la operación de recuperación. Si se especifica
una raíz, el método debe devolver una ruta de acceso a un contenedor en el mismo
árbol que la raíz.

El proveedor de navegación de ejemplo no invalida este método, pero usa la


implementación predeterminada. Acepta rutas de acceso que usan "/" y " \ " como
separadores de ruta de acceso. En primer lugar, normaliza la ruta de acceso para que
solo tenga separadores " " y, a continuación, divide la ruta de acceso primaria en el
último \ " " y devuelve la ruta de acceso \ primaria.

Para recordar sobre la implementación de GetParentPath

La implementación del método


System.Management.Automation.Provider.Navigationcmdletprovider.Getparentpath*
debe dividir la ruta de acceso léxicamente en el separador de rutas de acceso del
espacio de nombres del proveedor. Por ejemplo, el proveedor del sistema de archivos
usa este método para buscar el último " " y devuelve todo a \ la izquierda del separador.

Recuperar el nombre de la ruta de acceso


secundaria
El proveedor de navegación implementa el método
System.Management.Automation.Provider.Navigationcmdletprovider.Getchildname*
para recuperar el nombre (elemento hoja) del elemento secundario del elemento
ubicado en la ruta de acceso completa o parcial específica del proveedor indicada.

El proveedor de navegación de ejemplo no invalida este método. A continuación se


muestra la implementación predeterminada. Acepta rutas de acceso que usan "/" y " \ "
como separadores de ruta de acceso. En primer lugar, normaliza la ruta de acceso para
que solo tenga separadores " " y, a continuación, divide la ruta de acceso primaria en el
último " " y devuelve el nombre de la parte de ruta \ \ de acceso secundaria.

Cosas que debe recordar sobre la implementación de


GetChildName
La implementación del método
System.Management.Automation.Provider.Navigationcmdletprovider.Getchildname*
debe dividir la ruta de acceso léxicamente en el separador de ruta de acceso. Si la ruta
de acceso proporcionada no contiene separadores de ruta de acceso, el método debe
devolver la ruta de acceso sin modificar.

) Importante

La ruta de acceso proporcionada en la llamada a este método puede contener


caracteres que no son válidos en el espacio de nombres del proveedor. Estos
caracteres se usan probablemente para la expansión de caracteres comodín o la
coincidencia de expresiones regulares, y la implementación de este método no
debe quitarlos.

Determinar si un elemento es un contenedor


El proveedor de navegación puede implementar el método
System.Management.Automation.Provider.Navigationcmdletprovider.Isitemcontainer*
para determinar si la ruta de acceso especificada indica un contenedor. Devuelve true si
la ruta de acceso representa un contenedor y false en caso contrario. El usuario necesita
este método para poder usar el Test-Path cmdlet para la ruta de acceso proporcionada.

El código siguiente muestra la implementación


System.Management.Automation.Provider.Navigationcmdletprovider.Isitemcontainer*
en nuestro proveedor de navegación de ejemplo. El método comprueba que la ruta de
acceso especificada es correcta y si la tabla existe, y devuelve true si la ruta de acceso
indica un contenedor.
C#

protected override bool IsItemContainer(string path)


{
if (PathIsDrive(path))
{
return true;
}

string[] pathChunks = ChunkPath(path);


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...

return false;
} // IsItemContainer

Cosas que debe recordar sobre la implementación de


IsItemContainer
La clase .NET del proveedor de navegación podría declarar las funcionalidades de
proveedor de ExpandLayoutdcards, Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En este caso, la
implementación de
System.Management.Automation.Provider.Navigationcmdletprovider.Isitemcontainer*
debe asegurarse de que la ruta de acceso pasada cumple los requisitos. Para ello, el
método debe tener acceso a la propiedad adecuada, por ejemplo, la propiedad
System.Management.Automation.Provider.Cmdletprovider.Exclude*.

Mover un elemento
Para admitir el cmdlet , el proveedor de navegación implementa el Move-Item método
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*. Este
método mueve el elemento especificado por el parámetro al path contenedor en la ruta
de acceso proporcionada en el parámetro destination .

El proveedor de navegación de ejemplo no invalida el método


System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem*. A
continuación se muestra la implementación predeterminada.

Cosas que debe recordar sobre la implementación de MoveItem


La clase .NET del proveedor de navegación podría declarar las funcionalidades de
proveedor de ExpandLayoutdcards, Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En este caso, la
implementación de
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem* debe
asegurarse de que la ruta de acceso pasada cumple los requisitos. Para ello, el método
debe tener acceso a la propiedad adecuada, por ejemplo, la propiedad
CmdletProvider.Exclude.

De forma predeterminada, las invalidaciones de este método no deben mover objetos


sobre objetos existentes a menos que la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force* esté establecida en
true . Por ejemplo, el proveedor del sistema de archivos no copiará c:\temp\abc.txt

sobre un archivo c:\bar.txt existente a menos que la propiedad


System.Management.Automation.Provider.Cmdletprovider.Force* esté establecida en
true . Si la ruta de acceso especificada en el parámetro existe y es un contenedor, no se
requiere la propiedad destination
System.Management.Automation.Provider.Cmdletprovider.Force*. En este caso,
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem* debe
mover el elemento indicado por el parámetro al contenedor indicado por el parámetro
como path destination elemento secundario.

La implementación del método


System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem* debe
llamar a System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos. Este
método se usa para confirmar la ejecución de una operación cuando se realiza un
cambio en el estado del sistema, por ejemplo, la eliminación de archivos.
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess envía el
nombre del recurso que se va a cambiar al usuario, con el tiempo de ejecución de
Windows PowerShell teniendo en cuenta cualquier configuración de línea de comandos
o variables de preferencia para determinar lo que se debe mostrar al usuario.
Después de que la llamada a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva , el
método true
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitem* debe
llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue. Este
método envía un mensaje al usuario para permitir que los comentarios digan si la
operación debe continuar. El proveedor debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue como una
comprobación adicional de modificaciones del sistema potencialmente peligrosas.

Adjuntar parámetros dinámicos al cmdlet


Move-Item
A veces, Move-Item el cmdlet requiere parámetros adicionales que se proporcionan
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de navegación debe implementar el método
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitemdynamic
parameters* para obtener los valores de parámetro necesarios del elemento en la ruta
de acceso indicada y devolver un objeto que tenga propiedades y campos con atributos
de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary.

Este proveedor de navegación no implementa este método. Sin embargo, el código


siguiente es la implementación predeterminada de
System.Management.Automation.Provider.Navigationcmdletprovider.Moveitemdynamic
parameters*.

Normalización de una ruta de acceso relativa


El proveedor de navegación implementa el método
System.Management.Automation.Provider.Navigationcmdletprovider.Normalizerelativep
ath* para normalizar la ruta de acceso completa indicada en el parámetro como relativa
a la ruta de acceso especificada por el path basePath parámetro . El método devuelve
una representación de cadena de la ruta de acceso normalizada. Escribe un error si el
path parámetro especifica una ruta de acceso inexistente.

El proveedor de navegación de ejemplo no invalida este método. A continuación se


muestra la implementación predeterminada.
Cosas que debe recordar sobre la implementación de
NormalizeRelativePath

La implementación de
System.Management.Automation.Provider.Navigationcmdletprovider.Normalizerelativep
ath* debe analizar el parámetro , pero no tiene que usar el análisis puramente path
sintáctico. Se recomienda diseñar este método para usar la ruta de acceso para buscar la
información de ruta de acceso en el almacén de datos y crear una ruta de acceso que
coincida con la sintaxis de mayúsculas y minúsculas y ruta de acceso estandarizada.

Ejemplo de código
Para obtener código de ejemplo completo, vea Ejemplo de código
AccessDbProviderSample05.

Definir tipos de objeto y formato


Es posible que un proveedor agregue miembros a objetos existentes o defina nuevos
objetos. Para obtener más información,vea Extending Object Types and Formatting.

Creación del proveedor de Windows


PowerShell de datos
Para obtener más información, vea Cómo registrar cmdlets, proveedores y aplicaciones
host.

Probar el proveedor Windows PowerShell


proveedor
Cuando el proveedor Windows PowerShell se haya registrado con Windows PowerShell,
puede probarlo ejecutando los cmdlets admitidos en la línea de comandos, incluidos los
cmdlets que están disponibles mediante derivación. En este ejemplo se probará el
proveedor de navegación de ejemplo.

1. Ejecute el nuevo shell y use el Set-Location cmdlet para establecer la ruta de


acceso para indicar la base de datos de Access.

PowerShell
Set-Location mydb:

2. Ahora ejecute el cmdlet para recuperar una lista de los elementos de base de Get-
Childitem datos, que son las tablas de base de datos disponibles. Para cada tabla,
este cmdlet también recupera el número de filas de tabla.

PowerShell

Get-ChildItem | Format-Table rowcount,name -AutoSize

Output

RowCount Name
-------- ----
180 MSysAccessObjects
0 MSysACEs
1 MSysCmdbars
0 MSysIMEXColumns
0 MSysIMEXSpecs
0 MSysObjects
0 MSysQueries
7 MSysRelationships
8 Categories
91 Customers
9 Employees
2155 Order Details
830 Orders
77 Products
3 Shippers
29 Suppliers

3. Use de Set-Location nuevo el cmdlet para establecer la ubicación de la tabla de


datos Employees.

PowerShell

Set-Location Employees

4. Ahora vamos a usar el Get-Location cmdlet para recuperar la ruta de acceso a la


tabla Employees.

PowerShell

Get-Location
Output

Path
----
mydb:\Employees

5. Ahora use el Get-Childitem cmdlet canaldo al Format-Table cmdlet . Este conjunto


de cmdlets recupera los elementos de la tabla de datos Employees, que son las
filas de la tabla. Tienen el formato especificado por el Format-Table cmdlet .

PowerShell

Get-ChildItem | Format-Table rownumber,psiscontainer,data -AutoSize

Output

RowNumber PSIsContainer Data


--------- -------------- ----
0 False System.Data.DataRow
1 False System.Data.DataRow
2 False System.Data.DataRow
3 False System.Data.DataRow
4 False System.Data.DataRow
5 False System.Data.DataRow
6 False System.Data.DataRow
7 False System.Data.DataRow
8 False System.Data.DataRow

6. Ahora puede ejecutar el cmdlet para recuperar los elementos Get-Item de la fila 0
de la tabla de datos Employees.

PowerShell

Get-Item 0

Output

PSPath : AccessDB::C:\PS\Northwind.mdb\Employees\0
PSParentPath : AccessDB::C:\PS\Northwind.mdb\Employees
PSChildName : 0
PSDrive : mydb
PSProvider : System.Management.Automation.ProviderInfo
PSIsContainer : False
Data : System.Data.DataRow
RowNumber : 0
7. Use de Get-Item nuevo el cmdlet para recuperar los datos de los empleados de los
elementos de la fila 0.

PowerShell

(Get-Item 0).data

Output

EmployeeID : 1
LastName : Davis
FirstName : Sara
Title : Sales Representative
TitleOfCourtesy : Ms.
BirthDate : 12/8/1968 12:00:00 AM
HireDate : 5/1/1992 12:00:00 AM
Address : 4567 Main Street
Apt. 2A
City : Buffalo
Region : NY
PostalCode : 98052
Country : USA
HomePhone : (206) 555-9857
Extension : 5467
Photo : EmpID1.bmp
Notes : Education includes a BA in psychology from
Colorado State University. She also completed "The
Art of the Cold Call." Nancy is a member of
Toastmasters International.
ReportsTo : 2

Consulte también
Creación de Windows PowerShell proveedores

Diseño del proveedor Windows PowerShell aplicación

Extensión de tipos de objeto y formato

Implementación de un proveedor de Windows PowerShell contenedor

Cómo registrar cmdlets, proveedores y aplicaciones host

Guía del programador de Windows PowerShell

Windows PowerShell SDK


Creación de un proveedor de contenido
de Windows PowerShell
Artículo • 27/09/2021

En este tema se describe cómo crear un proveedor Windows PowerShell que permita al
usuario manipular el contenido de los elementos de un almacén de datos. Como
consecuencia, un proveedor que puede manipular el contenido de los elementos se
conoce como proveedor de Windows PowerShell contenido.

7 Nota

Puede descargar el archivo de código fuente de C# (AccessDBSampleProvider06.cs)


para este proveedor mediante el Kit de desarrollo de software de Microsoft
Windows para los componentes en tiempo de ejecución de Windows Vista y .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .
Para obtener más información sobre otras implementaciones Windows PowerShell
proveedor de recursos, vea Designing Your Windows PowerShell Provider.

Definir la clase Windows PowerShell content


provider
Un Windows PowerShell de contenido debe crear una clase .NET que admita la interfaz
System.Management.Automation.Provider.Icontentcmdletprovider. Esta es la definición
de clase para el proveedor de elementos que se describe en esta sección.

C#

[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider,
IContentCmdletProvider

Tenga en cuenta que en esta definición de clase, el atributo


System.Management.Automation.Provider.Cmdletproviderattribute incluye dos
parámetros. El primer parámetro especifica un nombre descriptivo para el proveedor
que usa Windows PowerShell. El segundo parámetro especifica las Windows PowerShell
específicas que el proveedor expone al entorno Windows PowerShell tiempo de
ejecución durante el procesamiento de comandos. Para este proveedor, no se han
agregado Windows PowerShell funcionalidades específicas.

Definición de la funcionalidad de la clase base


Como se describeen Diseño del proveedor de Windows PowerShell , la clase
System.Management.Automation.Provider.Navigationcmdletprovider deriva de otras
clases que proporcionan funcionalidad de proveedor diferente. Por Windows PowerShell
proveedor de contenido, normalmente define toda la funcionalidad proporcionada por
esas clases.

Para obtener más información sobre cómo implementar la funcionalidad para agregar
información de inicialización específica de la sesión y para liberar los recursos que usa el
proveedor, vea Crear un proveedor de Windows PowerShell básico. Sin embargo, la
mayoría de los proveedores, incluido el proveedor descrito aquí, pueden usar la
implementación predeterminada de esta funcionalidad proporcionada por Windows
PowerShell.

Para acceder al almacén de datos, el proveedor debe implementar los métodos de la


clase base System.Management.Automation.Provider.Drivecmdletprovider. Para obtener
más información sobre la implementación de estos métodos, vea Creating a Windows
PowerShell Drive Provider.

Para manipular los elementos de un almacén de datos, como obtener, establecer y


borrar elementos, el proveedor debe implementar los métodos proporcionados por la
clase base System.Management.Automation.Provider.Itemcmdletprovider. Para obtener
más información sobre la implementación de estos métodos, vea Creating a Windows
PowerShell Item Provider.

Para trabajar en almacenes de datos de varias capas, el proveedor debe implementar los
métodos proporcionados por la clase base
System.Management.Automation.Provider.Containercmdletprovider. Para obtener más
información sobre la implementación de estos métodos, vea Creating a Windows
PowerShell Container Provider.

Para admitir comandos recursivos, contenedores anidados y rutas de acceso relativas, el


proveedor debe implementar la clase base
System.Management.Automation.Provider.Navigationcmdletprovider. Además, este
proveedor de contenido Windows PowerShell puede adjuntar la interfaz
System.Management.Automation.Provider.Icontentcmdletprovider a la clase base
System.Management.Automation.Provider.Navigationcmdletprovider y, por tanto, debe
implementar los métodos proporcionados por esa clase. Para obtener más información,
vea Implementar esos métodos, vea Implementar un proveedor de Windows PowerShell
navegación.

Implementar un lector de contenido


Para leer contenido de un elemento, un proveedor debe implementar una clase de
lector de contenido que deriva de
System.Management.Automation.Provider.Icontentreader. El lector de contenido de este
proveedor permite el acceso al contenido de una fila de una tabla de datos. La clase de
lector de contenido define un método Read que recupera los datos de la fila indicada y
devuelve una lista que representa los datos, un método Seek que mueve el lector de
contenido, un método Close que cierra el lector de contenido y un método Dispose.

C#

public class AccessDBContentReader : IContentReader


{
// A provider instance is required so as to get "content"
private AccessDBProvider provider;
private string path;
private long currentOffset;

internal AccessDBContentReader(string path, AccessDBProvider provider)


{
this.path = path;
this.provider = provider;
}

/// <summary>
/// Read the specified number of rows from the source.
/// </summary>
/// <param name="readCount">The number of items to
/// return.</param>
/// <returns>An array of elements read.</returns>
public IList Read(long readCount)
{
// Read the number of rows specified by readCount and increment
// offset
string tableName;
int rowNumber;
PathType type = provider.GetNamesFromPath(path, out tableName, out
rowNumber);

Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
Collection<DataRow> results = new Collection<DataRow>();

if (currentOffset < 0 || currentOffset >= rows.Count)


{
return null;
}

int rowsRead = 0;

while (rowsRead < readCount && currentOffset < rows.Count)


{
results.Add(rows[(int)currentOffset].Data);
rowsRead++;
currentOffset++;
}

return results;
} // Read

/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
/// <param name="offset">Number of rows to offset</param>
/// <param name="origin">Starting row from which to offset</param>
public void Seek(long offset, System.IO.SeekOrigin origin)
{
// get the number of rows in the table which will help in
// calculating current position
string tableName;
int rowNumber;

PathType type = provider.GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Invalid)
{
throw new ArgumentException("Path specified must represent a
table or a row :" + path);
}

if (type == PathType.Table)
{
Collection<DatabaseRowInfo> rows = provider.GetRows(tableName);

int numRows = rows.Count;

if (offset > rows.Count)


{
throw new
ArgumentException(
"Offset cannot be greater than the number of rows
available"
);
}

if (origin == System.IO.SeekOrigin.Begin)
{
// starting from Beginning with an index 0, the current
offset
// has to be advanced to offset - 1
currentOffset = offset - 1;
}
else if (origin == System.IO.SeekOrigin.End)
{
// starting from the end which is numRows - 1, the current
// offset is so much less than numRows - 1
currentOffset = numRows - 1 - offset;
}
else
{
// calculate from the previous value of current offset
// advancing forward always
currentOffset += offset;
}
} // if (type...
else
{
// for row, the offset will always be set to 0
currentOffset = 0;
}

} // Seek

/// <summary>
/// Closes the content reader, so all members are reset
/// </summary>
public void Close()
{
Dispose();
} // Close

/// <summary>
/// Dispose any resources being used
/// </summary>
public void Dispose()
{
Seek(0, System.IO.SeekOrigin.Begin);

GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentReader

Implementar un escritor de contenido


Para escribir contenido en un elemento, un proveedor debe implementar una clase de
escritor de contenido que se deriva de
System.Management.Automation.Provider.Icontentwriter. La clase content writer define
un método Write que escribe el contenido de fila especificado, un método Seek que
mueve el escritor de contenido, un método Close que cierra el escritor de contenido y
un método Dispose.

C#

public class AccessDBContentWriter : IContentWriter


{
// A provider instance is required so as to get "content"
private AccessDBProvider provider;
private string path;
private long currentOffset;

internal AccessDBContentWriter(string path, AccessDBProvider provider)


{
this.path = path;
this.provider = provider;
}

/// <summary>
/// Write the specified row contents in the source
/// </summary>
/// <param name="content"> The contents to be written to the source.
/// </param>
/// <returns>An array of elements which were successfully written to
/// the source</returns>
///
public IList Write(IList content)
{
if (content == null)
{
return null;
}

// Get the total number of rows currently available it will


// determine how much to overwrite and how much to append at
// the end
string tableName;
int rowNumber;
PathType type = provider.GetNamesFromPath(path, out tableName, out
rowNumber);

if (type == PathType.Table)
{
OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
if (da == null)
{
return null;
}

DataSet ds = provider.GetDataSetForTable(da, tableName);


DataTable table = provider.GetDataTable(ds, tableName);

string[] colValues = (content[0] as string).Split(',');


// set the specified row
DataRow row = table.NewRow();

for (int i = 0; i < colValues.Length; i++)


{
if (!String.IsNullOrEmpty(colValues[i]))
{
row[i] = colValues[i];
}
}

//table.Rows.InsertAt(row, rowNumber);
// Update the table
table.Rows.Add(row);
da.Update(ds, tableName);

}
else
{
throw new InvalidOperationException("Operation not supported.
Content can be added only for tables");
}

return null;
} // Write

/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
/// <param name="offset">Number of rows to offset</param>
/// <param name="origin">Starting row from which to offset</param>
public void Seek(long offset, System.IO.SeekOrigin origin)
{
// get the number of rows in the table which will help in
// calculating current position
string tableName;
int rowNumber;

PathType type = provider.GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Invalid)
{
throw new ArgumentException("Path specified should represent
either a table or a row : " + path);
}

Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);

int numRows = rows.Count;

if (offset > rows.Count)


{
throw new
ArgumentException(
"Offset cannot be greater than the number of rows
available"
);
}

if (origin == System.IO.SeekOrigin.Begin)
{
// starting from Beginning with an index 0, the current offset
// has to be advanced to offset - 1
currentOffset = offset - 1;
}
else if (origin == System.IO.SeekOrigin.End)
{
// starting from the end which is numRows - 1, the current
// offset is so much less than numRows - 1
currentOffset = numRows - 1 - offset;
}
else
{
// calculate from the previous value of current offset
// advancing forward always
currentOffset += offset;
}

} // Seek

/// <summary>
/// Closes the content reader, so all members are reset
/// </summary>
public void Close()
{
Dispose();
} // Close

/// <summary>
/// Dispose any resources being used
/// </summary>
public void Dispose()
{
Seek(0, System.IO.SeekOrigin.Begin);

GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentWriter

Recuperar el lector de contenido


Para obtener contenido de un elemento, el proveedor debe implementar
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader*
para admitir el Get-Content cmdlet . Este método devuelve el lector de contenido para
el elemento ubicado en la ruta de acceso especificada. A continuación, se puede abrir el
objeto de lector para leer el contenido.

Esta es la implementación de
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader*
para este método para este proveedor.

C#

public IContentReader GetContentReader(string path)


{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be obtained only
for tables");
}

return new AccessDBContentReader(path, this);


} // GetContentReader

C#

public IContentReader GetContentReader(string path)


{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be obtained only
for tables");
}

return new AccessDBContentReader(path, this);


} // GetContentReader
Cosas que debe recordar sobre la implementación de
GetContentReader

Las condiciones siguientes pueden aplicarse a una implementación de


System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreader*:

Al definir la clase de proveedor, un proveedor de contenido de Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentread
er* debe asegurarse de que la ruta de acceso pasada al método cumple los
requisitos de las funcionalidades especificadas. Para ello, el método debe tener
acceso a la propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

De forma predeterminada, las invalidaciones de este método no deben recuperar


un lector para los objetos que están ocultos para el usuario a menos que la
propiedad System.Management.Automation.Provider.Cmdletprovider.Force* esté
establecida en true . Se debe escribir un error si la ruta de acceso representa un
elemento que está oculto al usuario y
System.Management.Automation.Provider.Cmdletprovider.Force* está establecido
en false .

Adjuntar parámetros dinámicos al cmdlet Get-


Content.
El Get-Content cmdlet puede requerir parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
Windows PowerShell proveedor de contenido debe implementar el método
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentreaderdyn
amicparameters*. Este método recupera parámetros dinámicos para el elemento en la
ruta de acceso indicada y devuelve un objeto que tiene propiedades y campos con
atributos de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El Windows
PowerShell runtime usa el objeto devuelto para agregar los parámetros al cmdlet .
Este Windows PowerShell proveedor de contenedores no implementa este método. Sin
embargo, el código siguiente es la implementación predeterminada de este método.

C#

public object GetContentReaderDynamicParameters(string path)


{
return null;
}

C#

public object GetContentReaderDynamicParameters(string path)


{
return null;
}

Recuperación del escritor de contenido


Para escribir contenido en un elemento, el proveedor debe implementar
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*
para admitir los Set-Content Add-Content cmdlets y . Este método devuelve el escritor
de contenido para el elemento ubicado en la ruta de acceso especificada.

Esta es la implementación de
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*
para este método.

C#

public IContentWriter GetContentWriter(string path)


{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be added only to
tables");
}
return new AccessDBContentWriter(path, this);
}

C#

public IContentWriter GetContentWriter(string path)


{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be added only to
tables");
}

return new AccessDBContentWriter(path, this);


}

Cosas que debe recordar sobre la implementación de


GetContentWriter

Se pueden aplicar las condiciones siguientes a la implementación de


System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriter*:

Al definir la clase de proveedor, un proveedor de contenido de Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwrite
r* debe asegurarse de que la ruta de acceso pasada al método cumple los
requisitos de las funcionalidades especificadas. Para ello, el método debe tener
acceso a la propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

De forma predeterminada, las invalidaciones de este método no deben recuperar


un escritor para los objetos que están ocultos para el usuario a menos que la
propiedad System.Management.Automation.Provider.Cmdletprovider.Force* esté
establecida en true . Se debe escribir un error si la ruta de acceso representa un
elemento que está oculto al usuario y
System.Management.Automation.Provider.Cmdletprovider.Force* está establecido
en false .

Adjuntar parámetros dinámicos a los cmdlets


Add-Content y Set-Content dinámicos
Los Add-Content Set-Content cmdlets y pueden requerir parámetros dinámicos
adicionales que se agregan a un entorno de ejecución. Para proporcionar estos
parámetros dinámicos, el proveedor de contenido Windows PowerShell debe
implementar el método
System.Management.Automation.Provider.Icontentcmdletprovider.Getcontentwriterdyna
micparameters* para controlar estos parámetros. Este método recupera parámetros
dinámicos para el elemento en la ruta de acceso indicada y devuelve un objeto que
tiene propiedades y campos con atributos de análisis similares a una clase de cmdlet o
un objeto System.Management.Automation.Runtimedefinedparameterdictionary. El
Windows PowerShell runtime usa el objeto devuelto para agregar los parámetros a los
cmdlets.

Este Windows PowerShell proveedor de contenedores no implementa este método. Sin


embargo, el código siguiente es la implementación predeterminada de este método.

C#

public object GetContentWriterDynamicParameters(string path)


{
return null;
}

Borrar contenido
El proveedor de contenido implementa el método
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* para
admitir el Clear-Content cmdlet . Este método quita el contenido del elemento en la
ruta de acceso especificada, pero deja intacto el elemento.

Esta es la implementación del método


System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent* para
este proveedor.
C#

public void ClearContent(string path)


{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out rowNumber);

if (type != PathType.Table)
{
WriteError(new ErrorRecord(
new InvalidOperationException("Operation not supported. Content
can be cleared only for table"),
"NotValidRow", ErrorCategory.InvalidArgument,
path));
return;
}

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

// Clear contents at the specified location


for (int i = 0; i < table.Rows.Count; i++)
{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "ClearContent"))
{
da.Update(ds, tableName);
}

} // ClearContent

Cosas que debe recordar sobre la implementación de ClearContent


Las condiciones siguientes se pueden aplicar a una implementación de
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*:

Al definir la clase de proveedor, un proveedor de contenido de Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

De forma predeterminada, las invalidaciones de este método no deben borrar el


contenido de los objetos que se ocultan al usuario a menos que la propiedad
System.Management.Automation.Provider.Cmdletprovider.Force* esté establecida
en true . Se debe escribir un error si la ruta de acceso representa un elemento que
está oculto al usuario y
System.Management.Automation.Provider.Cmdletprovider.Force* está establecido
en false .

La implementación del método


System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Este método se usa para confirmar la ejecución de una operación cuando se realiza
un cambio en el almacén de datos, como borrar contenido. El método
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess envía el
nombre del recurso que se va a cambiar al usuario, con el tiempo de ejecución de
Windows PowerShell controlando cualquier configuración de línea de comandos o
variables de preferencia para determinar lo que se debe mostrar.

Después de que la llamada a


System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva
, el método true
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontent*
debe llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue. Este
método envía un mensaje al usuario para permitir que los comentarios
comprueben si se debe continuar la operación. La llamada a
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue
permite realizar una comprobación adicional de las modificaciones potencialmente
peligrosas del sistema.
Adjuntar parámetros dinámicos al cmdlet
Clear-Content.
El Clear-Content cmdlet puede requerir parámetros dinámicos adicionales que se
agregan en tiempo de ejecución. Para proporcionar estos parámetros dinámicos, el
proveedor de contenido Windows PowerShell debe implementar el método
System.Management.Automation.Provider.Icontentcmdletprovider.Clearcontentdynamic
parameters* para controlar estos parámetros. Este método recupera los parámetros del
elemento en la ruta de acceso indicada. Este método recupera parámetros dinámicos
para el elemento en la ruta de acceso indicada y devuelve un objeto que tiene
propiedades y campos con atributos de análisis similares a una clase de cmdlet o un
objeto System.Management.Automation.Runtimedefinedparameterdictionary. El
Windows PowerShell runtime usa el objeto devuelto para agregar los parámetros al
cmdlet .

Este Windows PowerShell proveedor de contenedores no implementa este método. Sin


embargo, el código siguiente es la implementación predeterminada de este método.

C#

public object ClearContentDynamicParameters(string path)


{
return null;
}

C#

public object ClearContentDynamicParameters(string path)


{
return null;
}

Ejemplo de código
Para obtener código de ejemplo completo, vea Ejemplo de código
AccessDbProviderSample06.

Definir tipos de objeto y formato


Al escribir un proveedor, puede ser necesario agregar miembros a objetos existentes o
definir nuevos objetos. Una vez hecho esto, debe crear un archivo Types que Windows
PowerShell pueda usar para identificar los miembros del objeto y un archivo Format que
defina cómo se muestra el objeto. Para obtener más información, vea Extender tipos de
objeto y Aplicar formatoa .

Compilar el proveedor Windows PowerShell


datos
Vea How to Register Cmdlets, Providers, and Host Applications( Cómo registrar cmdlets,
proveedores y aplicaciones host).

Probar el proveedor Windows PowerShell datos


Cuando el Windows PowerShell se haya registrado con Windows PowerShell, puede
probarlo ejecutando los cmdlets admitidos en la línea de comandos. Por ejemplo,
pruebe el proveedor de contenido de ejemplo.

Use el cmdlet para recuperar el contenido del elemento especificado en la tabla de base
de datos en la ruta Get-Content de acceso especificada por el parámetro Path . El
parámetro especifica el número de elementos que debe leer el lector de contenido
definido ReadCount (valor predeterminado 1). Con la siguiente entrada de comando, el
cmdlet recupera dos filas (elementos) de la tabla y muestra su contenido. Tenga en
cuenta que la siguiente salida de ejemplo usa una base de datos de Access ficticia.

PowerShell

Get-Content -Path mydb:\Customers -ReadCount 2

Output

ID : 1
FirstName : Eric
LastName : Gruber
Email : ericgruber@fabrikam.com
Title : President
Company : Fabrikam
WorkPhone : (425) 555-0100
Address : 4567 Main Street
City : Buffalo
State : NY
Zip : 98052
Country : USA
ID : 2
FirstName : Eva
LastName : Corets
Email : evacorets@cohowinery.com
Title : Sales Representative
Company : Coho Winery
WorkPhone : (360) 555-0100
Address : 8910 Main Street
City : Cabmerlot
State : WA
Zip : 98089
Country : USA

Consulte también
Creación de Windows PowerShell proveedores de recursos

Diseñar el proveedor Windows PowerShell aplicación

Extensión de tipos de objeto y formato

Implementar un proveedor de Windows PowerShell navegación

Cómo registrar cmdlets, proveedores y aplicaciones host

Windows PowerShell SDK

Guía del programador de Windows PowerShell


Creación de un proveedor de
propiedades de Windows PowerShell
Artículo • 27/09/2021

En este tema se describe cómo crear un proveedor que permita al usuario manipular las
propiedades de los elementos de un almacén de datos. Como consecuencia, este tipo
de proveedor se conoce como proveedor Windows PowerShell de propiedades. Por
ejemplo, el proveedor del Registro proporcionado por Windows PowerShell controla los
valores de clave del Registro como propiedades del elemento de clave del Registro. Este
tipo de proveedor debe agregar la interfaz
System.Management.Automation.Provider.Ipropertycmdletprovider a la implementación
de la clase .NET.

7 Nota

Windows PowerShell proporciona un archivo de plantilla que puede usar para


desarrollar un proveedor Windows PowerShell trabajo. El archivo
TemplateProvider.cs está disponible en el Kit de desarrollo de software de
Microsoft Windows para Windows Vista y .NET Framework 3.0 Runtime
Components. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. La plantilla
descargada está disponible en el <PowerShell Samples> directorio . Debe realizar
una copia de este archivo y usar la copia para crear un nuevo proveedor de
Windows PowerShell, quitando cualquier funcionalidad que no necesite. Para
obtener más información sobre otras implementaciones Windows PowerShell
proveedor de recursos, vea Designing Your Windows PowerShell Provider.

U Precaución

Los métodos del proveedor de propiedades deben escribir cualquier objeto


mediante el método
System.Management.Automation.Provider.Cmdletprovider.Writepropertyobject*.

Definición del proveedor Windows PowerShell


datos
Un proveedor de propiedades debe crear una clase .NET que admita la interfaz
System.Management.Automation.Provider.Ipropertycmdletprovider. Esta es la
declaración de clase predeterminada del archivo TemplateProvider.cs proporcionado por
Windows PowerShell.

Definición de la funcionalidad base


La interfaz System.Management.Automation.Provider.Ipropertycmdletprovider se puede
adjuntar a cualquiera de las clases base del proveedor, a excepción de la clase
System.Management.Automation.Provider.Drivecmdletprovider. Agregue la
funcionalidad base que requiere la clase base que está usando. Para obtener más
información sobre las clases base, vea Designing Your Windows PowerShell Provider.

Recuperación de propiedades
Para recuperar propiedades, el proveedor debe implementar el método
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty* para
admitir llamadas desde el Get-ItemProperty cmdlet . Este método recupera las
propiedades del elemento ubicado en la ruta de acceso interna del proveedor
especificada (completa).

El providerSpecificPickList parámetro indica qué propiedades se recuperarán. Si este


parámetro es null o está vacío, el método debe recuperar todas las propiedades.
Además,
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty* escribe
una instancia de un objeto System.Management.Automation.PSObject que representa
un contenedor de propiedades de las propiedades recuperadas. El método no debe
devolver nada.

Se recomienda que la implementación de


System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty* admita
la expansión con caracteres comodín de los nombres de propiedad para cada elemento
de la lista de selección. Para ello, use la clase
System.Management.Automation.Wildcardpattern para realizar la coincidencia del
patrón de caracteres comodín.

Esta es la implementación predeterminada de


System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty* desde
el archivo TemplateProvider.cs proporcionado por Windows PowerShell.
Cosas que debe recordar sobre la implementación de GetProperty
Se pueden aplicar las condiciones siguientes a la implementación de
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty*:

Al definir la clase de proveedor, un proveedor de propiedades Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Ipropertycmdletprovider.Getproperty*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

De forma predeterminada, las invalidaciones de este método no deben recuperar


un lector para los objetos que están ocultos para el usuario a menos que la
propiedad System.Management.Automation.Provider.Cmdletprovider.Force* esté
establecida en true . Se debe escribir un error si la ruta de acceso representa un
elemento que está oculto al usuario y
System.Management.Automation.Provider.Cmdletprovider.Force* está establecido
en false .

Adjuntar parámetros dinámicos al cmdlet Get-


ItemProperty.
El Get-ItemProperty cmdlet puede requerir parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de Windows PowerShell debe implementar el método
System.Management.Automation.Provider.Ipropertycmdletprovider.Getpropertydynamic
parameters*. El parámetro indica una ruta de acceso interna del proveedor completa,
mientras que el parámetro especifica las propiedades específicas del proveedor path
providerSpecificPickList especificadas en la línea de comandos. Este parámetro puede
estar null o vacío si las propiedades se canalizarán al cmdlet . En este caso, este
método devuelve un objeto que tiene propiedades y campos con atributos de análisis
similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El Windows
PowerShell en tiempo de ejecución usa el objeto devuelto para agregar los parámetros
al cmdlet .

Esta es la implementación predeterminada de


System.Management.Automation.Provider.Ipropertycmdletprovider.Getpropertydynamic
parameters* desde el archivo TemplateProvider.cs proporcionado por Windows
PowerShell.

Establecer propiedades
Para establecer propiedades, el proveedor de Windows PowerShell debe implementar el
método
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty* para
admitir llamadas desde el Set-ItemProperty cmdlet . Este método establece una o varias
propiedades del elemento en la ruta de acceso especificada y sobrescribe las
propiedades proporcionadas según sea necesario.
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
también escribe una instancia de un objeto System.Management.Automation.PSObject
que representa un contenedor de propiedades de las propiedades actualizadas.

Esta es la implementación predeterminada de


System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty* desde
el archivo TemplateProvider.cs proporcionado por Windows PowerShell.

Aspectos que debe recordar sobre la implementación de Set-


ItemProperty
Las condiciones siguientes pueden aplicarse a una implementación de
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*:

Al definir la clase de proveedor, un proveedor de propiedades Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.
De forma predeterminada, las invalidaciones de este método no deben recuperar
un lector para los objetos que están ocultos para el usuario a menos que la
propiedad System.Management.Automation.Provider.Cmdletprovider.Force* esté
establecida en true . Se debe escribir un error si la ruta de acceso representa un
elemento que está oculto al usuario y
System.Management.Automation.Provider.Cmdletprovider.Force* está establecido
en false .

La implementación del método


System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Este método se usa para confirmar la ejecución de una operación cuando se realiza
un cambio en el estado del sistema, por ejemplo, cambiar el nombre de los
archivos. System.Management.Automation.Provider.Cmdletprovider.ShouldProcess
envía el nombre del recurso que se va a cambiar al usuario, con el tiempo de
ejecución de Windows PowerShell y controlando cualquier configuración de línea
de comandos o variables de preferencia para determinar lo que se debe mostrar.

Después de que la llamada a


System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva
, si se pueden realizar modificaciones potencialmente peligrosas del sistema, el
método true
System.Management.Automation.Provider.Ipropertycmdletprovider.Setproperty*
debe llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue. Este
método envía un mensaje de confirmación al usuario para permitir comentarios
adicionales que indiquen que la operación debe continuar.

Adjuntar parámetros dinámicos para el cmdlet


Set-ItemProperty.
El Set-ItemProperty cmdlet puede requerir parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de Windows PowerShell debe implementar el método
System.Management.Automation.Provider.Ipropertycmdletprovider.Setpropertydynamic
parameters*. Este método devuelve un objeto que tiene propiedades y campos con
atributos de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El valor se puede
devolver si no se van a null agregar parámetros dinámicos.

Esta es la implementación predeterminada de


System.Management.Automation.Provider.Ipropertycmdletprovider.Getpropertydynamic
parameters* desde el archivo TemplateProvider.cs proporcionado por Windows
PowerShell.

Borrar propiedades
Para borrar las propiedades, Windows PowerShell proveedor de propiedades debe
implementar el método
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty* para
admitir llamadas desde el Clear-ItemProperty cmdlet . Este método establece una o
varias propiedades para el elemento ubicado en la ruta de acceso especificada.

Esta es la implementación predeterminada de


System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*
desde el archivo TemplateProvider.cs proporcionado por Windows PowerShell.

Cosas que hay que recordar sobre la implementación de


ClearProperty

Se pueden aplicar las condiciones siguientes a la implementación de


System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*:

Al definir la clase de proveedor, un proveedor de propiedades Windows


PowerShell podría declarar funcionalidades de proveedor de ExpandWildcards,
Filter, Include o Exclude, de la enumeración
System.Management.Automation.Provider.Providercapabilities. En estos casos, la
implementación del método
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*
debe asegurarse de que la ruta de acceso pasada al método cumple los requisitos
de las funcionalidades especificadas. Para ello, el método debe tener acceso a la
propiedad adecuada, por ejemplo, las propiedades
System.Management.Automation.Provider.Cmdletprovider.Exclude* y
System.Management.Automation.Provider.Cmdletprovider.Include*.

De forma predeterminada, las invalidaciones de este método no deben recuperar


un lector para los objetos que están ocultos para el usuario a menos que la
propiedad System.Management.Automation.Provider.Cmdletprovider.Force* esté
establecida en true . Se debe escribir un error si la ruta de acceso representa un
elemento que está oculto al usuario y
System.Management.Automation.Provider.Cmdletprovider.Force* está establecido
en false .

La implementación del método


System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*
debe llamar a
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess y
comprobar su valor devuelto antes de realizar cambios en el almacén de datos.
Este método se usa para confirmar la ejecución de una operación antes de realizar
un cambio en el estado del sistema, como borrar el contenido.
System.Management.Automation.Provider.Cmdletprovider.ShouldProcess envía el
nombre del recurso que se va a cambiar al usuario, teniendo en cuenta el runtime
de Windows PowerShell cualquier configuración de línea de comandos o variables
de preferencia para determinar lo que se debe mostrar.

Después de que la llamada a


System.Management.Automation.Provider.Cmdletprovider.ShouldProcess devuelva
, si se pueden realizar modificaciones potencialmente peligrosas del sistema, el
método true
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearproperty*
debe llamar al método
System.Management.Automation.Provider.Cmdletprovider.ShouldContinue. Este
método envía un mensaje de confirmación al usuario para permitir comentarios
adicionales que indiquen que se debe continuar con la operación potencialmente
peligrosa.

Adjuntar parámetros dinámicos al cmdlet


Clear-ItemProperty.
El Clear-ItemProperty cmdlet puede requerir parámetros adicionales que se especifican
dinámicamente en tiempo de ejecución. Para proporcionar estos parámetros dinámicos,
el proveedor de Windows PowerShell debe implementar el método
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearpropertydynam
icparameters*. Este método devuelve un objeto que tiene propiedades y campos con
atributos de análisis similares a una clase de cmdlet o un objeto
System.Management.Automation.Runtimedefinedparameterdictionary. El valor se puede
devolver si no se van a null agregar parámetros dinámicos.
Esta es la implementación predeterminada de
System.Management.Automation.Provider.Ipropertycmdletprovider.Clearpropertydynam
icparameters* desde el archivo TemplateProvider.cs proporcionado por Windows
PowerShell.

Creación del proveedor Windows PowerShell


datos
Vea How to Register Cmdlets, Providers, and Host Applications ( Cómo registrar
cmdlets, proveedores y aplicaciones host).

Consulte también
Proveedor de Windows PowerShell

Diseñar el proveedor Windows PowerShell aplicación

Extensión de tipos de objeto y formato

Cómo registrar cmdlets, proveedores y aplicaciones host


Cómo crear un shell de la consola
Artículo • 27/09/2021

Windows PowerShell proporciona una Make-Shell, también denominada "make-kit", que se


usa para crear un shell de consola que no es extensible. Los shells creados con esta nueva
herramienta no se pueden extender más adelante a través de Windows PowerShell
complemento.

Sintaxis
Esta es la sintaxis que se usa para Make-Shell desde dentro de un archivo make.

make-shell
-out n.exe
-namespace ns
[ -lib libdirectory1[,libdirectory2,..] ]
[ -reference ca1.dll[,ca2.dll,...] ]
[ -formatdata fd1.format.ps1xml[,fd2.format.ps1xml,...] ]
[ -typedata td1.type.ps1xml[,td2.type.ps1xml,...] ]
[ -source c1.cs [,c2.cs,...] ]
[ -authorizationmanager authorizationManagerType ]
[ -win32icon i.ico ]
[ -initscript p.ps1 ]
[ -builtinscript s1.ps1[,s2.ps1,...] ]
[ -resource resourcefile.txt ]
[ -cscflags cscFlags ]
[ -? | -help ]

Parámetros
Esta es una breve descripción de los parámetros de Make-Shell.

U Precaución

Make-Shell no admite las rutas de acceso UNC a los ensamblados.

Parámetro Descripción
Parámetro Descripción

-out n.exe Necesario. Nombre del shell que se genera. La ruta de acceso se
especifica como parte de este parámetro.

Make-shell anexará ".exe" a este valor si no se especifica.


Precaución: No cree un archivo de salida con el mismo nombre que
el archivo de .dll referencia. Si lo intenta, la herramienta Make-Shell
crea un archivo .cs con el mismo nombre, que sobrescribirá el
archivo .cs que tiene el código fuente del cmdlet.

-namespace ns Necesario. Espacio de nombres que se usará para la clase derivada


System.Management.Automation.Runspaces.Runspaceconfiguration
que el kit make genera y compila.

-lib libdirectory1[,libdirectory2,..] Directorios en los que se buscan ensamblados de .NET, incluidos los
ensamblados de Windows PowerShell, los ensamblados
especificados por el parámetro , los ensamblados a los que hace
referencia indirectamente otro ensamblado y los ensamblados del
sistema reference .NET.

-reference ca1.dll[,ca2.dll,...] Lista separada por comas de los ensamblados que se incluirán en el
shell. Estos ensamblados incluyen todos los ensamblados de cmdlet
y proveedor, así como los ensamblados de recursos que se deben
cargar. Si no se especifica este parámetro, se genera un shell que
contiene solo los cmdlets y proveedores principales proporcionados
por Windows PowerShell.

Los ensamblados se pueden especificar mediante su ruta de acceso


completa; de lo contrario, se buscarán mediante la ruta de acceso
especificada por el lib parámetro .

-formatdata Lista separada por comas de datos de formato que se incluirán en


fd1.format.ps1xml[,fd2.format.ps1xml,...] el shell. Si no se especifica este parámetro, se genera un shell que
contiene solo los datos de formato proporcionados por Windows
PowerShell.

-typedata Lista separada por comas de datos de tipo que se incluirán en el


td1.type.ps1xml[,td2.type.ps1xml,...] shell. Si no se especifica este parámetro, se genera un shell que
contiene solo los datos de tipo proporcionados por Windows
PowerShell.
Parámetro Descripción

-source c1.cs [,c2.cs,...] Nombre de un archivo, proporcionado por el desarrollador del


shell, que contiene cualquier código fuente necesario para compilar
el shell.

El archivo de código fuente puede contener cualquiera de los


siguientes códigos fuente:

- Implementación del administrador de autorización que invalida el


administrador de autorización predeterminado. (Esto también se
podría proporcionar compilado en un ensamblado).
- Declaraciones de atributos informativos de ensamblado: como
AssemblyCompanyAttribute, AssemblyCopyrightAttribute,
AssemblyFileVersionAttribute,
AssemblyInformationalVersionAttribute, AssemblyProductAttribute
y AssemblyAttribute.

-authorizationmanager Tipo que contiene la implementación del administrador de


authorizationManagerType autorización. Esto se puede definir en el código fuente o compilarse
en un ensamblado (especificado por el reference parámetro ). Si
no se especifica este parámetro, se usa el administrador de
seguridad predeterminado. El valor debe ser el nombre de tipo
completo, incluidos los espacios de nombres.

-win32icon i.ico Icono del archivo .exe para el shell. Si no se especifica, el shell
tendrá el icono que incluye el compilador de c# (si lo hay).

-initscript p.ps1 Perfil de inicio del shell. El archivo se incluye "tal y como está";
Make-Shell no realiza ninguna comprobación de validez.

-builtinscript s1.ps1[,s2.ps1,...] Lista de scripts integrados para el shell. Estos scripts se detectan
antes que los scripts de la ruta de acceso y su contenido no se
puede cambiar una vez creado el shell.

Los archivos se incluyen "tal y como están"; Make-Shell no realiza


ninguna comprobación de validez.

-resource resourcefile.txt Archivo .txt que contiene recursos de ayuda y banner para el shell.
El primer recurso se denomina ShellHelp y contiene el texto que se
muestra si se invoca el shell con el help parámetro . El segundo
recurso se denomina ShellBanner y contiene el texto y la
información de copyright que se muestran cuando el shell se inicia
en modo interactivo.

Si no se proporciona este parámetro o estos recursos no están


presentes, se usa una ayuda genérica y un banner.

-cscflags cscFlags Marcas que se deben pasar al compilador de C# (csc.exe). Se pasan


sin cambios. Si este parámetro incluye espacios, debe estar entre
comillas dobles.
Parámetro Descripción

-? Muestra el mensaje de copyright y Make-Shell de línea de


comandos.
-help

-verbose Muestra información detallada mientras se crea el shell.

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Conceptos de Windows PowerShell
Artículo • 23/10/2021

Esta sección contiene información conceptual que le ayudará a comprender PowerShell


desde el punto de vista de un desarrollador.

Nombre del tema Descripción

about_Objects Descripción de los objetos de PowerShell. Para obtener más


información, vea Acerca de la creación de objetos.

Creación de espacios de Entornos operativos donde se procesan los comandos. Para


ejecución obtener más información, vea Runspace (Clase).

Extensión de los objetos de Cómo extender objetos de PowerShell. Para obtener más
salida información, consulte Acerca de Types.ps1xml.

Registro de cmdlets Cómo hacer que los módulos y complementos estén


disponibles en PowerShell. Para obtener más información, vea
Módulos y complementos.

Solicitud de confirmación de los Cómo los cmdlets y proveedores solicitan comentarios al


cmdlets usuario antes de realizar una acción.

RuntimeDefinedParameter (clase) Declaraciones de parámetros en tiempo de ejecución.

Espacio de nombres Información general de los espacios de nombres de la API de


System.Management.Automation PowerShell.

Información general sobre Información general sobre los proveedores de PowerShell que
Proveedor de Windows se usan para acceder a los almacenes de datos.
PowerShell

Escritura de la ayuda de los Cómo escribir la Ayuda del cmdlet de PowerShell.


cmdlets de PowerShell

Consulte también
Clase de PowerShell

Referencia de la API de PowerShell

Guía del programador de Windows PowerShell

Escritura de la Ayuda de los módulos de Windows PowerShell

Escritura de un proveedor de Windows PowerShell


Windows PowerShell Referencia de API

Referencia de Windows PowerShell


Código de ejemplo de Windows
PowerShell
Artículo • 27/09/2021

®Windows PowerShell Los ejemplos están disponibles a través de Windows SDK. Esta
sección contiene el código de ejemplo que se incluye en los ejemplos Windows SDK.

7 Nota

Cuando se Windows SDK, se crea un directorio Samples en el que todos los


Windows PowerShell están disponibles. Un directorio de instalación típico es
C:\Archivos de programa\Microsoft SDKs\Windows\v6.0. Inicie Windows
PowerShell y escriba "cd Samples\SysMgmt\PowerShell" para buscar el directorio
Windows PowerShell Samples. En este documento, el Windows PowerShell samples
se conoce como <PowerShell Samples> .

Lista de código de ejemplo


Código de ejemplo Descripción

Ejemplo de código Este es el proveedor descrito en Creación de un proveedor


AccessDbProviderSample01 Windows PowerShell básico.

Ejemplo de código Este es el proveedor descrito en Creación de un proveedor


AccessDbProviderSample02 Windows PowerShell unidad de disco .

Ejemplo de código Este es el proveedor descrito en Creación de un Windows


AccessDbProviderSample03 PowerShell de elementos .

Ejemplo de código Este es el proveedor descrito en Creating a Windows PowerShell


AccessDbProviderSample04 Container Provider.

Ejemplo de código Este es el proveedor descrito en Creación de un Windows


AccessDbProviderSample05 PowerShell de navegación.

Ejemplo de código Este es el proveedor descrito en Creación de un Windows


AccessDbProviderSample06 PowerShell de contenido.

Ejemplos de código Este es el Get-Process ejemplo de cmdlet básico que se describe en


GetProc01 Creación del primer cmdlet.

Ejemplos de código Este es el Get-Process ejemplo de cmdlet descrito en Agregar


GetProc02 parámetros que procesan Command-Line entrada.
Código de ejemplo Descripción

Ejemplos de código Este es el Get-Process ejemplo de cmdlet descrito en Agregar


GetProc03 parámetros que procesan la entrada de canalización.

Ejemplos de código Este es el ejemplo de cmdlet descrito en Agregar informes de


GetProc04 errores no Get-Process terminales al cmdlet.

Ejemplos de código Este cmdlet es similar al cmdlet descrito en Get-Process Adding


GetProc05 Nonterminating Error Reporting to Your Cmdlet.

Ejemplos de código Este es el Stop-Process ejemplo de cmdlet descrito en Creación de


StopProc01 un cmdlet que modifica el sistema.

Ejemplos de código Este es el Stop-Process ejemplo de cmdlet descrito en Agregar


StopProcessSample04 conjuntos de parámetros a un cmdlet.

Ejemplos de código Estos son los ejemplos de código para el espacio de ejecución
Runspace01 descrito en Creación de una aplicación de consola que ejecuta un
comando especificado.

Ejemplos de código En este ejemplo se usa la clase


Runspace02 System.Management.Automation.Runspaceinvoke para ejecutar el
Get-Process cmdlet sincrónicamente.

Ejemplos de código Estos son los ejemplos de código para el espacio de ejecución
Runspace03 descrito en "Crear una aplicación de consola que ejecuta un script
especificado".

Ejemplos de código Este es un ejemplo de código para un espacio de ejecución que usa
Runspace04 la clase System.Management.Automation.Runspaceinvoke para
ejecutar un script que genera un error de terminación.

Ejemplo de código
Runspace05

Ejemplo de código
Runspace06

Ejemplo de código
Runspace07

Ejemplo de código
Runspace08

Ejemplo de código
Runspace09
Código de ejemplo Descripción

Ejemplo de código Este es el código fuente del ejemplo Runspace10, que agrega un
Runspace10 cmdlet a
System.Management.Automation.Runspaces.Runspaceconfiguration
y, a continuación, usa la información de configuración modificada
para crear el espacio de ejecución.

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código
AccessDbProviderSample01
Artículo • 27/09/2021

El código siguiente muestra la implementación del proveedor de Windows PowerShell


descrito en Creación de un proveedor de Windows PowerShell básico. Esta
implementación proporciona métodos para iniciar y detener el proveedor y, aunque no
proporciona un medio para acceder a un almacén de datos o para obtener o establecer
los datos en el almacén de datos, proporciona la funcionalidad básica necesaria para
todos los proveedores.

7 Nota

Puede descargar el archivo de código fuente de C# (AccessDBSampleProvider01.cs)


para este proveedor mediante el Kit de desarrollo de software de Windows para los
componentes en tiempo de ejecución de Windows Vista y Microsoft .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .
Para obtener más información sobre otras implementaciones Windows PowerShell
proveedor, vea Designing Your Windows PowerShell Provider.

Ejemplo de código
C#

using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// Simple provider.
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : CmdletProvider
{
}

#endregion AccessDBProvider
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código
AccessDbProviderSample02
Artículo • 25/09/2021

El código siguiente muestra la implementación del proveedor de Windows PowerShell


descrito en Creación de un proveedor Windows PowerShell unidad de disco. Esta
implementación crea una ruta de acceso, establece una conexión a una base de datos
de Access y, a continuación, quita la unidad.

7 Nota

Puede descargar el archivo de código fuente de C# (AccessDBSampleProvider02.cs)


para este proveedor mediante el Kit de desarrollo de software de Microsoft
Windows para los componentes en tiempo de ejecución de Windows Vista y
Microsoft .NET Framework 3.0. Para obtener instrucciones de descarga, consulte
How to Install Windows PowerShell and Download the Windows PowerShell SDK.
Los archivos de origen descargados están disponibles en el <PowerShell Samples>
directorio . Para obtener más información sobre otras implementaciones Windows
PowerShell proveedor, vea Designing Your Windows PowerShell Provider.

Ejemplo de código
C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// A PowerShell Provider which acts upon a access data store.
/// </summary>
/// <remarks>
/// This example only demonstrates the drive overrides
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : DriveCmdletProvider
{
#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

} // AccessDBProvider

#endregion AccessDBProvider

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;
/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código
AccessDbProviderSample03
Artículo • 06/11/2021

El código siguiente muestra la implementación del proveedor de Windows PowerShell


descrito en Creación de un Windows PowerShell de elementos . Este proveedor que
puede manipular los datos de un almacén de datos.

7 Nota

Puede descargar el archivo de código fuente de C# (AccessDBSampleProvider03.cs)


para este proveedor mediante el Kit de desarrollo de software de Microsoft
Windows para los componentes en tiempo de ejecución de Windows Vista y .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .
Para obtener más información sobre otras implementaciones Windows PowerShell
proveedor de servicios, vea Designing Your Windows PowerShell Provider.

Ejemplo de código
C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Collections.ObjectModel;
using System.Text;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// A PowerShell Provider which acts upon a access database.
/// </summary>
/// <remarks>
/// This example implements the item overloads.
/// </remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]

public class AccessDBProvider : ItemCmdletProvider


{
#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();
builder.Driver = "Microsoft Access Driver (*.mdb)";
builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}

// Get in-memory representation of table


OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out
rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads

#region Helper Methods

/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");
return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath

/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;

if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the path</param>
/// <returns>what the path represents</returns>
private PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;

default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath

/// <summary>
/// Throws an argument exception stating that the specified path does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object representing
/// information about one database table
/// </returns>
private Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;

// iterate through all rows in the schema and create


DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName + "\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count, columns);

results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables

/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
private Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;

} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
private OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName) ||


!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create sql


// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
private DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);

// Create a dataset object which will provide an in-memory


// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
private DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;

return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // SafeConvertRowNumber

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

#endregion Helper Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

private enum PathType { Database, Table, Row, Invalid };

#endregion Private Properties


}

#endregion AccessDBProvider

#region Helper Classes

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#endregion Helper Classes


}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código
AccessDbProviderSample04
Artículo • 25/09/2021

El código siguiente muestra la implementación del proveedor de Windows PowerShell


descrito en Creación de un proveedor Windows PowerShell contenedor . Este proveedor
funciona en almacenes de datos de varias capas. Para este tipo de almacén de datos, el
nivel superior del almacén contiene los elementos raíz y cada nivel posterior se conoce
como nodo de elementos secundarios. Al permitir que el usuario trabaje en estos nodos
secundarios, un usuario puede interactuar jerárquicamente a través del almacén de
datos.

Ejemplo de código
C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Data.OleDb;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// A PowerShell Provider which acts upon an Access database
/// </summary>
/// <remarks>
/// This example implements the container overloads</remarks>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : ContainerCmdletProvider
{

#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}

// Get in-memory representation of table


OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads


#region Container Overloads

/// <summary>
/// Return either the tables in the database or the datarows
/// </summary>
/// <param name="path">The path to the parent</param>
/// <param name="recurse">True to return all child items recursively.
/// </param>
protected override void GetChildItems(string path, bool recurse)
{
// If path represented is a drive then the children in the path
are
// tables. Hence all tables in the drive represented will have to
be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set


then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name,
recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildItems

/// <summary>
/// Return the names of all child items.
/// </summary>
/// <param name="path">The root path.</param>
/// <param name="returnContainers">Not used.</param>
protected override void GetChildNames(string path,
ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row.RowNumber, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildNames

/// <summary>
/// Determines if the specified path has child items.
/// </summary>
/// <param name="path">The path to examine.</param>
/// <returns>
/// True if the specified path has child items.
/// </returns>
protected override bool HasChildItems(string path)
{
if (PathIsDrive(path))
{
return true;
}

return (ChunkPath(path).Length == 1);


} // HasChildItems

/// <summary>
/// Creates a new item at the specified path.
/// </summary>
///
/// <param name="path">
/// The path to the new item.
/// </param>
///
/// <param name="type">
/// Type for the object to create. "Table" for creating a new table
and
/// "Row" for creating a new row in a table.
/// </param>
///
/// <param name="newItemValue">
/// Object for creating new instance of a type at the specified path.
For
/// creating a "Table" the object parameter is ignored and for
creating
/// a "Row" the object must be of type string which will contain
comma
/// separated values of the rows to insert.
/// </param>
protected override void NewItem(string path, string type,
object newItemValue)
{
string tableName;
int rowNumber;
PathType pt = GetNamesFromPath(path, out tableName, out
rowNumber);

if (pt == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

// Check if type is either "table" or "row", if not throw an


// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
&& !String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
WriteError(new ErrorRecord
(new ArgumentException("Type must be either
a table or row"),
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
)
);

throw new ArgumentException("This provider can only create


items of type \"table\" or \"row\"");
}

// Path type is the type of path of the container. So if a drive


// is specified, then a table can be created under it and if a
table
// is specified, then a row can be created under it. For the sake
of
// completeness, if a row is specified, then if the row specified
by
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
// on the number of rows

if (PathIsDrive(path))
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
// Execute command using ODBC connection to create a
table
try
{
// create the table using an sql statement
string newTableName = newItemValue.ToString();

if (!TableNameIsValid(newTableName))
{
return;
}
string sql = "create table " + newTableName
+ " (ID INT)";

// Create the table using the Odbc connection from


the
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

if (ShouldProcess(newTableName, "create"))
{
OdbcCommand cmd = new OdbcCommand(sql,
connection);
cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
}
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
throw new
ArgumentException("A row cannot be created under a
database, specify a path that represents a Table");
}
}// if (PathIsDrive...
else
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
if (rowNumber < 0)
{
throw new
ArgumentException("A table cannot be created
within another table, specify a path that represents a database");
}
else
{
throw new
ArgumentException("A table cannot be created
inside a row, specify a path that represents a database");
}
} //if (String.Equals....
// if path specified is a row, create a new row
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
// The user is required to specify the values to be
inserted
// into the table in a single string separated by commas
string value = newItemValue as string;

if (String.IsNullOrEmpty(value))
{
throw new
ArgumentException("Value argument must have comma
separated values of each column in a row");
}
string[] rowValues = value.Split(',');

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

if (rowValues.Length != table.Columns.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The table has {0} columns and
the value specified must have so many comma separated values",
table.Columns.Count);

throw new ArgumentException(message);


}

if (!Force && (rowNumber >=0 && rowNumber <


table.Rows.Count))
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The row {0} already
exists. To create a new row specify row number as {1}, or specify path to a
table, or use the -Force parameter",
rowNumber,
table.Rows.Count);

throw new ArgumentException(message);


}
if (rowNumber > table.Rows.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"To create a new row specify row
number as {0}, or specify path to a table",
table.Rows.Count);

throw new ArgumentException(message);


}

// Create a new row and update the row with the input
// provided by the user
DataRow row = table.NewRow();
for (int i = 0; i < rowValues.Length; i++)
{
row[i] = rowValues[i];
}
table.Rows.Add(row);

if (ShouldProcess(tableName, "update rows"))


{
// Update the table from memory back to the data
source
da.Update(ds, tableName);
}

}// else if (String...


}// else ...

} // NewItem

/// <summary>
/// Copies an item at the specified path to the location specified
/// </summary>
///
/// <param name="path">
/// Path of the item to copy
/// </param>
///
/// <param name="copyPath">
/// Path of the item to copy to
/// </param>
///
/// <param name="recurse">
/// Tells the provider to recurse subcontainers when copying
/// </param>
///
protected override void CopyItem(string path, string copyPath, bool
recurse)
{
string tableName, copyTableName;
int rowNumber, copyRowNumber;
PathType type = GetNamesFromPath(path, out tableName, out
rowNumber);
PathType copyType = GetNamesFromPath(copyPath, out copyTableName,
out copyRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(copyPath);
}

// Get the table and the table to copy to


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter cda = GetAdapterForTable(copyTableName);


if (cda == null)
{
return;
}

DataSet cds = GetDataSetForTable(cda, copyTableName);


DataTable copyTable = GetDataTable(cds, copyTableName);

// if source represents a table


if (type == PathType.Table)
{
// if copyPath does not represent a table
if (copyType != PathType.Table)
{
ArgumentException e = new ArgumentException("Table can
only be copied on to another table location");

WriteError(new ErrorRecord(e, "PathNotValid",


ErrorCategory.InvalidArgument, copyPath));

throw e;
}

// if table already exists then force parameter should be set


// to force a copy
if (!Force && GetTable(copyTableName) != null)
{
throw new ArgumentException("Specified path already
exists");
}

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];
DataRow copyRow = copyTable.NewRow();

copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
}
} // if (type == ...
// if source represents a row
else
{
if (copyType == PathType.Row)
{
if (!Force && (copyRowNumber < copyTable.Rows.Count))
{
throw new ArgumentException("Specified path already
exists.");
}

DataRow row = table.Rows[rowNumber];


DataRow copyRow = null;

if (copyRowNumber < copyTable.Rows.Count)


{
// copy to an existing row
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
}
else if (copyRowNumber == copyTable.Rows.Count)
{
// copy to the next row in the table that will
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
else
{
// attempting to copy to a nonexistent row or a row
// that cannot be created now - throw an exception
string message =
String.Format(CultureInfo.CurrentCulture,
"The item cannot be specified
to the copied row. Specify row number as {0}, or specify a path to the
table.",
table.Rows.Count);

throw new ArgumentException(message);


}
}
else
{
// destination path specified represents a table,
// create a new row and copy the item
DataRow copyRow = copyTable.NewRow();
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
}

if (ShouldProcess(copyTableName, "CopyItems"))
{
cda.Update(cds, copyTableName);
}

} //CopyItem

/// <summary>
/// Removes (deletes) the item at the specified path
/// </summary>
///
/// <param name="path">
/// The path to the item to remove.
/// </param>
///
/// <param name="recurse">
/// True if all children in a subtree should be removed, false if
only
/// the item at the specified path should be removed. Is applicable
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
protected override void RemoveItem(string path, bool recurse)
{
string tableName;
int rowNumber = 0;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// if recurse flag has been specified, delete all the rows as
well
if (recurse)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

for (int i = 0; i < table.Rows.Count; i++)


{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
RemoveTable(tableName);
}
}//if (recurse...
else
{
// Remove the table
if (ShouldProcess(path, "RemoveItem"))
{
RemoveTable(tableName);
}
}
}
else if (type == PathType.Row)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

table.Rows[rowNumber].Delete();

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
}
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // RemoveItem

#endregion Container Overloads


#region Helper Methods

/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");

return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath

/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;

if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the path</param>
/// <returns>what the path represents</returns>
private PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];
if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;

default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath

/// <summary>
/// Throws an argument exception stating that the specified path does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object representing
/// information about one database table
/// </returns>
private Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;

// iterate through all rows in the schema and create


DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName +
"\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count, columns);

results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables
/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
private Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;

} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Removes the specified table from the database
/// </summary>
/// <param name="tableName">Name of the table to remove</param>
private void RemoveTable(string tableName)
{
// validate if tablename is valid and if table is present
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
{
return;
}

// Execute command using ODBC connection to remove a table


try
{
// delete the table using an sql statement
string sql = "drop table " + tableName;

AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

OdbcCommand cmd = new OdbcCommand(sql, connection);


cmd.ExecuteScalar();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "CannotRemoveSpecifiedTable",
ErrorCategory.InvalidOperation, null)
);
}

} // RemoveTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
private OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName)


||!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create sql


// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Set the delete cmd for the table here


sql = "Delete from " + tableName + " where ID = ?";
da.DeleteCommand = new OdbcCommand(sql, connection);

// Specify a DeleteCommand parameter based on the "ID"


// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";

// Create an InsertCommand based on the sql string


// Insert into "tablename" values (?,?,?)" where
// ? represents a column in the table. Note that
// the number of ? will be equal to the number of
// columnds
DataSet ds = new DataSet();

da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;

sql = "Insert into " + tableName + " values ( ";


for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
sql += "?, ";
}
sql = sql.Substring(0, sql.Length - 2);
sql += ")";
da.InsertCommand = new OdbcCommand(sql, connection);
// Create parameters for the InsertCommand based on the
// captions of each column
for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
private DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);

// Create a dataset object which will provide an in-memory


// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
private DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;

return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // SafeConvertRowNumber

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

/// <summary>
/// Gets the next available ID in the table
/// </summary>
/// <param name="table">DataTable object representing the table to
/// search for ID</param>
/// <returns>next available id</returns>
private int GetNextID(DataTable table)
{
int big = 0;
int id = 0;

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];

object o = row["ID"];

if (o.GetType().Name.Equals("Int16"))
{
id = (int)(short)o;
}
else
{
id = (int)o;
}

if (big < id)


{
big = id;
}
}

big++;
return big;
}

#endregion Helper Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

private enum PathType { Database, Table, Row, Invalid };

#endregion Private Properties


}

#endregion AccessDBProvider

#region Helper Classes

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }
} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#endregion Helper Classes


}

Consulte también
Windows PowerShell SDK
Ejemplo de código
AccessDbProviderSample05
Artículo • 27/09/2021

En el código siguiente se muestra la implementación del proveedor de Windows


PowerShell de navegación que se describe en Creación de un Windows PowerShell de
navegación. Este proveedor admite comandos recursivos, contenedores anidados y
rutas de acceso relativas que le permiten navegar por el almacén de datos.

Ejemplo de código
C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections.ObjectModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider

/// <summary>
/// This example implements the navigation methods.
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider
{

#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file and
set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));

return;
}

// Get in-memory representation of table


OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads

#region Container Overloads

/// <summary>
/// Return either the tables in the database or the datarows
/// </summary>
/// <param name="path">The path to the parent</param>
/// <param name="recurse">True to return all child items recursively.
/// </param>
protected override void GetChildItems(string path, bool recurse)
{
// If path represented is a drive then the children in the path
are
// tables. Hence all tables in the drive represented will have to
be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set


then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name,
recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildItems

/// <summary>
/// Return the names of all child items.
/// </summary>
/// <param name="path">The root path.</param>
/// <param name="returnContainers">Not used.</param>
protected override void GetChildNames(string path,
ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);

WriteItemObject(row.RowNumber, path, false);


}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildNames

/// <summary>
/// Determines if the specified path has child items.
/// </summary>
/// <param name="path">The path to examine.</param>
/// <returns>
/// True if the specified path has child items.
/// </returns>
protected override bool HasChildItems(string path)
{
if (PathIsDrive(path))
{
return true;
}

return (ChunkPath(path).Length == 1);


} // HasChildItems

/// <summary>
/// Creates a new item at the specified path.
/// </summary>
///
/// <param name="path">
/// The path to the new item.
/// </param>
///
/// <param name="type">
/// Type for the object to create. "Table" for creating a new table
and
/// "Row" for creating a new row in a table.
/// </param>
///
/// <param name="newItemValue">
/// Object for creating new instance of a type at the specified path.
For
/// creating a "Table" the object parameter is ignored and for
creating
/// a "Row" the object must be of type string which will contain
comma
/// separated values of the rows to insert.
/// </param>
protected override void NewItem(string path, string type,
object newItemValue)
{
string tableName;
int rowNumber;

PathType pt = GetNamesFromPath(path, out tableName, out


rowNumber);

if (pt == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

// Check if type is either "table" or "row", if not throw an


// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
&& !String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
WriteError(new ErrorRecord
(new ArgumentException("Type must be either
a table or row"),
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
)
);

throw new ArgumentException("This provider can only create


items of type \"table\" or \"row\"");
}

// Path type is the type of path of the container. So if a drive


// is specified, then a table can be created under it and if a
table
// is specified, then a row can be created under it. For the sake
of
// completeness, if a row is specified, then if the row specified
by
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
// on the number of rows

if (PathIsDrive(path))
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
// Execute command using ODBC connection to create a
table
try
{
// create the table using an sql statement
string newTableName = newItemValue.ToString();
string sql = "create table " + newTableName
+ " (ID INT)";

// Create the table using the Odbc connection from


the
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;
if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

if (ShouldProcess(newTableName, "create"))
{
OdbcCommand cmd = new OdbcCommand(sql,
connection);
cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
}
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
throw new
ArgumentException("A row cannot be created under a
database, specify a path that represents a Table");
}
}// if (PathIsDrive...
else
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
if (rowNumber < 0)
{
throw new
ArgumentException("A table cannot be created
within another table, specify a path that represents a database");
}
else
{
throw new
ArgumentException("A table cannot be created
inside a row, specify a path that represents a database");
}
} //if (String.Equals....
// if path specified is a row, create a new row
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
// The user is required to specify the values to be
inserted
// into the table in a single string separated by commas
string value = newItemValue as string;
if (String.IsNullOrEmpty(value))
{
throw new
ArgumentException("Value argument must have comma
separated values of each column in a row");
}
string[] rowValues = value.Split(',');

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

if (rowValues.Length != table.Columns.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The table has {0} columns and
the value specified must have so many comma separated values",
table.Columns.Count);

throw new ArgumentException(message);


}

if (!Force && (rowNumber >= 0 && rowNumber <


table.Rows.Count))
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The row {0} already exists. To
create a new row specify row number as {1}, or specify path to a table, or
use the -Force parameter",
rowNumber,
table.Rows.Count);

throw new ArgumentException(message);


}

if (rowNumber > table.Rows.Count)


{
string message =
String.Format(CultureInfo.CurrentCulture,
"To create a new row specify row
number as {0}, or specify path to a table",
table.Rows.Count);

throw new ArgumentException(message);


}
// Create a new row and update the row with the input
// provided by the user
DataRow row = table.NewRow();
for (int i = 0; i < rowValues.Length; i++)
{
row[i] = rowValues[i];
}
table.Rows.Add(row);

if (ShouldProcess(tableName, "update rows"))


{
// Update the table from memory back to the data
source
da.Update(ds, tableName);
}

}// else if (String...


}// else ...

} // NewItem

/// <summary>
/// Copies an item at the specified path to the location specified
/// </summary>
///
/// <param name="path">
/// Path of the item to copy
/// </param>
///
/// <param name="copyPath">
/// Path of the item to copy to
/// </param>
///
/// <param name="recurse">
/// Tells the provider to recurse subcontainers when copying
/// </param>
///
protected override void CopyItem(string path, string copyPath, bool
recurse)
{
string tableName, copyTableName;
int rowNumber, copyRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
PathType copyType = GetNamesFromPath(copyPath, out copyTableName,
out copyRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(copyPath);
}

// Get the table and the table to copy to


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter cda = GetAdapterForTable(copyTableName);


if (cda == null)
{
return;
}

DataSet cds = GetDataSetForTable(cda, copyTableName);


DataTable copyTable = GetDataTable(cds, copyTableName);

// if source represents a table


if (type == PathType.Table)
{
// if copyPath does not represent a table
if (copyType != PathType.Table)
{
ArgumentException e = new ArgumentException("Table can
only be copied on to another table location");

WriteError(new ErrorRecord(e, "PathNotValid",


ErrorCategory.InvalidArgument, copyPath));

throw e;
}

// if table already exists then force parameter should be set


// to force a copy
if (!Force && GetTable(copyTableName) != null)
{
throw new ArgumentException("Specified path already
exists");
}

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];
DataRow copyRow = copyTable.NewRow();

copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
}
} // if (type == ...
// if source represents a row
else
{
if (copyType == PathType.Row)
{
if (!Force && (copyRowNumber < copyTable.Rows.Count))
{
throw new ArgumentException("Specified path already
exists.");
}

DataRow row = table.Rows[rowNumber];


DataRow copyRow = null;

if (copyRowNumber < copyTable.Rows.Count)


{
// copy to an existing row
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
}
else if (copyRowNumber == copyTable.Rows.Count)
{
// copy to the next row in the table that will
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
else
{
// attempting to copy to a nonexistent row or a row
// that cannot be created now - throw an exception
string message =
String.Format(CultureInfo.CurrentCulture,
"The item cannot be specified to
the copied row. Specify row number as {0}, or specify a path to the table.",
table.Rows.Count);

throw new ArgumentException(message);


}
}
else
{
// destination path specified represents a table,
// create a new row and copy the item
DataRow copyRow = copyTable.NewRow();
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
}

if (ShouldProcess(copyTableName, "CopyItems"))
{
cda.Update(cds, copyTableName);
}

} //CopyItem

/// <summary>
/// Removes (deletes) the item at the specified path
/// </summary>
///
/// <param name="path">
/// The path to the item to remove.
/// </param>
///
/// <param name="recurse">
/// True if all children in a subtree should be removed, false if
only
/// the item at the specified path should be removed. Is applicable
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
protected override void RemoveItem(string path, bool recurse)
{
string tableName;
int rowNumber = 0;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// if recurse flag has been specified, delete all the rows as
well
if (recurse)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

for (int i = 0; i < table.Rows.Count; i++)


{
table.Rows[i].Delete();
}
if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
RemoveTable(tableName);
}
}//if (recurse...
else
{
// Remove the table
if (ShouldProcess(path, "RemoveItem"))
{
RemoveTable(tableName);
}
}
}
else if (type == PathType.Row)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

table.Rows[rowNumber].Delete();

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
}
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // RemoveItem

#endregion Container Overloads

#region Navigation

/// <summary>
/// Determine if the path specified is that of a container.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>True if the path specifies a container.</returns>
protected override bool IsItemContainer(string path)
{
if (PathIsDrive(path))
{
return true;
}

string[] pathChunks = ChunkPath(path);


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...

return false;
} // IsItemContainer

/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// <param name="path">
/// The full or partial provider specific path
/// </param>
///
/// <returns>
/// The leaf element in the path
/// </returns>
protected override string GetChildName(string path)
{
if (PathIsDrive(path))
{
return path;
}

string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
return tableName;
}
else if (type == PathType.Row)
{
return rowNumber.ToString(CultureInfo.CurrentCulture);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

return null;
}

/// <summary>
/// Removes the child segment of the path and returns the remaining
/// parent portion
/// </summary>
///
/// <param name="path">
/// A full or partial provider specific path. The path may be to an
/// item that may or may not exist.
/// </param>
///
/// <param name="root">
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// operation. If this parameter is not null or empty the result
/// of the method should not be a path to a container that is a
/// parent or in a different tree than the root.
/// </param>
///
/// <returns></returns>

protected override string GetParentPath(string path, string root)


{
// If root is specified then the path has to contain
// the root. If not nothing should be returned
if (!String.IsNullOrEmpty(root))
{
if (!path.Contains(root))
{
return null;
}
}

return path.Substring(0, path.LastIndexOf(pathSeparator,


StringComparison.OrdinalIgnoreCase));
}

/// <summary>
/// Joins two strings with a provider specific path separator.
/// </summary>
///
/// <param name="parent">
/// The parent segment of a path to be joined with the child.
/// </param>
///
/// <param name="child">
/// The child segment of a path to be joined with the parent.
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// joined by a path separator.
/// </returns>

protected override string MakePath(string parent, string child)


{
string result;

string normalParent = NormalizePath(parent);


normalParent = RemoveDriveFromPath(normalParent);
string normalChild = NormalizePath(child);
normalChild = RemoveDriveFromPath(normalChild);

if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
result = String.Empty;
}
else if (String.IsNullOrEmpty(normalParent) &&
!String.IsNullOrEmpty(normalChild))
{
result = normalChild;
}
else if (!String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent;
}
else
{
result = normalParent + pathSeparator;
}
} // else if (!String...
else
{
if (!normalParent.Equals(String.Empty) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent + pathSeparator;
}
else
{
result = normalParent;
}

if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result += normalChild.Substring(1);
}
else
{
result += normalChild;
}
} // else

return result;
} // MakePath

/// <summary>
/// Normalizes the path that was passed in and returns the normalized
/// path as a relative path to the basePath that was passed.
/// </summary>
///
/// <param name="path">
/// A fully qualified provider specific path to an item. The item
/// should exist or the provider should write out an error.
/// </param>
///
/// <param name="basepath">
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// A normalized path that is relative to the basePath that was
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>

protected override string NormalizeRelativePath(string path,


string basepath)
{
// Normalize the paths first
string normalPath = NormalizePath(path);
normalPath = RemoveDriveFromPath(normalPath);
string normalBasePath = NormalizePath(basepath);
normalBasePath = RemoveDriveFromPath(normalBasePath);

if (String.IsNullOrEmpty(normalBasePath))
{
return normalPath;
}
else
{
if (!normalPath.Contains(normalBasePath))
{
return null;
}

return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
}
}

/// <summary>
/// Moves the item specified by the path to the specified destination
/// </summary>
///
/// <param name="path">
/// The path to the item to be moved
/// </param>
///
/// <param name="destination">
/// The path of the destination container
/// </param>

protected override void MoveItem(string path, string destination)


{
// Get type, table name and rowNumber from the path
string tableName, destTableName;
int rowNumber, destRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

PathType destType = GetNamesFromPath(destination, out


destTableName,
out destRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (destType == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(destination);
}

if (type == PathType.Table)
{
ArgumentException e = new ArgumentException("Move not
supported for tables");

WriteError(new ErrorRecord(e, "MoveNotSupported",


ErrorCategory.InvalidArgument, path));

throw e;
}
else
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter dda = GetAdapterForTable(destTableName);


if (dda == null)
{
return;
}

DataSet dds = GetDataSetForTable(dda, destTableName);


DataTable destTable = GetDataTable(dds, destTableName);
DataRow row = table.Rows[rowNumber];

if (destType == PathType.Table)
{
DataRow destRow = destTable.NewRow();

destRow.ItemArray = row.ItemArray;
}
else
{
DataRow destRow = destTable.Rows[destRowNumber];

destRow.ItemArray = row.ItemArray;
}

// Update the changes


if (ShouldProcess(path, "MoveItem"))
{
WriteItemObject(row, path, false);
dda.Update(dds, destTableName);
}
}
}

#endregion Navigation

#region Helper Methods

/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");

return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath

/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;

if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
/// <param name="path">Path from which drive needs to be
removed</param>
/// <returns>Path with drive information removed</returns>
private string RemoveDriveFromPath(string path)
{
string result = path;
string root;

if (this.PSDriveInfo == null)
{
root = String.Empty;
}
else
{
root = this.PSDriveInfo.Root;
}

if (result == null)
{
result = String.Empty;
}

if (result.Contains(root))
{
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
}

return result;
}

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the path</param>
/// <returns>what the path represents</returns>
private PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;

default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath
/// <summary>
/// Throws an argument exception stating that the specified path does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object representing
/// information about one database table
/// </returns>
private Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;

// iterate through all rows in the schema and create


DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName + "\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count, columns);

results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables

/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
private Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;
} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Removes the specified table from the database
/// </summary>
/// <param name="tableName">Name of the table to remove</param>
private void RemoveTable(string tableName)
{
// validate if tablename is valid and if table is present
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
{
return;
}

// Execute command using ODBC connection to remove a table


try
{
// delete the table using an sql statement
string sql = "drop table " + tableName;

AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

OdbcCommand cmd = new OdbcCommand(sql, connection);


cmd.ExecuteScalar();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "CannotRemoveSpecifiedTable",
ErrorCategory.InvalidOperation, null)
);
}

} // RemoveTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
private OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName) ||


!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create sql


// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Set the delete cmd for the table here


sql = "Delete from " + tableName + " where ID = ?";
da.DeleteCommand = new OdbcCommand(sql, connection);

// Specify a DeleteCommand parameter based on the "ID"


// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";

// Create an InsertCommand based on the sql string


// Insert into "tablename" values (?,?,?)" where
// ? represents a column in the table. Note that
// the number of ? will be equal to the number of
// columnds
DataSet ds = new DataSet();

da.FillSchema(ds, SchemaType.Source);
ds.Locale = CultureInfo.InvariantCulture;

sql = "Insert into " + tableName + " values ( ";


for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
sql += "?, ";
}
sql = sql.Substring(0, sql.Length - 2);
sql += ")";
da.InsertCommand = new OdbcCommand(sql, connection);

// Create parameters for the InsertCommand based on the


// captions of each column
for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
private DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);
// Create a dataset object which will provide an in-memory
// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
private DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;

return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // SafeConvertRowNumber

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

/// <summary>
/// Gets the next available ID in the table
/// </summary>
/// <param name="table">DataTable object representing the table to
/// search for ID</param>
/// <returns>next available id</returns>
private int GetNextID(DataTable table)
{
int big = 0;

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];

int id = (int)row["ID"];

if (big < id)


{
big = id;
}
}

big++;
return big;
}

#endregion Helper Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

private enum PathType { Database, Table, Row, Invalid };

#endregion Private Properties

} // AccessDBProvider

#endregion AccessDBProvider

#region Helper Classes

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#endregion Helper Classes


}

Consulte también
Windows PowerShell SDK
Ejemplo de código
AccessDbProviderSample06
Artículo • 25/09/2021

En el código siguiente se muestra la implementación del proveedor Windows


PowerShell contenido descrito en Creación de un Windows PowerShell de contenido.
Este proveedor permite al usuario manipular el contenido de los elementos de un
almacén de datos.

7 Nota

Puede descargar el archivo de código fuente de C# (AccessDBSampleProvider06.cs)


para este proveedor mediante el Kit de desarrollo de software de Microsoft
Windows para los componentes en tiempo de ejecución de Windows Vista y
Microsoft .NET Framework 3.0. Para obtener instrucciones de descarga, consulte
How to Install Windows PowerShell and Download the Windows PowerShell SDK.
Los archivos de origen descargados están disponibles en el <PowerShell Samples>
directorio . Para obtener más información sobre otras implementaciones Windows
PowerShell proveedor de recursos, vea Designing Your Windows PowerShell
Provider.

Ejemplo de código
C#

using System;
using System.IO;
using System.Data;
using System.Data.Odbc;
using System.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Provider;
using System.Text;
using System.Text.RegularExpressions;
using System.ComponentModel;
using System.Globalization;

namespace Microsoft.Samples.PowerShell.Providers
{
#region AccessDBProvider
/// <summary>
/// This example implements the content methods.
/// </summary>
[CmdletProvider("AccessDB", ProviderCapabilities.None)]
public class AccessDBProvider : NavigationCmdletProvider,
IContentCmdletProvider
{

#region Drive Manipulation

/// <summary>
/// Create a new drive. Create a connection to the database file
and set
/// the Connection property in the PSDriveInfo.
/// </summary>
/// <param name="drive">
/// Information describing the drive to add.
/// </param>
/// <returns>The added drive.</returns>
protected override PSDriveInfo NewDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
null)
);

return null;
}

// check if drive root is not null or empty


// and if its an existing file
if (String.IsNullOrEmpty(drive.Root) || (File.Exists(drive.Root)
== false))
{
WriteError(new ErrorRecord(
new ArgumentException("drive.Root"),
"NoRoot",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// create a new drive and create an ODBC connection to the new


drive
AccessDBPSDriveInfo accessDBPSDriveInfo = new
AccessDBPSDriveInfo(drive);

OdbcConnectionStringBuilder builder = new


OdbcConnectionStringBuilder();

builder.Driver = "Microsoft Access Driver (*.mdb)";


builder.Add("DBQ", drive.Root);

OdbcConnection conn = new


OdbcConnection(builder.ConnectionString);
conn.Open();
accessDBPSDriveInfo.Connection = conn;

return accessDBPSDriveInfo;
} // NewDrive

/// <summary>
/// Removes a drive from the provider.
/// </summary>
/// <param name="drive">The drive to remove.</param>
/// <returns>The drive removed.</returns>
protected override PSDriveInfo RemoveDrive(PSDriveInfo drive)
{
// check if drive object is null
if (drive == null)
{
WriteError(new ErrorRecord(
new ArgumentNullException("drive"),
"NullDrive",
ErrorCategory.InvalidArgument,
drive)
);

return null;
}

// close ODBC connection to the drive


AccessDBPSDriveInfo accessDBPSDriveInfo = drive as
AccessDBPSDriveInfo;

if (accessDBPSDriveInfo == null)
{
return null;
}
accessDBPSDriveInfo.Connection.Close();

return accessDBPSDriveInfo;
} // RemoveDrive

#endregion Drive Manipulation

#region Item Methods

/// <summary>
/// Retrieves an item using the specified path.
/// </summary>
/// <param name="path">The path to the item to return.</param>
protected override void GetItem(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
WriteItemObject(this.PSDriveInfo, path, true);
return;
}// if (PathIsDrive...

// Get table name and row information from the path and do
// necessary actions
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
DatabaseTableInfo table = GetTable(tableName);
WriteItemObject(table, path, true);
}
else if (type == PathType.Row)
{
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path, false);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // GetItem

/// <summary>
/// Set the content of a row of data specified by the supplied path
/// parameter.
/// </summary>
/// <param name="path">Specifies the path to the row whose columns
/// will be updated.</param>
/// <param name="values">Comma separated string of values</param>
protected override void SetItem(string path, object values)
{
// Get type, table name and row number from the path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Row)
{
WriteError(new ErrorRecord(new NotSupportedException(
"SetNotSupported"), "",
ErrorCategory.InvalidOperation, path));
return;
}

// Get in-memory representation of table


OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}
DataSet ds = GetDataSetForTable(da, tableName);
DataTable table = GetDataTable(ds, tableName);

if (rowNumber >= table.Rows.Count)


{
// The specified row number has to be available. If not
// NewItem has to be used to add a new row
throw new ArgumentException("Row specified is not
available");
} // if (rowNum...

string[] colValues = (values as string).Split(',');

// set the specified row


DataRow row = table.Rows[rowNumber];

for (int i = 0; i < colValues.Length; i++)


{
row[i] = colValues[i];
}

// Update the table


if (ShouldProcess(path, "SetItem"))
{
da.Update(ds, tableName);
}

} // SetItem

/// <summary>
/// Test to see if the specified item exists.
/// </summary>
/// <param name="path">The path to the item to verify.</param>
/// <returns>True if the item is found.</returns>
protected override bool ItemExists(string path)
{
// check if the path represented is a drive
if (PathIsDrive(path))
{
return true;
}

// Obtain type, table name and row number from path


string tableName;
int rowNumber;
PathType type = GetNamesFromPath(path, out tableName, out
rowNumber);

DatabaseTableInfo table = GetTable(tableName);

if (type == PathType.Table)
{
// if specified path represents a table then
DatabaseTableInfo
// object for the same should exist
if (table != null)
{
return true;
}
}
else if (type == PathType.Row)
{
// if specified path represents a row then DatabaseTableInfo
should
// exist for the table and then specified row number must be
within
// the maximum row count in the table
if (table != null && rowNumber < table.RowCount)
{
return true;
}
}

return false;

} // ItemExists

/// <summary>
/// Test to see if the specified path is syntactically valid.
/// </summary>
/// <param name="path">The path to validate.</param>
/// <returns>True if the specified path is valid.</returns>
protected override bool IsValidPath(string path)
{
bool result = true;

// check if the path is null or empty


if (String.IsNullOrEmpty(path))
{
result = false;
}

// convert all separators in the path to a uniform one


path = NormalizePath(path);

// split the path into individual chunks


string[] pathChunks = path.Split(pathSeparator.ToCharArray());

foreach (string pathChunk in pathChunks)


{
if (pathChunk.Length == 0)
{
result = false;
}
}
return result;
} // IsValidPath

#endregion Item Overloads

#region Container Overloads

/// <summary>
/// Return either the tables in the database or the datarows
/// </summary>
/// <param name="path">The path to the parent</param>
/// <param name="recurse">True to return all child items
recursively.
/// </param>
protected override void GetChildItems(string path, bool recurse)
{
// If path represented is a drive then the children in the path
are
// tables. Hence all tables in the drive represented will have
to be
// returned
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table, path, true);

// if the specified item exists and recurse has been set


then
// all child items within it have to be obtained as well
if (ItemExists(path) && recurse)
{
GetChildItems(path + pathSeparator + table.Name,
recurse);
}
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get the table name, row number and type of path from the
// path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Obtain all the rows within the table
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);
WriteItemObject(row, path + pathSeparator +
row.RowNumber,
false);
}
else
{
// In this case, the path specified is not valid
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildItems

/// <summary>
/// Return the names of all child items.
/// </summary>
/// <param name="path">The root path.</param>
/// <param name="returnContainers">Not used.</param>
protected override void GetChildNames(string path,
ReturnContainers returnContainers)
{
// If the path represented is a drive, then the child items are
// tables. get the names of all the tables in the drive.
if (PathIsDrive(path))
{
foreach (DatabaseTableInfo table in GetTables())
{
WriteItemObject(table.Name, path, true);
} // foreach (DatabaseTableInfo...
} // if (PathIsDrive...
else
{
// Get type, table name and row number from path specified
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
// Get all the rows in the table and then write out the
// row numbers.
foreach (DatabaseRowInfo row in GetRows(tableName))
{
WriteItemObject(row.RowNumber, path, false);
} // foreach (DatabaseRowInfo...
}
else if (type == PathType.Row)
{
// In this case the user has directly specified a row,
hence
// just give that particular row
DatabaseRowInfo row = GetRow(tableName, rowNumber);

WriteItemObject(row.RowNumber, path, false);


}
else
{
ThrowTerminatingInvalidPathException(path);
}
} // else
} // GetChildNames

/// <summary>
/// Determines if the specified path has child items.
/// </summary>
/// <param name="path">The path to examine.</param>
/// <returns>
/// True if the specified path has child items.
/// </returns>
protected override bool HasChildItems(string path)
{
if (PathIsDrive(path))
{
return true;
}

return (ChunkPath(path).Length == 1);


} // HasChildItems

/// <summary>
/// Creates a new item at the specified path.
/// </summary>
///
/// <param name="path">
/// The path to the new item.
/// </param>
///
/// <param name="type">
/// Type for the object to create. "Table" for creating a new table
and
/// "Row" for creating a new row in a table.
/// </param>
///
/// <param name="newItemValue">
/// Object for creating new instance of a type at the specified
path. For
/// creating a "Table" the object parameter is ignored and for
creating
/// a "Row" the object must be of type string which will contain
comma
/// separated values of the rows to insert.
/// </param>
protected override void NewItem(string path, string type,
object newItemValue)
{
string tableName;
int rowNumber;

PathType pt = GetNamesFromPath(path, out tableName, out


rowNumber);

if (pt == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

// Check if type is either "table" or "row", if not throw an


// exception
if (!String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase)
&& !String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
WriteError(new ErrorRecord
(new ArgumentException("Type must be
either a table or row"),
"CannotCreateSpecifiedObject",
ErrorCategory.InvalidArgument,
path
)
);

throw new ArgumentException("This provider can only create


items of type \"table\" or \"row\"");
}

// Path type is the type of path of the container. So if a drive


// is specified, then a table can be created under it and if a
table
// is specified, then a row can be created under it. For the
sake of
// completeness, if a row is specified, then if the row
specified by
// the path does not exist, a new row is created. However, the
row
// number may not match as the row numbers only get incremented
based
// on the number of rows

if (PathIsDrive(path))
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
// Execute command using ODBC connection to create a
table
try
{
// create the table using an sql statement
string newTableName = newItemValue.ToString();
string sql = "create table " + newTableName
+ " (ID INT)";

// Create the table using the Odbc connection from


the
// drive.
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

if (ShouldProcess(newTableName, "create"))
{
OdbcCommand cmd = new OdbcCommand(sql,
connection);
cmd.ExecuteScalar();
}
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex,
"CannotCreateSpecifiedTable",
ErrorCategory.InvalidOperation, path)
);
}
} // if (String...
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
throw new
ArgumentException("A row cannot be created under a
database, specify a path that represents a Table");
}
}// if (PathIsDrive...
else
{
if (String.Equals(type, "table",
StringComparison.OrdinalIgnoreCase))
{
if (rowNumber < 0)
{
throw new
ArgumentException("A table cannot be created
within another table, specify a path that represents a database");
}
else
{
throw new
ArgumentException("A table cannot be created
inside a row, specify a path that represents a database");
}
} //if (String.Equals....
// if path specified is a row, create a new row
else if (String.Equals(type, "row",
StringComparison.OrdinalIgnoreCase))
{
// The user is required to specify the values to be
inserted
// into the table in a single string separated by commas
string value = newItemValue as string;

if (String.IsNullOrEmpty(value))
{
throw new
ArgumentException("Value argument must have
comma separated values of each column in a row");
}
string[] rowValues = value.Split(',');

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

if (rowValues.Length != table.Columns.Count)
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The table has {0} columns and
the value specified must have so many comma separated values",
table.Columns.Count);

throw new ArgumentException(message);


}

if (!Force && (rowNumber >= 0 && rowNumber <


table.Rows.Count))
{
string message =
String.Format(CultureInfo.CurrentCulture,
"The row {0} already exists. To
create a new row specify row number as {1}, or specify path to a table, or
use the -Force parameter",
rowNumber,
table.Rows.Count);

throw new ArgumentException(message);


}

if (rowNumber > table.Rows.Count)


{
string message =
String.Format(CultureInfo.CurrentCulture,
"To create a new row specify row
number as {0}, or specify path to a table",
table.Rows.Count);

throw new ArgumentException(message);


}

// Create a new row and update the row with the input
// provided by the user
DataRow row = table.NewRow();
for (int i = 0; i < rowValues.Length; i++)
{
row[i] = rowValues[i];
}
table.Rows.Add(row);

if (ShouldProcess(tableName, "update rows"))


{
// Update the table from memory back to the data
source
da.Update(ds, tableName);
}

}// else if (String...


}// else ...

} // NewItem

/// <summary>
/// Copies an item at the specified path to the location specified
/// </summary>
///
/// <param name="path">
/// Path of the item to copy
/// </param>
///
/// <param name="copyPath">
/// Path of the item to copy to
/// </param>
///
/// <param name="recurse">
/// Tells the provider to recurse subcontainers when copying
/// </param>
///
protected override void CopyItem(string path, string copyPath, bool
recurse)
{
string tableName, copyTableName;
int rowNumber, copyRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
PathType copyType = GetNamesFromPath(copyPath, out
copyTableName, out copyRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(copyPath);
}

// Get the table and the table to copy to


OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter cda = GetAdapterForTable(copyTableName);


if (cda == null)
{
return;
}

DataSet cds = GetDataSetForTable(cda, copyTableName);


DataTable copyTable = GetDataTable(cds, copyTableName);

// if source represents a table


if (type == PathType.Table)
{
// if copyPath does not represent a table
if (copyType != PathType.Table)
{
ArgumentException e = new ArgumentException("Table can
only be copied on to another table location");

WriteError(new ErrorRecord(e, "PathNotValid",


ErrorCategory.InvalidArgument, copyPath));

throw e;
}
// if table already exists then force parameter should be
set
// to force a copy
if (!Force && GetTable(copyTableName) != null)
{
throw new ArgumentException("Specified path already
exists");
}

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];
DataRow copyRow = copyTable.NewRow();

copyRow.ItemArray = row.ItemArray;
copyTable.Rows.Add(copyRow);
}
} // if (type == ...
// if source represents a row
else
{
if (copyType == PathType.Row)
{
if (!Force && (copyRowNumber < copyTable.Rows.Count))
{
throw new ArgumentException("Specified path already
exists.");
}

DataRow row = table.Rows[rowNumber];


DataRow copyRow = null;

if (copyRowNumber < copyTable.Rows.Count)


{
// copy to an existing row
copyRow = copyTable.Rows[copyRowNumber];
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
}
else if (copyRowNumber == copyTable.Rows.Count)
{
// copy to the next row in the table that will
// be created
copyRow = copyTable.NewRow();
copyRow.ItemArray = row.ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
else
{
// attempting to copy to a nonexistent row or a row
// that cannot be created now - throw an exception
string message =
String.Format(CultureInfo.CurrentCulture,
"The item cannot be specified to
the copied row. Specify row number as {0}, or specify a path to the table.",
table.Rows.Count);

throw new ArgumentException(message);


}
}
else
{
// destination path specified represents a table,
// create a new row and copy the item
DataRow copyRow = copyTable.NewRow();
copyRow.ItemArray = table.Rows[rowNumber].ItemArray;
copyRow[0] = GetNextID(copyTable);
copyTable.Rows.Add(copyRow);
}
}

if (ShouldProcess(copyTableName, "CopyItems"))
{
cda.Update(cds, copyTableName);
}

} //CopyItem

/// <summary>
/// Removes (deletes) the item at the specified path
/// </summary>
///
/// <param name="path">
/// The path to the item to remove.
/// </param>
///
/// <param name="recurse">
/// True if all children in a subtree should be removed, false if
only
/// the item at the specified path should be removed. Is applicable
/// only for container (table) items. Its ignored otherwise (even if
/// specified).
/// </param>
///
/// <remarks>
/// There are no elements in this store which are hidden from the
user.
/// Hence this method will not check for the presence of the Force
/// parameter
/// </remarks>
///
protected override void RemoveItem(string path, bool recurse)
{
string tableName;
int rowNumber = 0;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);
if (type == PathType.Table)
{
// if recurse flag has been specified, delete all the rows
as well
if (recurse)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

for (int i = 0; i < table.Rows.Count; i++)


{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
RemoveTable(tableName);
}
}//if (recurse...
else
{
// Remove the table
if (ShouldProcess(path, "RemoveItem"))
{
RemoveTable(tableName);
}
}
}
else if (type == PathType.Row)
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

table.Rows[rowNumber].Delete();

if (ShouldProcess(path, "RemoveItem"))
{
da.Update(ds, tableName);
}
}
else
{
ThrowTerminatingInvalidPathException(path);
}

} // RemoveItem

#endregion Container Overloads

#region Navigation

/// <summary>
/// Determine if the path specified is that of a container.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>True if the path specifies a container.</returns>
protected override bool IsItemContainer(string path)
{
if (PathIsDrive(path))
{
return true;
}

string[] pathChunks = ChunkPath(path);


string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
foreach (DatabaseTableInfo ti in GetTables())
{
if (string.Equals(ti.Name, tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
} // foreach (DatabaseTableInfo...
} // if (pathChunks...

return false;
} // IsItemContainer

/// <summary>
/// Get the name of the leaf element in the specified path
/// </summary>
///
/// <param name="path">
/// The full or partial provider specific path
/// </param>
///
/// <returns>
/// The leaf element in the path
/// </returns>
protected override string GetChildName(string path)
{
if (PathIsDrive(path))
{
return path;
}

string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Table)
{
return tableName;
}
else if (type == PathType.Row)
{
return rowNumber.ToString(CultureInfo.CurrentCulture);
}
else
{
ThrowTerminatingInvalidPathException(path);
}

return null;
}

/// <summary>
/// Removes the child segment of the path and returns the remaining
/// parent portion
/// </summary>
///
/// <param name="path">
/// A full or partial provider specific path. The path may be to an
/// item that may or may not exist.
/// </param>
///
/// <param name="root">
/// The fully qualified path to the root of a drive. This parameter
/// may be null or empty if a mounted drive is not in use for this
/// operation. If this parameter is not null or empty the result
/// of the method should not be a path to a container that is a
/// parent or in a different tree than the root.
/// </param>
///
/// <returns></returns>

protected override string GetParentPath(string path, string root)


{
// If root is specified then the path has to contain
// the root. If not nothing should be returned
if (!String.IsNullOrEmpty(root))
{
if (!path.Contains(root))
{
return null;
}
}

return path.Substring(0, path.LastIndexOf(pathSeparator,


StringComparison.OrdinalIgnoreCase));
}

/// <summary>
/// Joins two strings with a provider specific path separator.
/// </summary>
///
/// <param name="parent">
/// The parent segment of a path to be joined with the child.
/// </param>
///
/// <param name="child">
/// The child segment of a path to be joined with the parent.
/// </param>
///
/// <returns>
/// A string that represents the parent and child segments of the
path
/// joined by a path separator.
/// </returns>

protected override string MakePath(string parent, string child)


{
string result;

string normalParent = NormalizePath(parent);


normalParent = RemoveDriveFromPath(normalParent);
string normalChild = NormalizePath(child);
normalChild = RemoveDriveFromPath(normalChild);

if (String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
result = String.Empty;
}
else if (String.IsNullOrEmpty(normalParent) &&
!String.IsNullOrEmpty(normalChild))
{
result = normalChild;
}
else if (!String.IsNullOrEmpty(normalParent) &&
String.IsNullOrEmpty(normalChild))
{
if (normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent;
}
else
{
result = normalParent + pathSeparator;
}
} // else if (!String...
else
{
if (!normalParent.Equals(String.Empty,
StringComparison.OrdinalIgnoreCase) &&
!normalParent.EndsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result = normalParent + pathSeparator;
}
else
{
result = normalParent;
}

if (normalChild.StartsWith(pathSeparator,
StringComparison.OrdinalIgnoreCase))
{
result += normalChild.Substring(1);
}
else
{
result += normalChild;
}
} // else

return result;
} // MakePath

/// <summary>
/// Normalizes the path that was passed in and returns the
normalized
/// path as a relative path to the basePath that was passed.
/// </summary>
///
/// <param name="path">
/// A fully qualified provider specific path to an item. The item
/// should exist or the provider should write out an error.
/// </param>
///
/// <param name="basepath">
/// The path that the return value should be relative to.
/// </param>
///
/// <returns>
/// A normalized path that is relative to the basePath that was
/// passed. The provider should parse the path parameter, normalize
/// the path, and then return the normalized path relative to the
/// basePath.
/// </returns>
protected override string NormalizeRelativePath(string path,
string
basepath)
{
// Normalize the paths first
string normalPath = NormalizePath(path);
normalPath = RemoveDriveFromPath(normalPath);
string normalBasePath = NormalizePath(basepath);
normalBasePath = RemoveDriveFromPath(normalBasePath);

if (String.IsNullOrEmpty(normalBasePath))
{
return normalPath;
}
else
{
if (!normalPath.Contains(normalBasePath))
{
return null;
}

return normalPath.Substring(normalBasePath.Length +
pathSeparator.Length);
}
}

/// <summary>
/// Moves the item specified by the path to the specified
destination
/// </summary>
///
/// <param name="path">
/// The path to the item to be moved
/// </param>
///
/// <param name="destination">
/// The path of the destination container
/// </param>

protected override void MoveItem(string path, string destination)


{
// Get type, table name and rowNumber from the path
string tableName, destTableName;
int rowNumber, destRowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

PathType destType = GetNamesFromPath(destination, out


destTableName,
out destRowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}

if (destType == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(destination);
}

if (type == PathType.Table)
{
ArgumentException e = new ArgumentException("Move not
supported for tables");

WriteError(new ErrorRecord(e, "MoveNotSupported",


ErrorCategory.InvalidArgument, path));

throw e;
}
else
{
OdbcDataAdapter da = GetAdapterForTable(tableName);
if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

OdbcDataAdapter dda = GetAdapterForTable(destTableName);


if (dda == null)
{
return;
}

DataSet dds = GetDataSetForTable(dda, destTableName);


DataTable destTable = GetDataTable(dds, destTableName);
DataRow row = table.Rows[rowNumber];

if (destType == PathType.Table)
{
DataRow destRow = destTable.NewRow();

destRow.ItemArray = row.ItemArray;
}
else
{
DataRow destRow = destTable.Rows[destRowNumber];

destRow.ItemArray = row.ItemArray;
}

// Update the changes


if (ShouldProcess(path, "MoveItem"))
{
WriteItemObject(row, path, false);
dda.Update(dds, destTableName);
}
}
}

#endregion Navigation

#region Helper Methods

/// <summary>
/// Checks if a given path is actually a drive name.
/// </summary>
/// <param name="path">The path to check.</param>
/// <returns>
/// True if the path given represents a drive, false otherwise.
/// </returns>
private bool PathIsDrive(string path)
{
// Remove the drive name and first path separator. If the
// path is reduced to nothing, it is a drive. Also if its
// just a drive then there wont be any path separators
if (String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root, "")) ||
String.IsNullOrEmpty(
path.Replace(this.PSDriveInfo.Root + pathSeparator,
""))

)
{
return true;
}
else
{
return false;
}
} // PathIsDrive

/// <summary>
/// Breaks up the path into individual elements.
/// </summary>
/// <param name="path">The path to split.</param>
/// <returns>An array of path segments.</returns>
private string[] ChunkPath(string path)
{
// Normalize the path before splitting
string normalPath = NormalizePath(path);

// Return the path with the drive name and first path
// separator character removed, split by the path separator.
string pathNoDrive = normalPath.Replace(this.PSDriveInfo.Root
+ pathSeparator, "");

return pathNoDrive.Split(pathSeparator.ToCharArray());
} // ChunkPath
/// <summary>
/// Adapts the path, making sure the correct path separator
/// character is used.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
private string NormalizePath(string path)
{
string result = path;

if (!String.IsNullOrEmpty(path))
{
result = path.Replace("/", pathSeparator);
}

return result;
} // NormalizePath

/// <summary>
/// Ensures that the drive is removed from the specified path
/// </summary>
///
/// <param name="path">Path from which drive needs to be
removed</param>
/// <returns>Path with drive information removed</returns>
private string RemoveDriveFromPath(string path)
{
string result = path;
string root;

if (this.PSDriveInfo == null)
{
root = String.Empty;
}
else
{
root = this.PSDriveInfo.Root;
}

if (result == null)
{
result = String.Empty;
}

if (result.Contains(root))
{
result = result.Substring(result.IndexOf(root,
StringComparison.OrdinalIgnoreCase) + root.Length);
}

return result;
}

/// <summary>
/// Chunks the path and returns the table name and the row number
/// from the path
/// </summary>
/// <param name="path">Path to chunk and obtain information</param>
/// <param name="tableName">Name of the table as represented in the
/// path</param>
/// <param name="rowNumber">Row number obtained from the
path</param>
/// <returns>what the path represents</returns>
public PathType GetNamesFromPath(string path, out string tableName,
out int rowNumber)
{
PathType retVal = PathType.Invalid;
rowNumber = -1;
tableName = null;

// Check if the path specified is a drive


if (PathIsDrive(path))
{
return PathType.Database;
}

// chunk the path into parts


string[] pathChunks = ChunkPath(path);

switch (pathChunks.Length)
{
case 1:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
retVal = PathType.Table;
}
}
break;

case 2:
{
string name = pathChunks[0];

if (TableNameIsValid(name))
{
tableName = name;
}

int number = SafeConvertRowNumber(pathChunks[1]);

if (number >= 0)
{
rowNumber = number;
retVal = PathType.Row;
}
else
{
WriteError(new ErrorRecord(
new ArgumentException("Row number is not
valid"),
"RowNumberNotValid",
ErrorCategory.InvalidArgument,
path));
}
}
break;

default:
{
WriteError(new ErrorRecord(
new ArgumentException("The path supplied has too
many segments"),
"PathNotValid",
ErrorCategory.InvalidArgument,
path));
}
break;
} // switch(pathChunks...

return retVal;
} // GetNamesFromPath

/// <summary>
/// Throws an argument exception stating that the specified path
does
/// not represent either a table or a row
/// </summary>
/// <param name="path">path which is invalid</param>
private void ThrowTerminatingInvalidPathException(string path)
{
StringBuilder message = new StringBuilder("Path must represent
either a table or a row :");
message.Append(path);

throw new ArgumentException(message.ToString());


}

/// <summary>
/// Retrieve the list of tables from the database.
/// </summary>
/// <returns>
/// Collection of DatabaseTableInfo objects, each object
representing
/// information about one database table
/// </returns>
internal Collection<DatabaseTableInfo> GetTables()
{
Collection<DatabaseTableInfo> results =
new Collection<DatabaseTableInfo>();

// using ODBC connection to the database and get the schema of


tables
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return null;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");
int count;

// iterate through all rows in the schema and create


DatabaseTableInfo
// objects which represents a table
foreach (DataRow dr in dt.Rows)
{
String tableName = dr["TABLE_NAME"] as String;
DataColumnCollection columns = null;

// find the number of rows in the table


try
{
String cmd = "Select count(*) from \"" + tableName +
"\"";
OdbcCommand command = new OdbcCommand(cmd, connection);

count = (Int32)command.ExecuteScalar();
}
catch
{
count = 0;
}

// create DatabaseTableInfo object representing the table


DatabaseTableInfo table =
new DatabaseTableInfo(dr, tableName, count,
columns);

results.Add(table);
} // foreach (DataRow...

return results;
} // GetTables

/// <summary>
/// Return row information from a specified table.
/// </summary>
/// <param name="tableName">The name of the database table from
/// which to retrieve rows.</param>
/// <returns>Collection of row information objects.</returns>
public Collection<DatabaseRowInfo> GetRows(string tableName)
{
Collection<DatabaseRowInfo> results =
new Collection<DatabaseRowInfo>();

// Obtain rows in the table and add it to the collection


try
{
OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return null;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

int i = 0;
foreach (DataRow row in table.Rows)
{
results.Add(new DatabaseRowInfo(row,
i.ToString(CultureInfo.CurrentCulture)));
i++;
} // foreach (DataRow...
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedRows",
ErrorCategory.InvalidOperation, tableName));
}

return results;

} // GetRows

/// <summary>
/// Retrieve information about a single table.
/// </summary>
/// <param name="tableName">The table for which to retrieve
/// data.</param>
/// <returns>Table information.</returns>
private DatabaseTableInfo GetTable(string tableName)
{
foreach (DatabaseTableInfo table in GetTables())
{
if (String.Equals(tableName, table.Name,
StringComparison.OrdinalIgnoreCase))
{
return table;
}
}

return null;
} // GetTable

/// <summary>
/// Removes the specified table from the database
/// </summary>
/// <param name="tableName">Name of the table to remove</param>
private void RemoveTable(string tableName)
{
// validate if tablename is valid and if table is present
if (String.IsNullOrEmpty(tableName) ||
!TableNameIsValid(tableName) || !TableIsPresent(tableName))
{
return;
}

// Execute command using ODBC connection to remove a table


try
{
// delete the table using an sql statement
string sql = "drop table " + tableName;

AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null)
{
return;
}
OdbcConnection connection = di.Connection;

OdbcCommand cmd = new OdbcCommand(sql, connection);


cmd.ExecuteScalar();
}
catch (Exception ex)
{
WriteError(new ErrorRecord(ex, "CannotRemoveSpecifiedTable",
ErrorCategory.InvalidOperation, null)
);
}

} // RemoveTable

/// <summary>
/// Obtain a data adapter for the specified Table
/// </summary>
/// <param name="tableName">Name of the table to obtain the
/// adapter for</param>
/// <returns>Adapter object for the specified table</returns>
/// <remarks>An adapter serves as a bridge between a DataSet (in
memory
/// representation of table) and the data source</remarks>
internal OdbcDataAdapter GetAdapterForTable(string tableName)
{
OdbcDataAdapter da = null;
AccessDBPSDriveInfo di = this.PSDriveInfo as
AccessDBPSDriveInfo;

if (di == null || !TableNameIsValid(tableName) ||


!TableIsPresent(tableName))
{
return null;
}

OdbcConnection connection = di.Connection;

try
{
// Create a odbc data adpater. This can be sued to update
the
// data source with the records that will be created here
// using data sets
string sql = "Select * from " + tableName;
da = new OdbcDataAdapter(new OdbcCommand(sql, connection));

// Create a odbc command builder object. This will create


sql
// commands automatically for a single table, thus
// eliminating the need to create new sql statements for
// every operation to be done.
OdbcCommandBuilder cmd = new OdbcCommandBuilder(da);

// Set the delete cmd for the table here


sql = "Delete from " + tableName + " where ID = ?";
da.DeleteCommand = new OdbcCommand(sql, connection);

// Specify a DeleteCommand parameter based on the "ID"


// column
da.DeleteCommand.Parameters.Add(new OdbcParameter());
da.DeleteCommand.Parameters[0].SourceColumn = "ID";

// Create an InsertCommand based on the sql string


// Insert into "tablename" values (?,?,?)" where
// ? represents a column in the table. Note that
// the number of ? will be equal to the number of
// columnds
DataSet ds = new DataSet();
ds.Locale = CultureInfo.InvariantCulture;

da.FillSchema(ds, SchemaType.Source);

sql = "Insert into " + tableName + " values ( ";


for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
sql += "?, ";
}
sql = sql.Substring(0, sql.Length - 2);
sql += ")";
da.InsertCommand = new OdbcCommand(sql, connection);

// Create parameters for the InsertCommand based on the


// captions of each column
for (int i = 0; i < ds.Tables["Table"].Columns.Count; i++)
{
da.InsertCommand.Parameters.Add(new OdbcParameter());
da.InsertCommand.Parameters[i].SourceColumn =
ds.Tables["Table"].Columns[i].Caption;

// Open the connection if its not already open


if (connection.State != ConnectionState.Open)
{
connection.Open();
}
}
catch (Exception e)
{
WriteError(new ErrorRecord(e, "CannotAccessSpecifiedTable",
ErrorCategory.InvalidOperation, tableName));
}

return da;
} // GetAdapterForTable

/// <summary>
/// Gets the DataSet (in memory representation) for the table
/// for the specified adapter
/// </summary>
/// <param name="adapter">Adapter to be used for obtaining
/// the table</param>
/// <param name="tableName">Name of the table for which a
/// DataSet is required</param>
/// <returns>The DataSet with the filled in schema</returns>
internal DataSet GetDataSetForTable(OdbcDataAdapter adapter, string
tableName)
{
Debug.Assert(adapter != null);

// Create a dataset object which will provide an in-memory


// representation of the data being worked upon in the
// data source.
DataSet ds = new DataSet();

// Create a table named "Table" which will contain the same


// schema as in the data source.
//adapter.FillSchema(ds, SchemaType.Source);
adapter.Fill(ds, tableName);
ds.Locale = CultureInfo.InvariantCulture;

return ds;
} //GetDataSetForTable

/// <summary>
/// Get the DataTable object which can be used to operate on
/// for the specified table in the data source
/// </summary>
/// <param name="ds">DataSet object which contains the tables
/// schema</param>
/// <param name="tableName">Name of the table</param>
/// <returns>Corresponding DataTable object representing
/// the table</returns>
///
internal DataTable GetDataTable(DataSet ds, string tableName)
{
Debug.Assert(ds != null);
Debug.Assert(tableName != null);

DataTable table = ds.Tables[tableName];


table.Locale = CultureInfo.InvariantCulture;

return table;
} // GetDataTable

/// <summary>
/// Retrieves a single row from the named table.
/// </summary>
/// <param name="tableName">The table that contains the
/// numbered row.</param>
/// <param name="row">The index of the row to return.</param>
/// <returns>The specified table row.</returns>
private DatabaseRowInfo GetRow(string tableName, int row)
{
Collection<DatabaseRowInfo> di = GetRows(tableName);

// if the row is invalid write an appropriate error else return


the
// corresponding row information
if (row < di.Count && row >= 0)
{
return di[row];
}
else
{
WriteError(new ErrorRecord(
new ItemNotFoundException(),
"RowNotFound",
ErrorCategory.ObjectNotFound,
row.ToString(CultureInfo.CurrentCulture))
);
}

return null;
} // GetRow

/// <summary>
/// Method to safely convert a string representation of a row number
/// into its Int32 equivalent
/// </summary>
/// <param name="rowNumberAsStr">String representation of the row
/// number</param>
/// <remarks>If there is an exception, -1 is returned</remarks>
private int SafeConvertRowNumber(string rowNumberAsStr)
{
int rowNumber = -1;
try
{
rowNumber = Convert.ToInt32(rowNumberAsStr,
CultureInfo.CurrentCulture);
}
catch (FormatException fe)
{
WriteError(new ErrorRecord(fe, "RowStringFormatNotValid",
ErrorCategory.InvalidData, rowNumberAsStr));
}
catch (OverflowException oe)
{
WriteError(new ErrorRecord(oe,
"RowStringConversionToNumberFailed",
ErrorCategory.InvalidData, rowNumberAsStr));
}

return rowNumber;
} // 1

/// <summary>
/// Check if a table name is valid
/// </summary>
/// <param name="tableName">Table name to validate</param>
/// <remarks>Helps to check for SQL injection attacks</remarks>
private bool TableNameIsValid(string tableName)
{
Regex exp = new Regex(pattern, RegexOptions.Compiled |
RegexOptions.IgnoreCase);

if (exp.IsMatch(tableName))
{
return true;
}
WriteError(new ErrorRecord(
new ArgumentException("Table name not valid"),
"TableNameNotValid",
ErrorCategory.InvalidArgument, tableName));
return false;
} // TableNameIsValid

/// <summary>
/// Checks to see if the specified table is present in the
/// database
/// </summary>
/// <param name="tableName">Name of the table to check</param>
/// <returns>true, if table is present, false otherwise</returns>
private bool TableIsPresent(string tableName)
{
// using ODBC connection to the database and get the schema of
tables
AccessDBPSDriveInfo di = this.PSDriveInfo as AccessDBPSDriveInfo;
if (di == null)
{
return false;
}

OdbcConnection connection = di.Connection;


DataTable dt = connection.GetSchema("Tables");

// check if the specified tableName is available


// in the list of tables present in the database
foreach (DataRow dr in dt.Rows)
{
string name = dr["TABLE_NAME"] as string;
if (name.Equals(tableName,
StringComparison.OrdinalIgnoreCase))
{
return true;
}
}

WriteError(new ErrorRecord(
new ArgumentException("Specified Table is not present in
database"), "TableNotAvailable",
ErrorCategory.InvalidArgument, tableName));

return false;
}// TableIsPresent

/// <summary>
/// Gets the next available ID in the table
/// </summary>
/// <param name="table">DataTable object representing the table to
/// search for ID</param>
/// <returns>next available id</returns>
private int GetNextID(DataTable table)
{
int big = 0;

for (int i = 0; i < table.Rows.Count; i++)


{
DataRow row = table.Rows[i];

int id = (int)row["ID"];

if (big < id)


{
big = id;
}
}

big++;
return big;
}
#endregion Helper Methods

#region Content Methods


/// <summary>
/// Clear the contents at the specified location. In this case,
clearing
/// the item amounts to clearing a row
/// </summary>
/// <param name="path">The path to the content to clear.</param>
public void ClearContent(string path)
{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type != PathType.Table)
{
WriteError(new ErrorRecord(
new InvalidOperationException("Operation not supported.
Content can be cleared only for table"),
"NotValidRow", ErrorCategory.InvalidArgument,
path));
return;
}

OdbcDataAdapter da = GetAdapterForTable(tableName);

if (da == null)
{
return;
}

DataSet ds = GetDataSetForTable(da, tableName);


DataTable table = GetDataTable(ds, tableName);

// Clear contents at the specified location


for (int i = 0; i < table.Rows.Count; i++)
{
table.Rows[i].Delete();
}

if (ShouldProcess(path, "ClearContent"))
{
da.Update(ds, tableName);
}

} // ClearContent

/// <summary>
/// Not implemented.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public object ClearContentDynamicParameters(string path)
{
return null;
}

/// <summary>
/// Get a reader at the path specified.
/// </summary>
/// <param name="path">The path from which to read.</param>
/// <returns>A content reader used to read the data.</returns>
public IContentReader GetContentReader(string path)
{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be obtained
only for tables");
}

return new AccessDBContentReader(path, this);


} // GetContentReader

/// <summary>
/// Not implemented.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public object GetContentReaderDynamicParameters(string path)
{
return null;
}

/// <summary>
/// Get an object used to write content.
/// </summary>
/// <param name="path">The root path at which to write.</param>
/// <returns>A content writer for writing.</returns>
public IContentWriter GetContentWriter(string path)
{
string tableName;
int rowNumber;

PathType type = GetNamesFromPath(path, out tableName, out


rowNumber);

if (type == PathType.Invalid)
{
ThrowTerminatingInvalidPathException(path);
}
else if (type == PathType.Row)
{
throw new InvalidOperationException("contents can be added
only to tables");
}

return new AccessDBContentWriter(path, this);


}

/// <summary>
/// Not implemented.
/// </summary>
/// <param name="path"></param>
/// <returns></returns>
public object GetContentWriterDynamicParameters(string path)
{
return null;
}

#endregion Content Methods

#region Private Properties

private string pathSeparator = "\\";


private static string pattern = @"^[a-z]+[0-9]*_*$";

#endregion Private Properties

} // AccessDBProvider

#endregion AccessDBProvider

#region Helper Classes

#region Public Enumerations

/// <summary>
/// Type of item represented by the path
/// </summary>
public enum PathType
{
/// <summary>
/// Represents a database
/// </summary>
Database,
/// <summary>
/// Represents a table
/// </summary>
Table,
/// <summary>
/// Represents a row
/// </summary>
Row,
/// <summary>
/// Represents an invalid path
/// </summary>
Invalid
};

#endregion Public Enumerations

#region AccessDBPSDriveInfo

/// <summary>
/// Any state associated with the drive should be held here.
/// In this case, it's the connection to the database.
/// </summary>
internal class AccessDBPSDriveInfo : PSDriveInfo
{
private OdbcConnection connection;

/// <summary>
/// ODBC connection information.
/// </summary>
public OdbcConnection Connection
{
get { return connection; }
set { connection = value; }
}

/// <summary>
/// Constructor that takes one argument
/// </summary>
/// <param name="driveInfo">Drive provided by this provider</param>
public AccessDBPSDriveInfo(PSDriveInfo driveInfo)
: base(driveInfo)
{ }

} // class AccessDBPSDriveInfo

#endregion AccessDBPSDriveInfo

#region DatabaseTableInfo

/// <summary>
/// Contains information specific to the database table.
/// Similar to the DirectoryInfo class.
/// </summary>
public class DatabaseTableInfo
{
/// <summary>
/// Row from the "tables" schema
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The table name.
/// </summary>
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
private String name;

/// <summary>
/// The number of rows in the table.
/// </summary>
public int RowCount
{
get
{
return rowCount;
}
set
{
rowCount = value;
}
}
private int rowCount;

/// <summary>
/// The column definitions for the table.
/// </summary>
public DataColumnCollection Columns
{
get
{
return columns;
}
set
{
columns = value;
}
}
private DataColumnCollection columns;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row definition.</param>
/// <param name="name">The table name.</param>
/// <param name="rowCount">The number of rows in the table.</param>
/// <param name="columns">Information on the column tables.</param>
public DatabaseTableInfo(DataRow row, string name, int rowCount,
DataColumnCollection columns)
{
Name = name;
Data = row;
RowCount = rowCount;
Columns = columns;
} // DatabaseTableInfo
} // class DatabaseTableInfo

#endregion DatabaseTableInfo

#region DatabaseRowInfo

/// <summary>
/// Contains information specific to an individual table row.
/// Analogous to the FileInfo class.
/// </summary>
public class DatabaseRowInfo
{
/// <summary>
/// Row data information.
/// </summary>
public DataRow Data
{
get
{
return data;
}
set
{
data = value;
}
}
private DataRow data;

/// <summary>
/// The row index.
/// </summary>
public string RowNumber
{
get
{
return rowNumber;
}
set
{
rowNumber = value;
}
}
private string rowNumber;

/// <summary>
/// Constructor.
/// </summary>
/// <param name="row">The row information.</param>
/// <param name="name">The row index.</param>
public DatabaseRowInfo(DataRow row, string name)
{
RowNumber = name;
Data = row;
} // DatabaseRowInfo
} // class DatabaseRowInfo

#endregion DatabaseRowInfo

#region AccessDBContentReader

/// <summary>
/// Content reader used to retrieve data from this provider.
/// </summary>
public class AccessDBContentReader : IContentReader
{
// A provider instance is required so as to get "content"
private AccessDBProvider provider;
private string path;
private long currentOffset;

internal AccessDBContentReader(string path, AccessDBProvider


provider)
{
this.path = path;
this.provider = provider;
}

/// <summary>
/// Read the specified number of rows from the source.
/// </summary>
/// <param name="readCount">The number of items to
/// return.</param>
/// <returns>An array of elements read.</returns>
public IList Read(long readCount)
{
// Read the number of rows specified by readCount and increment
// offset
string tableName;
int rowNumber;
PathType type = provider.GetNamesFromPath(path, out tableName,
out rowNumber);

Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);
Collection<DataRow> results = new Collection<DataRow>();
if (currentOffset < 0 || currentOffset >= rows.Count)
{
return null;
}

int rowsRead = 0;

while (rowsRead < readCount && currentOffset < rows.Count)


{
results.Add(rows[(int)currentOffset].Data);
rowsRead++;
currentOffset++;
}

return results;
} // Read

/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
/// <param name="offset">Number of rows to offset</param>
/// <param name="origin">Starting row from which to offset</param>
public void Seek(long offset, System.IO.SeekOrigin origin)
{
// get the number of rows in the table which will help in
// calculating current position
string tableName;
int rowNumber;

PathType type = provider.GetNamesFromPath(path, out tableName,


out rowNumber);

if (type == PathType.Invalid)
{
throw new ArgumentException("Path specified must represent a
table or a row :" + path);
}

if (type == PathType.Table)
{
Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);

int numRows = rows.Count;

if (offset > rows.Count)


{
throw new
ArgumentException(
"Offset cannot be greater than the number of
rows available"
);
}
if (origin == System.IO.SeekOrigin.Begin)
{
// starting from Beginning with an index 0, the current
offset
// has to be advanced to offset - 1
currentOffset = offset - 1;
}
else if (origin == System.IO.SeekOrigin.End)
{
// starting from the end which is numRows - 1, the
current
// offset is so much less than numRows - 1
currentOffset = numRows - 1 - offset;
}
else
{
// calculate from the previous value of current offset
// advancing forward always
currentOffset += offset;
}
} // if (type...
else
{
// for row, the offset will always be set to 0
currentOffset = 0;
}

} // Seek

/// <summary>
/// Closes the content reader, so all members are reset
/// </summary>
public void Close()
{
Dispose();
} // Close

/// <summary>
/// Dispose any resources being used
/// </summary>
public void Dispose()
{
Seek(0, System.IO.SeekOrigin.Begin);

GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentReader

#endregion AccessDBContentReader

#region AccessDBContentWriter

/// <summary>
/// Content writer used to write data in this provider.
/// </summary>
public class AccessDBContentWriter : IContentWriter
{
// A provider instance is required so as to get "content"
private AccessDBProvider provider;
private string path;
private long currentOffset;

internal AccessDBContentWriter(string path, AccessDBProvider


provider)
{
this.path = path;
this.provider = provider;
}

/// <summary>
/// Write the specified row contents in the source
/// </summary>
/// <param name="content"> The contents to be written to the source.
/// </param>
/// <returns>An array of elements which were successfully written to
/// the source</returns>
///
public IList Write(IList content)
{
if (content == null)
{
return null;
}

// Get the total number of rows currently available it will


// determine how much to overwrite and how much to append at
// the end
string tableName;
int rowNumber;
PathType type = provider.GetNamesFromPath(path, out tableName,
out rowNumber);

if (type == PathType.Table)
{
OdbcDataAdapter da = provider.GetAdapterForTable(tableName);
if (da == null)
{
return null;
}

DataSet ds = provider.GetDataSetForTable(da, tableName);


DataTable table = provider.GetDataTable(ds, tableName);

string[] colValues = (content[0] as string).Split(',');

// set the specified row


DataRow row = table.NewRow();

for (int i = 0; i < colValues.Length; i++)


{
if (!String.IsNullOrEmpty(colValues[i]))
{
row[i] = colValues[i];
}
}

//table.Rows.InsertAt(row, rowNumber);
// Update the table
table.Rows.Add(row);
da.Update(ds, tableName);

}
else
{
throw new InvalidOperationException("Operation not
supported. Content can be added only for tables");
}

return null;
} // Write

/// <summary>
/// Moves the content reader specified number of rows from the
/// origin
/// </summary>
/// <param name="offset">Number of rows to offset</param>
/// <param name="origin">Starting row from which to offset</param>
public void Seek(long offset, System.IO.SeekOrigin origin)
{
// get the number of rows in the table which will help in
// calculating current position
string tableName;
int rowNumber;

PathType type = provider.GetNamesFromPath(path, out tableName,


out rowNumber);

if (type == PathType.Invalid)
{
throw new ArgumentException("Path specified should represent
either a table or a row : " + path);
}

Collection<DatabaseRowInfo> rows =
provider.GetRows(tableName);

int numRows = rows.Count;

if (offset > rows.Count)


{
throw new
ArgumentException(
"Offset cannot be greater than the number of rows
available"
);
}

if (origin == System.IO.SeekOrigin.Begin)
{
// starting from Beginning with an index 0, the current
offset
// has to be advanced to offset - 1
currentOffset = offset - 1;
}
else if (origin == System.IO.SeekOrigin.End)
{
// starting from the end which is numRows - 1, the current
// offset is so much less than numRows - 1
currentOffset = numRows - 1 - offset;
}
else
{
// calculate from the previous value of current offset
// advancing forward always
currentOffset += offset;
}

} // Seek

/// <summary>
/// Closes the content reader, so all members are reset
/// </summary>
public void Close()
{
Dispose();
} // Close

/// <summary>
/// Dispose any resources being used
/// </summary>
public void Dispose()
{
Seek(0, System.IO.SeekOrigin.Begin);

GC.SuppressFinalize(this);
} // Dispose
} // AccessDBContentWriter

#endregion AccessDBContentWriter

#endregion Helper Classes


} // namespace Microsoft.Samples.PowerShell.Providers

Consulte también
Guía del programador de Windows PowerShell
Windows PowerShell SDK
Ejemplos de código GetProc01
Artículo • 27/09/2021

Estos son los ejemplos de código para el cmdlet de ejemplo GetProc01. Este es el
ejemplo Get-Process de cmdlet básico que se describe en Creación del primer cmdlet.
Un Get-Process cmdlet está diseñado para recuperar información sobre todos los
procesos que se ejecutan en el equipo local.

Para obtener código de ejemplo completo, vea los temas siguientes.

Lenguaje Tema

C# Código de ejemplo GetProc01 (C#)

VB.NET Código de ejemplo GetProc01 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo GetProc01 (C#)
Artículo • 25/09/2021

El código siguiente muestra la implementación del cmdlet de ejemplo GetProc01.


Observe que el cmdlet se simplifica dejando el trabajo real de recuperación de procesos
al método System.Diagnostics.Process.Getprocesses*.

7 Nota

Puede descargar el archivo de código fuente de C# (getproc01.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK. Los archivos de origen
descargados están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
C#

using System;
using System.Diagnostics;
using System.Management.Automation; //Windows PowerShell
namespace

using System.ComponentModel;

// This sample shows how to create a simple cmdlet. To test this


// cmdlet, the snapin must be registered. First, run the command:
// installutil GetProcessSample01.dll
// Then run:
// Add-PSSnapin GetProcessSnapIn01
// After the snapin has been loaded, you can run:
// get-proc

namespace Microsoft.Samples.PowerShell.Commands
{

#region GetProcCommand

/// <summary>
/// This class implements the Get-Proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes of the local computer.
/// Then, the WriteObject method writes the associated processes
/// to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// Retrieve the current processes.
Process[] processes = Process.GetProcesses();

// Write the processes to the pipeline to make them available


// to the next cmdlet. The second argument (true) tells Windows
// PowerShell to enumerate the array and to send one process
// object at a time to the pipeline.
WriteObject(processes, true);
}

#endregion Overrides

} //GetProcCommand

#endregion GetProcCommand

#region PowerShell snap-in

/// <summary>
/// Create this sample as an PowerShell snap-in
/// </summary>
[RunInstaller(true)]
public class GetProcPSSnapIn01 : PSSnapIn
{
/// <summary>
/// Create an instance of the GetProcPSSnapIn01
/// </summary>
public GetProcPSSnapIn01()
: base()
{
}

/// <summary>
/// Get a name for this PowerShell snap-in. This name will be used in
registering
/// this PowerShell snap-in.
/// </summary>
public override string Name
{
get
{
return "GetProcPSSnapIn01";
}
}
/// <summary>
/// Vendor information for this PowerShell snap-in.
/// </summary>
public override string Vendor
{
get
{
return "Microsoft";
}
}

/// <summary>
/// Gets resource information for vendor. This is a string of format:
/// resourceBaseName,resourceName.
/// </summary>
public override string VendorResource
{
get
{
return "GetProcPSSnapIn01,Microsoft";
}
}

/// <summary>
/// Description of this PowerShell snap-in.
/// </summary>
public override string Description
{
get
{
return "This is a PowerShell snap-in that includes the get-
proc cmdlet.";
}
}
}

#endregion PowerShell snap-in


}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo GetProc01 (VB.NET)
Artículo • 27/09/2021

El código siguiente muestra la implementación del cmdlet de ejemplo GetProc01.


Observe que el cmdlet se simplifica dejando el trabajo real de recuperación de procesos
en el método System.Diagnostics.Process.Getprocesses*.

7 Nota

Puede descargar el archivo de código fuente de C# (getproc01.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Ejemplo de código

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplos de código GetProc02
Artículo • 25/09/2021

Estos son los ejemplos de código para el cmdlet de ejemplo GetProc02. Este es el Get-
Process ejemplo de cmdlet descrito en Agregar parámetros que procesan Command-

Line entrada. Este Get-Process cmdlet recupera los procesos en función de su nombre y,
a continuación, muestra información sobre los procesos en la línea de comandos.

7 Nota

Puede descargar el archivo de código fuente de C# (getproc02.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Para obtener código de ejemplo completo, vea los temas siguientes.

Lenguaje Tema

C# Código de ejemplo GetProc02 (C#)

VB.NET Código de ejemplo GetProc02 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo GetProc02 (C#)
Artículo • 27/09/2021

El código siguiente muestra la implementación de un Get-Process cmdlet que acepta la


entrada de la línea de comandos. Observe que esta implementación define un
parámetro para permitir la entrada de línea de comandos y usa el método Name
WriteObject(System.Object,System.Boolean) como mecanismo de salida para enviar
objetos de salida a la canalización.

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell namespace.
#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// The names of the processes to act on.
/// </summary>
private string[] processNames;

/// <summary>
/// Gets or sets the list of process names on which
/// the Get-Proc cmdlet will work.
/// </summary>
[Parameter(Position = 0)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

#endregion Parameters

#region Cmdlet Overrides


/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes specified by the Name
/// parameter. Then, the WriteObject method writes the
/// associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// If no process names are passed to the cmdlet, get all
// processes.
if (this.processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to cmdlet, get and write
// the associated processes.
foreach (string name in this.processNames)
{
WriteObject(Process.GetProcessesByName(name), true);
}
} // if (processNames...
} // ProcessRecord

#endregion Cmdlet Overrides


} // End GetProcCommand class.

#endregion GetProcCommand
}

Consulte también
Windows PowerShell SDK
Código de ejemplo GetProc02 (VB.NET)
Artículo • 25/09/2021

El código siguiente muestra la implementación de un Get-Process cmdlet que acepta la


entrada de la línea de comandos. Observe que esta implementación define un
parámetro para permitir la entrada de línea de comandos y usa el método Name
WriteObject(System.Object,System.Boolean) como mecanismo de salida para enviar
objetos de salida a la canalización.

Ejemplo de código

Consulte también
Windows PowerShell SDK
Ejemplos de código GetProc03
Artículo • 27/09/2021

Estos son los ejemplos de código para el cmdlet de ejemplo GetProc03. Este es el Get-
Process ejemplo de cmdlet descrito en Agregar parámetros que procesan la entrada de

canalización. Este cmdlet usa un parámetro que acepta la entrada de un objeto de


canalización, recupera la información del proceso del equipo local en función de los
nombres proporcionados y, a continuación, muestra información sobre los procesos en
la línea Get-Process Name de comandos.

7 Nota

Puede descargar el archivo de código fuente de C# (getprov03.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Para obtener código de ejemplo completo, consulte los temas siguientes.

Lenguaje Tema

C# Código de ejemplo GetProc03 (C#)

VB.NET Código de ejemplo GetProc03 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo GetProc03 (C#)
Artículo • 27/09/2021

El código siguiente muestra la implementación de un Get-Process cmdlet que puede


aceptar la entrada canalizada. Esta implementación define un parámetro que acepta la
entrada de canalización, recupera la información del proceso del equipo local en función
de los nombres proporcionados y, a continuación, usa el método Name
WriteObject(System.Object,System.Boolean) como mecanismo de salida para enviar
objetos a la canalización.

7 Nota

Puede descargar el archivo de código fuente de C# (getprov03.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK. Los archivos de origen
descargados están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell
namespace.
#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// The names of the processes to act on.
/// </summary>
private string[] processNames;
/// <summary>
/// Gets or setsthe list of process names on
/// which the Get-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes specified by the Name
/// parameter. Then, the WriteObject method writes the
/// associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// If no process names are passed to the cmdlet, get all
// processes.
if (this.processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to the cmdlet, get and write
// the associated processes.
foreach (string name in this.processNames)
{
WriteObject(Process.GetProcessesByName(name), true);
}
} // if (processNames ...
} // ProcessRecord
#endregion Overrides
} // End GetProcCommand class.

#endregion GetProcCommand
}

Consulte también
Guía del programador de Windows PowerShell
Windows PowerShell SDK
Código de ejemplo GetProc03 (VB.NET)
Artículo • 27/09/2021

El código siguiente muestra la implementación de un Get-Process cmdlet que puede


aceptar la entrada canalizada. Esta implementación define un parámetro que acepta la
entrada de canalización, recupera información de proceso del equipo local en función
de los nombres proporcionados y, a continuación, usa el método Name
WriteObject(System.Object,System.Boolean) como mecanismo de salida para enviar
objetos a la canalización.

Ejemplo de código
Ejemplos de código GetProc04
Artículo • 27/09/2021

Estos son los ejemplos de código para el cmdlet de ejemplo GetProc04. Este es el Get-
Process ejemplo de cmdlet descrito en Adding Nonterminating Error Reporting to Your

Cmdlet. Este Get-Process cmdlet llama al método


System.Management.Automation.Cmdlet.WriteError cada vez que se produce una
excepción de operación no válida al recuperar información del proceso.

7 Nota

Puede descargar el archivo de código fuente de C# (getprov04.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Para obtener código de ejemplo completo, vea los temas siguientes.

Lenguaje Tema

C# Código de ejemplo GetProc04 (C#)

VB.NET Código de ejemplo GetProc04 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo GetProc04 (C#)
Artículo • 27/09/2021

El código siguiente muestra la implementación de un Get-Process cmdlet que notifica


errores no terminales. Esta implementación llama al método
System.Management.Automation.Cmdlet.WriteError para notificar errores no terminales.

7 Nota

Puede descargar el archivo de código fuente de C# (getprov04.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK. Los archivos de origen
descargados están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell
namespace.
#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// The names of the processes to act on.
/// </summary>
private string[] processNames;

/// <summary>
/// Gets or sets the list of process names on
/// which the Get-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes specified by the Name
/// parameter. Then, the WriteObject method writes the
/// associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
// If no process names are passed to cmdlet, get all
// processes.
if (this.processNames == null)
{
WriteObject(Process.GetProcesses(), true);
}
else
{
// If process names are passed to the cmdlet, get and write
// the associated processes.
// If a nonterminating error occurs while retrieving
processes,
// call the WriteError method to send an error record to the
// error stream.
foreach (string name in this.processNames)
{
Process[] processes;

try
{
processes = Process.GetProcessesByName(name);
}
catch (InvalidOperationException ex)
{
WriteError(new ErrorRecord(
ex,
"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation,
name));
continue;
}
WriteObject(processes, true);
} // foreach (string name...
} // else
} // ProcessRecord

#endregion Overrides
} // End GetProcCommand class.

#endregion GetProcCommand
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo GetProc04 (VB.NET)
Artículo • 27/09/2021

El código siguiente muestra la implementación de un Get-Process cmdlet que notifica


errores no terminales. Esta implementación llama al método
System.Management.Automation.Cmdlet.WriteError para notificar errores no terminales.

7 Nota

Puede descargar el archivo de código fuente de C# (getprov04.cs) para este cmdlet


de Get-Proc mediante el Kit de desarrollo de software de Microsoft Windows para
los componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Ejemplo de código

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplos de código GetProc05
Artículo • 27/09/2021

Estos son los ejemplos de código para el cmdlet de ejemplo GetProc05. Este cmdlet es
similar al cmdlet descrito en Get-Process Adding Nonterminating Error Reporting to
Your Cmdlet.

Lenguaje Tema

C# Código de ejemplo GetProc05 (C#)

VB.NET Código de ejemplo GetProc05 (VB.NET)

Consulte también
Windows PowerShell SDK
Código de ejemplo GetProc05 (C#)
Artículo • 27/09/2021

Este es el código de C# completo para el cmdlet de ejemplo GetProc05.

C#

namespace Microsoft.Samples.PowerShell.Commands
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Management.Automation; // Windows PowerShell namespace.
using System.Security.Permissions;
using Win32Exception = System.ComponentModel.Win32Exception;
#region GetProcCommand

/// <summary>
/// This class implements the get-proc cmdlet.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc",
DefaultParameterSetName = "ProcessName")]
public class GetProcCommand : PSCmdlet
{
#region Fields
/// <summary>
/// The names of the processes to act on.
/// </summary>
private string[] processNames;

/// <summary>
/// The identifiers of the processes to act on.
/// </summary>
private int[] processIds;

/// <summary>
/// The process objects to act on.
/// </summary>
private Process[] inputObjects;

#endregion Fields

#region Parameters

/// <summary>
/// Gets or sets the list of process names on
/// which the Get-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true)]
[ValidateNotNullOrEmpty]
public string[] Name
{
get { return this.processNames; }
set { this.processNames = value; }
}

/// <summary>
/// Gets or sets the list of process identifiers on
/// which the Get-Proc cmdlet will work.
/// </summary>
[Parameter(
ParameterSetName = "Id",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The unique id of the process to get.")]
public int[] Id
{
get { return this.processIds; }
set { this.processIds = value; }
}

/// <summary>
/// Gets or sets Process objects directly. If the input is a
/// stream of [collection of] Process objects, the cmdlet bypasses the
/// ProcessName and Id parameters and reads the Process objects
/// directly. This allows the cmdlet to deal with processes that have
/// wildcard characters in their name.
/// <value>Process objects</value>
/// </summary>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
public Process[] Input
{
get { return this.inputObjects; }
set { this.inputObjects = value; }
}

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method calls the Process.GetProcesses
/// method to retrieve the processes. Then, the WriteObject
/// method writes the associated processes to the pipeline.
/// </summary>
protected override void ProcessRecord()
{
List<Process> matchingProcesses;
WriteDebug("Obtaining the list of matching process objects.");

switch (ParameterSetName)
{
case "Id":
matchingProcesses = this.GetMatchingProcessesById();
break;
case "ProcessName":
matchingProcesses = this.GetMatchingProcessesByName();
break;
case "InputObject":
matchingProcesses = this.GetProcessesByInput();
break;
default:
ThrowTerminatingError(
new ErrorRecord(
new ArgumentException("Bad ParameterSetName"),
"UnableToAccessProcessList",
ErrorCategory.InvalidOperation,
null));
return;
} // switch (ParameterSetName)

WriteDebug("Outputting the matching process objects.");

matchingProcesses.Sort(ProcessComparison);

foreach (Process process in matchingProcesses)


{
WriteObject(process);
}
} // ProcessRecord

#endregion Overrides

#region protected Methods and Data

/// <summary>
/// Retrieves the list of all processes matching the ProcessName
/// parameter and generates a nonterminating error for each
/// specified process name which is not found even though the name
/// contains no wildcards.
/// </summary>
/// <returns>The matching processes.</returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
private List<Process> GetMatchingProcessesByName()
{
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();

List<Process> allProcesses =
new List<Process>(Process.GetProcesses());
// The keys dictionary is used for rapid lookup of
// processes that are already in the matchingProcesses list.
Dictionary<int, byte> keys = new Dictionary<int, byte>();

List<Process> matchingProcesses = new List<Process>();

if (null == this.processNames)
{
matchingProcesses.AddRange(allProcesses);
}
else
{
foreach (string pattern in this.processNames)
{
WriteVerbose("Finding matches for process name \""
+ pattern + "\".");

// WildCard serach on the available processes


WildcardPattern wildcard =
new WildcardPattern(
pattern,
WildcardOptions.IgnoreCase);

bool found = false;

foreach (Process process in allProcesses)


{
if (!keys.ContainsKey(process.Id))
{
string processName = SafeGetProcessName(process);

// Remove the process from the allProcesses list


// so that it is not tested again.
if (processName.Length == 0)
{
allProcesses.Remove(process);
}

// Perform a wildcard search on this particular


// process name and check whether it matches the
// pattern specified.
if (!wildcard.IsMatch(processName))
{
continue;
}

WriteDebug("Found matching process id "


+ process.Id + ".");

// A match is found.
found = true;

// Store the process identifier so that the same


process
// is not added twice.
keys.Add(process.Id, 0);

// Add the process to the processes list.


matchingProcesses.Add(process);
}
} // foreach (Process...

if (!found &&
!WildcardPattern.ContainsWildcardCharacters(pattern))
{
WriteError(new ErrorRecord(
new ArgumentException("Cannot find process name "
+ "\"" + pattern + "\"."),
"ProcessNameNotFound",
ErrorCategory.ObjectNotFound,
pattern));
}
} // foreach (string...
} // if (null...

return matchingProcesses;
} // GetMatchingProcessesByName

/// <summary>
/// Returns the name of a process. If an error occurs, a blank
/// string is returned.
/// </summary>
/// <param name="process">The process whose name is
/// returned.</param>
/// <returns>The name of the process.</returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand, Unrestricted = true)]
protected static string SafeGetProcessName(Process process)
{
new EnvironmentPermission(PermissionState.Unrestricted).Assert();
string name = String.Empty;

if (process != null)
{
try
{
return process.ProcessName;
}
catch (Win32Exception)
{
}
catch (InvalidOperationException)
{
}
}

return name;
} // SafeGetProcessName

#endregion Cmdlet Overrides


#region Private Methods

/// <summary>
/// Function to sort by process name first, and then by
/// the process identifier.
/// </summary>
/// <param name="x">First process object.</param>
/// <param name="y">Second process object.</param>
/// <returns>
/// Returns less than zero if x is less than y,
/// greater than 0 if x is greater than y, and 0 if x == y.
/// </returns>
private static int ProcessComparison(Process x, Process y)
{
int diff = String.Compare(
SafeGetProcessName(x),
SafeGetProcessName(y),
StringComparison.CurrentCultureIgnoreCase);

if (0 != diff)
{
return diff;
}
else
{
return x.Id.CompareTo(y.Id);
}
}

/// <summary>
/// Retrieves the list of all processes matching the Id
/// parameter and generates a nonterminating error for
/// each specified process identofier which is not found.
/// </summary>
/// <returns>
/// An array of processes that match the given identifier.
/// </returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
private List<Process> GetMatchingProcessesById()
{
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();

List<Process> matchingProcesses = new List<Process>();

if (null != this.processIds)
{
// The keys dictionary is used for rapid lookup of the
// processes already in the matchingProcesses list.
Dictionary<int, byte> keys = new Dictionary<int, byte>();

foreach (int processId in this.processIds)


{
WriteVerbose("Finding match for process id "
+ processId + ".");

if (!keys.ContainsKey(processId))
{
Process process;
try
{
process = Process.GetProcessById(processId);
}
catch (ArgumentException ex)
{
WriteError(new ErrorRecord(
ex,
"ProcessIdNotFound",
ErrorCategory.ObjectNotFound,
processId));
continue;
}

WriteDebug("Found matching process.");

matchingProcesses.Add(process);
keys.Add(processId, 0);
}
}
}

return matchingProcesses;
} // GetMatchingProcessesById

/// <summary>
/// Retrieves the list of all processes matching the InputObject
/// parameter.
/// </summary>
/// <returns>The matching processes.</returns>
[EnvironmentPermissionAttribute(
SecurityAction.LinkDemand,
Unrestricted = true)]
private List<Process> GetProcessesByInput()
{
new EnvironmentPermission(
PermissionState.Unrestricted).Assert();

List<Process> matchingProcesses = new List<Process>();

if (null != this.Input)
{
// The keys dictionary is used for rapid lookup of the
// processes already in the matchingProcesses list.
Dictionary<int, byte> keys = new Dictionary<int, byte>();

foreach (Process process in this.Input)


{
WriteVerbose("Refreshing process object.");

if (!keys.ContainsKey(process.Id))
{
try
{
process.Refresh();
}
catch (Win32Exception)
{
}
catch (InvalidOperationException)
{
}

matchingProcesses.Add(process);
}
}
}

return matchingProcesses;
} // GetProcessesByInput
#endregion Private Methods
} // End GetProcCommand class.

#endregion GetProcCommand
}

Consulte también
Windows PowerShell SDK
Código de ejemplo GetProc05 (VB.NET)
Artículo • 27/09/2021

Este es el código VB.NET completo para el cmdlet de ejemplo GetProc05.

VB

Imports System
Imports System.Collections.Generic
Imports Win32Exception = System.ComponentModel.Win32Exception
Imports System.Diagnostics
Imports System.Security.Permissions

'Windows PowerShell namespace


Imports System.Management.Automation
Imports System.ComponentModel

Namespace Microsoft.Samples.PowerShell.Commands

' This sample is a complete implementation of the get-proc Cmdlet.


#Region "GetProcCommand"

''' <summary>
''' This class implements the get-proc cmdlet
''' </summary>
<Cmdlet(VerbsCommon.Get, "Proc", _
DefaultParameterSetName:="ProcessName")> _
Public Class GetProcCommand
Inherits PSCmdlet
#Region "Parameters"

''' <summary>
''' The list of process names on which this cmdlet will work
''' </summary>
<Parameter(Position:=0, ParameterSetName:="ProcessName", _
ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True), _
ValidateNotNullOrEmpty()> _
Public Property Name() As String()
Get
Return processNames
End Get

Set(ByVal value As String())


processNames = value
End Set

End Property

''' <summary>
''' gets/sets an array of process IDs
''' </summary>
<Parameter(ParameterSetName:="Id", _
Mandatory:=True, ValueFromPipeline:=True, _
ValueFromPipelineByPropertyName:=True, _
HelpMessage:="The unique id of the process to get.")> _
Public Property Id() As Integer()
Get
Return processIds
End Get
Set(ByVal value As Integer())
processIds = value
End Set
End Property

''' <summary>
''' If the input is a stream of [collections of] Process
''' objects, we bypass the ProcessName and Id parameters and
''' read the Process objects directly. This allows us to deal
''' with processes which have wildcard characters in their name.
''' <value>Process objects</value>
''' </summary>
<Parameter(ParameterSetName:="InputObject", _
Mandatory:=True, ValueFromPipeline:=True)> _
Public Property Input() As Process()
Get
Return inputObjects
End Get
Set(ByVal value As Process())
inputObjects = value
End Set
End Property

#End Region

#Region "Cmdlet Overrides"

''' <summary>
''' For each of the requested processnames, retrieve and write
''' the associated processes.
''' </summary>
Protected Overrides Sub ProcessRecord()
Dim matchingProcesses As List(Of Process)

WriteDebug("Obtaining list of matching process objects.")

Select Case ParameterSetName


Case "Id"
matchingProcesses = GetMatchingProcessesById()
Case "ProcessName"
matchingProcesses = GetMatchingProcessesByName()
Case "InputObject"
matchingProcesses = GetProcessesByInput()
Case Else
ThrowTerminatingError(New ErrorRecord( _
New ArgumentException("Bad ParameterSetName"), _
"UnableToAccessProcessList", _
ErrorCategory.InvalidOperation, Nothing))
Return
End Select

WriteDebug("Outputting matching process objects.")

matchingProcesses.Sort(AddressOf ProcessComparison)

Dim process As Process


For Each process In matchingProcesses
WriteObject(process)
Next process

End Sub 'ProcessRecord

#End Region

#Region "protected Methods and Data"


''' <summary>
''' Retrieves the list of all processes matching the ProcessName
''' parameter.
''' Generates a non-terminating error for each specified
''' process name which is not found even though it contains
''' no wildcards.
''' </summary>
''' <returns></returns>

Private Function GetMatchingProcessesByName() As List(Of Process)

Dim allProcesses As List(Of Process) = _


New List(Of Process)(Process.GetProcesses())

' The keys dictionary will be used for rapid lookup of


' processes already in the matchingProcesses list.
Dim keys As Dictionary(Of Integer, Byte) = _
New Dictionary(Of Integer, Byte)()

Dim matchingProcesses As List(Of Process) = New List(Of Process)


()

If Nothing Is processNames Then


matchingProcesses.AddRange(allProcesses)
Else
Dim pattern As String
For Each pattern In processNames
WriteVerbose(("Finding matches for process name """ & _
pattern & """."))

' WildCard search on the available processes


Dim wildcard As New WildcardPattern(pattern, _
WildcardOptions.IgnoreCase)

Dim found As Boolean = False

Dim process As Process


For Each process In allProcesses
If Not keys.ContainsKey(process.Id) Then
Dim processName As String = _
SafeGetProcessName(process)

' Remove the process from the allProcesses list


' so that it's not tested again.
If processName.Length = 0 Then
allProcesses.Remove(process)
End If

' Perform a wildcard search on this particular


' process and check whether this matches the
' pattern specified.
If Not wildcard.IsMatch(processName) Then
GoTo ContinueForEach2
End If

WriteDebug(String.Format( _
"Found matching process id ""{0}"".",
process.Id))

' We have found a match.


found = True

' Store the process ID so that we don't add the


' same one twice.
keys.Add(process.Id, 0)

' Add the process to the processes list.


matchingProcesses.Add(process)
End If
ContinueForEach2:
Next process ' foreach (Process...
If Not found AndAlso Not _
WildcardPattern.ContainsWildcardCharacters(pattern) _
Then
WriteError(New ErrorRecord( _
New ArgumentException("Cannot find process name
" & _
" " & pattern & "."), "ProcessNameNotFound", _
ErrorCategory.ObjectNotFound, pattern))
End If
Next pattern
End If
Return matchingProcesses

End Function 'GetMatchingProcessesByName

''' <summary>
''' Returns the name of a process. If an error occurs, a blank
''' string will be returned.
''' </summary>
''' <param name="process">The process whose name will be
''' returned.</param>
''' <returns>The name of the process.</returns>
Protected Shared Function SafeGetProcessName(ByVal process As
Process) _
As String

Dim name As String = ""

If Not (process Is Nothing) Then


Try
Return process.ProcessName
Catch e1 As Win32Exception
Catch e2 As InvalidOperationException
End Try
End If
Return name

End Function 'SafeGetProcessName

#End Region

#Region "Private Methods"

''' <summary>
''' Function to sort by ProcessName first, then by Id
''' </summary>
''' <param name="x">first Process object</param>
''' <param name="y">second Process object</param>
''' <returns>
''' returns less than zero if x less than y,
''' greater than 0 if x greater than y, 0 if x == y
''' </returns>
Private Shared Function ProcessComparison(ByVal x As Process, _
ByVal y As Process) As Integer
Dim diff As Integer = String.Compare(SafeGetProcessName(x), _
SafeGetProcessName(y),
StringComparison.CurrentCultureIgnoreCase)

If 0 <> diff Then


Return diff
End If
Return x.Id - y.Id

End Function 'ProcessComparison

''' <summary>
''' Retrieves the list of all processes matching the Id
''' parameter.
''' Generates a non-terminating error for each specified
''' process ID which is not found.
''' </summary>
''' <returns>An array of processes that match the given id.
''' </returns>
Protected Function GetMatchingProcessesById() As List(Of Process)
Dim matchingProcesses As List(Of Process) = New List(Of Process)

If Not (processIds Is Nothing) Then

' The keys dictionary will be used for rapid lookup of


' processes already in the matchingProcesses list.
Dim keys As Dictionary(Of Integer, Byte) = _
New Dictionary(Of Integer, Byte)()

Dim processId As Integer


For Each processId In processIds
WriteVerbose("Finding match for process id " & _
processId & ".")

If Not keys.ContainsKey(processId) Then


Dim process As Process
Try
process = _
System.Diagnostics.Process.GetProcessById( _
processId)
Catch ex As ArgumentException
WriteError(New ErrorRecord(ex, _
"ProcessIdNotFound", _
ErrorCategory.ObjectNotFound, processId))
GoTo ContinueForEach1
End Try

WriteDebug("Found matching process.")

matchingProcesses.Add(process)
keys.Add(processId, 0)
End If
ContinueForEach1:
Next processId
End If

Return matchingProcesses

End Function 'GetMatchingProcessesById

''' <summary>
''' Retrieves the list of all processes matching the Input
''' parameter.
''' </summary>
Private Function GetProcessesByInput() As List(Of Process)

Dim matchingProcesses As List(Of Process) = New List(Of Process)


()

If Not (Nothing Is Input) Then


' The keys dictionary will be used for rapid lookup of
' processes already in the matchingProcesses list.
Dim keys As Dictionary(Of Integer, Byte) = _
New Dictionary(Of Integer, Byte)()
Dim process As Process
For Each process In Input
WriteVerbose("Refreshing process object.")

If Not keys.ContainsKey(process.Id) Then


Try
process.Refresh()
Catch e1 As Win32Exception
Catch e2 As InvalidOperationException
End Try
matchingProcesses.Add(process)
End If
Next process
End If
Return matchingProcesses

End Function 'GetProcessesByInput

#End Region

#Region "Private Data"

Private processNames() As String


Private processIds() As Integer
Private inputObjects() As Process

#End Region

End Class 'GetProcCommand

#End Region

#Region "PowerShell snap-in" '


''' <summary>
''' Create this sample as an PowerShell snap-in
''' </summary>
<RunInstaller(True)> _
Public Class GetProcPSSnapIn05
Inherits PSSnapIn

''' <summary>
''' Create an instance of the GetProcPSSnapIn05
''' </summary>
Public Sub New()

End Sub 'New

''' <summary>
''' Get a name for this PowerShell snap-in. This name will
''' be used in registering
''' this PowerShell snap-in.
''' </summary>

Public Overrides ReadOnly Property Name() As String


Get
Return "GetProcPSSnapIn05"
End Get
End Property

''' <summary>
''' Vendor information for this PowerShell snap-in.
''' </summary>

Public Overrides ReadOnly Property Vendor() As String


Get
Return "Microsoft"
End Get
End Property

''' <summary>
''' Gets resource information for vendor. This is a string of
format:
''' resourceBaseName,resourceName.
''' </summary>

Public Overrides ReadOnly Property VendorResource() As String


Get
Return "GetProcPSSnapIn05,Microsoft"
End Get
End Property

''' <summary>
''' Description of this PowerShell snap-in.
''' </summary>

Public Overrides ReadOnly Property Description() As String


Get
Return "This is a PowerShell snap-in that includes " & _
"the get-proc sample."
End Get
End Property
End Class 'GetProcPSSnapIn05

#End Region

End Namespace

Consulte también
Windows PowerShell SDK
Ejemplos de código StopProc01
Artículo • 24/09/2021

Este es el ejemplo de código para el cmdlet de ejemplo StopProc01. Este es el Stop-


Process ejemplo de cmdlet descrito en Creación de un cmdlet que modifica el sistema.

El cmdlet está diseñado para detener los procesos que se recuperan mediante el Stop-
Process cmdlet Get-Proc (descrito en Creación del primer cmdlet).

7 Nota

Puede descargar el archivo de código fuente de C# (stopproc01.cs) para el cmdlet


Stop-Proc mediante el Kit de desarrollo de software de Microsoft Windows para los
componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Lenguaje Tema

C# Código de ejemplo StopProc01 (C#)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo StopProc01 (C#)
Artículo • 27/09/2021

Este es el código de C# completo para el cmdlet de ejemplo StopProc01.

7 Nota

Puede descargar el archivo de código fuente de C# (stopproc01.cs) para el cmdlet


Stop-Proc mediante el Kit de desarrollo de software de Microsoft Windows para los
componentes en tiempo de ejecución de Windows Vista y .NET Framework 3.0.
Para obtener instrucciones de descarga, consulte How to Install Windows
PowerShell and Download the Windows PowerShell SDK. Los archivos de origen
descargados están disponibles en el <PowerShell Samples> directorio .

C#

using System;
using System.Diagnostics;
using System.Collections;
using Win32Exception = System.ComponentModel.Win32Exception;
using System.Management.Automation; // Windows PowerShell namespace
using System.Globalization;

// This sample shows how to implement a PassThru parameter that indicates


that
// the user wants the cmdlet to return an object, and how to request
// user feedback by calls to the ShouldProcess and ShouldContinue methods.
//
// To test this cmdlet, create a module folder that has the same name as
// this assembly (StopProcesssample01), save the assembly in the module
folder, and then run the
// following command:
// import-module stopprocesssample01

namespace Microsoft.Samples.PowerShell.Commands
{
#region StopProcCommand

/// <summary>
/// This class implements the stop-proc cmdlet.
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
SupportsShouldProcess = true)]
public class StopProcCommand : Cmdlet
{
#region Parameters

/// <summary>
/// This parameter provides the list of process names on
/// which the Stop-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true
)]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// This parameter overrides the ShouldContinue call to force
/// the cmdlet to stop its operation. This parameter should always
/// be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// This parameter indicates that the cmdlet should return
/// an object to the pipeline after the processing has been
/// completed.
/// </summary>
[Parameter]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;

#endregion Parameters

#region Cmdlet Overrides

/// <summary>
/// The ProcessRecord method does the following for each of the
/// requested process names:
/// 1) Check that the process is not a critical process.
/// 2) Attempt to stop that process.
/// If no process is requested then nothing occurs.
/// </summary>
protected override void ProcessRecord()
{
foreach (string name in processNames)
{
// For every process name passed to the cmdlet, get the
associated
// processes.
// Write a nonterminating error for failure to retrieve
// a process.
Process[] processes;

try
{
processes = Process.GetProcessesByName(name);
}
catch (InvalidOperationException ioe)
{
WriteError(new
ErrorRecord(ioe,"UnableToAccessProcessByName",
ErrorCategory.InvalidOperation, name));

continue;
}

// Try to stop the processes that have been retrieved.


foreach (Process process in processes)
{
string processName;

try
{
processName = process.ProcessName;
}
catch (Win32Exception e)
{
WriteError(new ErrorRecord(e, "ProcessNameNotFound",
ErrorCategory.ReadError,
process));
continue;
}

// Confirm the operation with the user first.


// This is always false if the WhatIf parameter is set.
if
(!ShouldProcess(string.Format(CultureInfo.CurrentCulture,"{0} ({1})",
processName,
process.Id)))
{
continue;
}

// Make sure that the user really wants to stop a


critical
// process that could possibly stop the computer.
bool criticalProcess =

criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));

if (criticalProcess &&!force)
{
string message = String.Format
(CultureInfo.CurrentCulture,
"The process \"{0}\" is a critical process
and should not be stopped. Are you sure you wish to stop the process?",
processName);

// It is possible that the ProcessRecord method is


called
// multiple times when objects are received as inputs
from
// the pipeline. So to retain YesToAll and NoToAll
input that
// the user may enter across multiple calls to this
function,
// they are stored as private members of the cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll, ref noToAll))
{
continue;
}
} // if (criticalProcess...

// Stop the named process.


try
{
process.Kill();
}
catch (Exception e)
{
if ((e is Win32Exception) || (e is SystemException)
||
(e is InvalidOperationException))
{
// This process could not be stopped so write
// a nonterminating error.
WriteError(new ErrorRecord(e,
"CouldNotStopProcess",
ErrorCategory.CloseError,
process));
continue;
} // if ((e is...
else throw;
} // catch

// If the PassThru parameter is


// specified, return the terminated process.
if (passThru)
{
WriteObject(process);
}
} // foreach (Process...
} // foreach (string...
} // ProcessRecord

#endregion Cmdlet Overrides

#region Private Data

private bool yesToAll, noToAll;

/// <summary>
/// Partial list of critical processes that should not be
/// stopped. Lower case is used for case insensitive matching.
/// </summary>
private ArrayList criticalProcessNames = new ArrayList(
new string[] { "system", "winlogon", "spoolsv" }
);

#endregion Private Data

} // StopProcCommand

#endregion StopProcCommand
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplos de código
StopProcessSample04
Artículo • 24/09/2021

Estos son los ejemplos de código para el cmdlet de ejemplo StopProc00. Este es el
Stop-Process ejemplo de cmdlet descrito en Agregar conjuntos de parámetros a un

cmdlet. El Stop-Process cmdlet está diseñado para detener los procesos que se
recuperan mediante el cmdlet Get-Proc (descrito en Creación del primer cmdlet).

7 Nota

Puede descargar C# (stopprocesssample04.cs) y VB.NET (stopprocesssample04.vb)


para este cmdlet de Stop-Proc mediante el Kit de desarrollo de software de
Microsoft Windows para los componentes de tiempo de ejecución de Windows
Vista y .NET Framework 3.0. Para obtener instrucciones de descarga, consulte How
to Install Windows PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Para obtener código de ejemplo completo, consulte los temas siguientes.

Lenguaje Tema

C# Código de ejemplo StopProc04 (C#)

VB.NET Código de ejemplo StopProc04 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo
StopProcessSample04 (C#)
Artículo • 27/09/2021

Este es el código de ejemplo de C# completo para el cmdlet de ejemplo StopProc04.


Este es el código del cmdlet descrito Stop-Process en Adding Parameter Sets to a
Cmdlet. El Stop-Process cmdlet está diseñado para detener los procesos que se
recuperan mediante el cmdlet Get-Proc (descrito en Creación del primer cmdlet).

7 Nota

Puede descargar el archivo de código fuente de C# (stopprocesssample04.cs) para


este cmdlet de Stop-Proc mediante el Kit de desarrollo de software de Microsoft
Windows para los componentes en tiempo de ejecución de Windows Vista y .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .

C#

using System;
using System.Diagnostics;
using System.Collections;
using Win32Exception = System.ComponentModel.Win32Exception;
using System.Management.Automation; //Windows PowerShell
namespace
using System.Globalization;

// This sample shows how to declare parameter sets, the input object, and
// how to specify the default parameter set to use.
//
// To test this cmdlet, create a module folder that has the same name as
// this assembly (StopProcesssample04), save the assembly in the module
folder, and then run the
// following command:
// import-module stopprocesssample04

namespace Microsoft.Samples.PowerShell.Commands
{
#region StopProcCommand

/// <summary>
/// This class implements the stop-proc cmdlet.
/// </summary>
[Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName = "ProcessId",
SupportsShouldProcess = true)]
public class StopProcCommand : PSCmdlet
{
#region Parameters

/// <summary>
/// This parameter provides the list of process names on
/// which the Stop-Proc cmdlet will work.
/// </summary>
[Parameter(
Position = 0,
ParameterSetName = "ProcessName",
Mandatory = true,
ValueFromPipeline = true,
ValueFromPipelineByPropertyName = true,
HelpMessage = "The name of one or more processes to stop.
Wildcards are permitted."
)]
[Alias("ProcessName")]
public string[] Name
{
get { return processNames; }
set { processNames = value; }
}
private string[] processNames;

/// <summary>
/// This parameter overrides the ShouldContinue call to force
/// the cmdlet to stop its operation. This parameter should always
/// be used with caution.
/// </summary>
[Parameter]
public SwitchParameter Force
{
get { return force; }
set { force = value; }
}
private bool force;

/// <summary>
/// This parameter indicates that the cmdlet should return
/// an object to the pipeline after the processing has been
/// completed.
/// </summary>
[Parameter(
HelpMessage = "If set the process(es) will be passed to the
pipeline after stopped."
)]
public SwitchParameter PassThru
{
get { return passThru; }
set { passThru = value; }
}
private bool passThru;
/// This parameter provides the list of process identifiers on
/// which the Stop-Proc cmdlet will work.
[Parameter(
ParameterSetName = "ProcessId",
Mandatory = true,
ValueFromPipelineByPropertyName = true,
ValueFromPipeline = true
)]
[Alias("ProcessId")]
public int[] Id
{
get { return processIds; }
set { processIds = value; }
}
private int[] processIds;

/// <summary>
/// This parameter accepts an array of Process objects from the
/// the pipeline. This object contains the processes to stop.
/// </summary>
/// <value>Process objects</value>
[Parameter(
ParameterSetName = "InputObject",
Mandatory = true,
ValueFromPipeline = true)]
public Process[] InputObject
{
get { return inputObject; }
set { inputObject = value; }
}
private Process[] inputObject;

#endregion Parameters

#region CmdletOverrides

/// <summary>
/// The ProcessRecord method does the following for each of the
/// requested process names:
/// 1) Check that the process is not a critical process.
/// 2) Attempt to stop that process.
/// If no process is requested then nothing occurs.
/// </summary>
protected override void ProcessRecord()
{
switch (ParameterSetName)
{
case "ProcessName":
ProcessByName();
break;

case "ProcessId":
ProcessById();
break;
case "InputObject":
foreach (Process process in inputObject)
{
SafeStopProcess(process);
}
break;

default:
throw new ArgumentException("Bad ParameterSet Name");
} // switch (ParameterSetName...
} // ProcessRecord

#endregion Cmdlet Overrides

#region Helper Methods

/// <summary>
/// Returns all processes with matching names.
/// </summary>
/// <param name="processName">
/// The name of the processes to return.
/// </param>
/// <param name="allProcesses">An array of all
/// computer processes.</param>
/// <returns>An array of matching processes.</returns>
internal ArrayList SafeGetProcessesByName(string processName,
ref ArrayList allProcesses)
{
// Create and array to store the matching processes.
ArrayList matchingProcesses = new ArrayList();

// Create the wildcard for pattern matching.


WildcardOptions options = WildcardOptions.IgnoreCase |
WildcardOptions.Compiled;
WildcardPattern wildcard = new WildcardPattern(processName,
options);

// Walk all of the machine processes.


foreach(Process process in allProcesses)
{
string processNameToMatch = null;
try
{
processNameToMatch = process.ProcessName;
}
catch (Win32Exception e)
{
// Remove the process from the list so that it is not
// checked again.
allProcesses.Remove(process);

string message =
String.Format(CultureInfo.CurrentCulture, "The
process \"{0}\" could not be found",
processName);
WriteVerbose(message);
WriteError(new ErrorRecord(e, "ProcessNotFound",
ErrorCategory.ObjectNotFound,
processName));

continue;
}

if (!wildcard.IsMatch(processNameToMatch))
{
continue;
}

matchingProcesses.Add(process);
} // foreach(Process...

return matchingProcesses;
} // SafeGetProcessesByName

/// <summary>
/// Safely stops a named process. Used as standalone function
/// to declutter the ProcessRecord method.
/// </summary>
/// <param name="process">The process to stop.</param>
private void SafeStopProcess(Process process)
{
string processName = null;

try
{
processName = process.ProcessName;
}
catch (Win32Exception e)
{
WriteError(new ErrorRecord(e, "ProcessNotFound",
ErrorCategory.OpenError, processName));

return;
}

// Confirm the operation first.


// This is always false if the WhatIf parameter is specified.
if (!ShouldProcess(string.Format(CultureInfo.CurrentCulture,
"{0} ({1})", processName, process.Id)))
{
return;
}

// Make sure that the user really wants to stop a critical


// process that can possibly stop the computer.
bool criticalProcess =
criticalProcessNames.Contains(processName.ToLower(CultureInfo.CurrentCulture
));
string message = null;
if (criticalProcess && !force)
{
message = String.Format(CultureInfo.CurrentCulture,
"The process \"{0}\" is a
critical process and should not be stopped. Are you sure you wish to stop
the process?",
processName);
// It is possible that the ProcessRecord method is called
// multiple times when objects are recieved as inputs from
// the pipeline. So to retain YesToAll and NoToAll input that
// the user may enter across mutilple calls to this function,
// they are stored as private members of the cmdlet.
if (!ShouldContinue(message, "Warning!",
ref yesToAll, ref noToAll))
{
return;
}
} // if (criticalProcess...

// Display a warning message if stopping a critical


// process.
if (criticalProcess)
{
message =
String.Format(CultureInfo.CurrentCulture,
"Stopping the critical process \"{0}\".",
processName);
WriteWarning(message);
} // if (criticalProcess...

try
{
// Stop the process.
process.Kill();
}
catch (Exception e)
{
if ((e is Win32Exception) || (e is SystemException) ||
(e is InvalidOperationException))
{
// This process could not be stopped so write
// a non-terminating error.
WriteError(new ErrorRecord(e, "CouldNotStopProcess",
ErrorCategory.CloseError,
process)
);

return;
} // if ((e is...
else throw;
} // catch

// Write a user-level verbose message to the pipeline. These are


// intended to give the user detailed information on the
// operations performed by the cmdlet. These messages will
// appear with the -Verbose option.
message = String.Format(CultureInfo.CurrentCulture,
"Stopped process \"{0}\", pid {1}.",
processName, process.Id);

WriteVerbose(message);

// If the PassThru prameter is specified, return the terminated


// process to the pipeline.
if (passThru)
{
// Write a debug message to the host that can be used
// when troubleshooting a problem. All debug messages
// will appear with the -Debug option
message =
String.Format(CultureInfo.CurrentCulture,
"Writing process \"{0}\" to pipeline",
processName);
WriteDebug(message);
WriteObject(process);
} // if (passThru..
} // SafeStopProcess

/// <summary>
/// Stop processes based on their names (using the
/// ParameterSetName as ProcessName)
/// </summary>
private void ProcessByName()
{
ArrayList allProcesses = null;

// Get a list of all processes.


try
{
allProcesses = new ArrayList(Process.GetProcesses());
}
catch (InvalidOperationException ioe)
{
base.ThrowTerminatingError(new ErrorRecord(
ioe, "UnableToAccessProcessList",
ErrorCategory.InvalidOperation, null));
}

// If a process name is passed to the cmdlet, get


// the associated processes.
// Write a nonterminating error for failure to
// retrieve a process.
foreach (string name in processNames)
{
// The allProcesses array list is passed as a reference
because
// any process whose name cannot be obtained will be removed
// from the list so that its not compared the next time.
ArrayList processes =
SafeGetProcessesByName(name, ref allProcesses);

// If no processes were found write a non-


// terminating error.
if (processes.Count == 0)
{
WriteError(new ErrorRecord(
new Exception("Process not found."),
"ProcessNotFound",
ErrorCategory.ObjectNotFound,
name));
} // if (processes...
// Otherwise terminate all processes in the list.
else
{
foreach (Process process in processes)
{
SafeStopProcess(process);
} // foreach (Process...
} // else
} // foreach (string...
} // ProcessByName

/// <summary>
/// Stop processes based on their identifiers (using the
/// ParameterSetName as ProcessIds)
/// </summary>
internal void ProcessById()
{
foreach (int processId in processIds)
{
Process process = null;
try
{
process = Process.GetProcessById(processId);

// Write a debug message to the host that can be used


// when troubleshooting a problem. All debug messages
// will appear with the -Debug option
string message =
String.Format(CultureInfo.CurrentCulture,
"Acquired process for pid : {0}",
process.Id);
WriteDebug(message);
}
catch (ArgumentException ae)
{
string
message = String.Format(CultureInfo.CurrentCulture,
"The process id {0} could not be
found",
processId);
WriteVerbose(message);
WriteError(new ErrorRecord(ae, "ProcessIdNotFound",
ErrorCategory.ObjectNotFound,
processId));
continue;
}

SafeStopProcess(process);
} // foreach (int...
} // ProcessById

#endregion Helper Methods

#region Private Data

private bool yesToAll, noToAll;

/// <summary>
/// Partial list of critical processes that should not be
/// stopped. Lower case is used for case insensitive matching.
/// </summary>
private ArrayList criticalProcessNames = new ArrayList(
new string[] { "system", "winlogon", "spoolsv", "calc" }
);

#endregion Private Data

} // StopProcCommand

#endregion StopProcCommand
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Código de ejemplo
StopProcessSample04 (VB.NET)
Artículo • 24/09/2021

Este es el código de ejemplo VB.NET completo para el cmdlet de ejemplo StopProc04.


Este es el código del cmdlet descrito Stop-Process en Adding Parameter Sets to a
Cmdlet. El Stop-Process cmdlet está diseñado para detener los procesos que se
recuperan mediante el cmdlet Get-Proc (descrito en Creación del primer cmdlet).

7 Nota

Puede descargar el archivo de código fuente VB.NET (stopprocesssample04.vb)


para este cmdlet de Stop-Proc mediante el Kit de desarrollo de software de
Microsoft Windows para los componentes en tiempo de ejecución de Windows
Vista y .NET Framework 3.0. Para obtener instrucciones de descarga, consulte How
to Install Windows PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

VB

Imports System
Imports System.Diagnostics
Imports System.Collections
Imports Win32Exception = System.ComponentModel.Win32Exception
Imports System.Management.Automation 'Windows PowerShell namespace
Imports System.ComponentModel
Imports System.Globalization

Namespace Microsoft.Samples.PowerShell.Commands

' This sample introduces parameter sets, the input object and
' DefaultParameterSet.
#Region "StopProcCommand"

''' <summary>
''' Class that implements the stop-proc cmdlet.
''' </summary>
<Cmdlet(VerbsLifecycle.Stop, "Proc",
DefaultParameterSetName:="ProcessId", _
SupportsShouldProcess:=True)> _
Public Class StopProcCommand
Inherits PSCmdlet
#Region "Parameters"
''' <summary>
''' The list of process names on which this cmdlet will work.
''' </summary>

<Parameter(Position:=0, ParameterSetName:="ProcessName", _
Mandatory:=True, _
ValueFromPipeline:=True, ValueFromPipelineByPropertyName:=True, _
HelpMessage:="The name of one or more processes to stop. " & _
"Wildcards are permitted."), [Alias]("ProcessName")> _
Public Property Name() As String()
Get
Return processNames
End Get
Set(ByVal value As String())
processNames = value
End Set
End Property
Private processNames() As String

''' <summary>
''' Overrides the ShouldContinue check to force stop operation.
''' This option should always be used with caution.
''' </summary>

<Parameter()> _
Public Property Force() As SwitchParameter
Get
Return myForce
End Get
Set(ByVal value As SwitchParameter)
myForce = value
End Set
End Property
Private myForce As Boolean

''' <summary>
''' Common parameter to determine if the process should pass the
''' object down the pipeline after the process has been stopped.
''' </summary>

<Parameter( _
HelpMessage:= _
"If set the process(es) will be passed to the pipeline " & _
"after stopping them.")> _
Public Property PassThru() As SwitchParameter
Get
Return myPassThru
End Get
Set(ByVal value As SwitchParameter)
myPassThru = value
End Set
End Property
Private myPassThru As Boolean
''' <summary>
''' The list of process IDs on which this cmdlet will work.
''' </summary>

<Parameter(ParameterSetName:="ProcessId", _
Mandatory:=True, _
ValueFromPipelineByPropertyName:=True, _
ValueFromPipeline:=True), [Alias]("ProcessId")> _
Public Property Id() As Integer()
Get
Return processIds
End Get
Set(ByVal value As Integer())
processIds = value
End Set
End Property
Private processIds() As Integer

''' <summary>
''' An array of Process objects from the stream to stop.
''' </summary>
''' <value>Process objects</value>
<Parameter(ParameterSetName:="InputObject", _
Mandatory:=True, ValueFromPipeline:=True)> _
Public Property InputObject() As Process()
Get
Return myInputObject
End Get
Set(ByVal value As Process())
myInputObject = value
End Set
End Property
Private myInputObject() As Process

#End Region

#Region "CmdletOverrides"
''' <summary>
''' For each of the requested processnames:
''' 1) check it's not a special process
''' 2) attempt to stop that process.
''' If no process requested, then nothing occurs.
''' </summary>
Protected Overrides Sub ProcessRecord()
Select Case ParameterSetName
Case "ProcessName"
ProcessByName()

Case "ProcessId"
ProcessById()

Case "InputObject"
Dim process As Process
For Each process In myInputObject
SafeStopProcess(process)
Next process

Case Else
Throw New ArgumentException("Bad ParameterSet Name")
End Select

End Sub 'ProcessRecord ' ProcessRecord


#End Region

#Region "Helper Methods"


''' <summary>
''' Returns all processes with matching names.
''' </summary>
''' <param name="processName">
''' The name of the process(es) to return
''' </param>
''' <param name="allProcesses">An array of all
''' machine processes.</param>
''' <returns>An array of matching processes.</returns>
Friend Function SafeGetProcessesByName(ByVal processName As String,
_
ByRef allProcesses As ArrayList) As ArrayList

' Create and array to store the matching processes.


Dim matchingProcesses As New ArrayList()

' Create the wildcard for pattern matching.


Dim options As WildcardOptions = WildcardOptions.IgnoreCase Or _
WildcardOptions.Compiled
Dim wildcard As New WildcardPattern(processName, options)

' Walk all of the machine processes.


Dim process As Process
For Each process In allProcesses
Dim processNameToMatch As String = Nothing
Try
processNameToMatch = process.ProcessName
Catch e As Win32Exception
' Remove the process from the list so that it is not
' checked again.
allProcesses.Remove(process)

Dim message As String = _


String.Format(CultureInfo.CurrentCulture, _
"The process ""{0}"" could not be found",
processName)
WriteVerbose(message)
WriteError(New ErrorRecord(e, _
"ProcessNotFound", ErrorCategory.ObjectNotFound, _
processName))

GoTo ContinueForEach1
End Try

If Not wildcard.IsMatch(processNameToMatch) Then


GoTo ContinueForEach1
End If

matchingProcesses.Add(process)
ContinueForEach1:
Next process
Return matchingProcesses

End Function 'SafeGetProcessesByName

''' <summary>
''' Safely stops a named process. Used as standalone function
''' to declutter ProcessRecord method.
''' </summary>
''' <param name="process">The process to stop.</param>
Private Sub SafeStopProcess(ByVal process As Process)
Dim processName As String = Nothing

Try
processName = process.ProcessName
Catch e As Win32Exception
WriteError(New ErrorRecord(e, "ProcessNotFound", _
ErrorCategory.OpenError, processName))

Return
End Try

' Confirm the operation first.


' This is always false if WhatIf is set.
If Not ShouldProcess(String.Format(CultureInfo.CurrentCulture, _
"{0} ({1})", processName, process.Id)) Then
Return
End If

' Make sure the user really wants to stop a critical


' process and possibly stop the machine.
Dim criticalProcess As Boolean = _
criticalProcessNames.Contains( _
processName.ToLower(CultureInfo.CurrentCulture))

Dim message As String = Nothing


If criticalProcess AndAlso Not myForce Then
message = String.Format(CultureInfo.CurrentCulture, _
"The process ""{0}"" is a critical process and " & _
"should not be stopped. " & _
"Are you sure you wish to stop the process?",
processName)

' It is possible that ProcessRecord is called multiple


' when objects are received as inputs from a pipeline.
' So, to retain YesToAll and NoToAll input that the
' user may enter across multiple calls to this
' function, they are stored as private members of the
' Cmdlet.
If Not ShouldContinue(message, "Warning!", yesToAll,
noToAll) Then
Return
End If
End If

' Display a warning information if stopping a critical


' process
If criticalProcess Then
message = String.Format(CultureInfo.CurrentCulture, _
"Stopping the critical process ""{0}"".", processName)
WriteWarning(message)
End If

Try
' Stop the process.
process.Kill()
Catch e As Exception
If TypeOf e Is Win32Exception OrElse TypeOf e Is
SystemException _
OrElse TypeOf e Is InvalidOperationException Then
' This process could not be stopped so write
' a non-terminating error.
WriteError(New ErrorRecord(e, _
"CouldNotStopProcess", ErrorCategory.CloseError,
process))
Return
Else
Throw
End If
End Try

' Write a user-level message to the pipeline. These are


' intended to give the user detailed information on the
' operations performed by the Cmdlet. These messages will
' appear with the -Verbose option.
message = String.Format(CultureInfo.CurrentCulture, _
"Stopped process ""{0}"", pid {1}.", processName,
process.Id)

WriteVerbose(message)

' If the -PassThru command line argument is


' specified, pass the terminated process on.
If myPassThru Then
' Write a debug message to the host which will be helpful
' in troubleshooting a problem. All debug messages
' will appear with the -Debug option
message = String.Format(CultureInfo.CurrentCulture, _
"Writing process ""{0}"" to pipeline", processName)
WriteDebug(message)
WriteObject(process)
End If

End Sub 'SafeStopProcess


''' <summary>
''' Stop processes based on their names (using the
''' ParameterSetName as ProcessName)
''' </summary>
Private Sub ProcessByName()
Dim allProcesses As ArrayList = Nothing

' Get a list of all processes.


Try
allProcesses = New ArrayList(Process.GetProcesses())
Catch ioe As InvalidOperationException
MyBase.ThrowTerminatingError(New ErrorRecord(ioe, _
"UnableToAccessProcessList", _
ErrorCategory.InvalidOperation, Nothing))
End Try

' If a name parameter is passed to cmdlet, get


' the associated process(es).
' Write a non-terminating error for failure to
' retrieve a process
Dim name As String
For Each name In processNames
' The allProcesses array list is passed as a reference
because
' any process whose name cannot be obtained will be removed
' from the list so that its not compared the next time.
Dim processes As ArrayList = SafeGetProcessesByName(name, _
allProcesses)

' If no processes were found write a non-terminating error.


If processes.Count = 0 Then
WriteError(New ErrorRecord( _
New Exception("Process not found."), _
"ProcessNotFound", ErrorCategory.ObjectNotFound,
name))
Else
' Otherwise terminate all processes in the list.
Dim process As Process
For Each process In processes
SafeStopProcess(process)
Next process
End If

Next name

End Sub 'ProcessByName

''' <summary>
''' Stop processes based on their ids (using the
''' ParameterSetName as ProcessIds)
''' </summary>
Friend Sub ProcessById()
Dim processId As Integer
For Each processId In processIds
Dim process As Process = Nothing
Try
process =
System.Diagnostics.Process.GetProcessById(processId)

' Write a debug message to the host which will be


helpful
' in troubleshooting a problem. All debug messages
' will appear with the -Debug option
Dim message As String = String.Format( _
CultureInfo.CurrentCulture, _
"Acquired process for pid : {0}", process.Id)
WriteDebug(message)
Catch ae As ArgumentException
Dim message As String = String.Format( _
CultureInfo.CurrentCulture, _
"The process id {0} could not be found", processId)
WriteVerbose(message)
WriteError(New ErrorRecord(ae, _
"ProcessIdNotFound", _
ErrorCategory.ObjectNotFound, processId))
GoTo ContinueForEach1
End Try

SafeStopProcess(process)
ContinueForEach1:
Next processId

End Sub 'ProcessById ' ProcessById


#End Region

#Region "Private Data"

Private yesToAll, noToAll As Boolean

''' <summary>
''' Partial list of critical processes that should not be
''' stopped. Lower case is used for case insensitive matching.
''' </summary>
Private criticalProcessNames As New ArrayList( _
New String() {"system", "winlogon", "spoolsv", "calc"})

#End Region

End Class 'StopProcCommand

#End Region

#Region "PowerShell snap-in" '


''' <summary>
''' Create this sample as an PowerShell snap-in
''' </summary>
<RunInstaller(True)> _
Public Class StopProcPSSnapIn04
Inherits PSSnapIn
''' <summary>
''' Create an instance of the StopProcPSSnapIn04
''' </summary>
Public Sub New()

End Sub 'New

''' <summary>
''' Get a name for this PowerShell snap-in. This name will
''' be used in registering this PowerShell snap-in.
''' </summary>
Public Overrides ReadOnly Property Name() As String
Get
Return "StopProcPSSnapIn04"
End Get
End Property

''' <summary>
''' Vendor information for this PowerShell snap-in.
''' </summary>

Public Overrides ReadOnly Property Vendor() As String


Get
Return "Microsoft"
End Get
End Property

''' <summary>
''' Gets resource information for vendor. This is a string of
format:
''' resourceBaseName,resourceName.
''' </summary>
Public Overrides ReadOnly Property VendorResource() As String
Get
Return "StopProcPSSnapIn04,Microsoft"
End Get
End Property

''' <summary>
''' Description of this PowerShell snap-in.
''' </summary>
Public Overrides ReadOnly Property Description() As String
Get
Return "This is a PowerShell snap-in that includes " & _
"the stop-proc cmdlet."
End Get
End Property
End Class 'StopProcPSSnapIn04

#End Region

End Namespace
Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplos de código Runspace01
Artículo • 26/09/2021

Estos son los ejemplos de código para el espacio de ejecución descrito en Creación de
una aplicación de consola que ejecuta un comando especificado. El comando que se
invoca en el espacio de ejecución es el Get-Process cmdlet .

Para obtener código de ejemplo completo, vea los temas siguientes.

Lenguaje Tema

C# Ejemplo de código Runspace01 (C#)

VB.NET Ejemplo de código Runspace01 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace01 (C#)
Artículo • 24/09/2021

Estos son los ejemplos de código para el espacio de ejecución descrito en Creación de
una aplicación de consola que ejecuta un comando especificado. Para ello, la aplicación
invoca un espacio de ejecución y, a continuación, invoca un comando . (Tenga en cuenta
que esta aplicación no especifica información de configuración del espacio de ejecución
ni crea explícitamente una canalización). El comando que se invoca es el Get-Process
cmdlet .

7 Nota

Puede descargar el archivo de código fuente de C# (runspace01.cs) para este


espacio de ejecución mediante el Kit de desarrollo de software de Microsoft
Windows para los componentes en tiempo de ejecución de Windows Vista y
Microsoft .NET Framework 3.0. Para obtener instrucciones de descarga, consulte
How to Install Windows PowerShell and Download the Windows PowerShell SDK.
Los archivos de origen descargados están disponibles en el <PowerShell Samples>
directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Management.Automation;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace01
{
/// <summary>
/// This sample uses the PowerShell class to execute
/// the get-process cmdlet synchronously. The name and
/// handlecount are then extracted from the PSObjects
/// returned and displayed.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerShell object to run a command.
/// 2. Adding a command to the pipeline of the PowerShell object.
/// 3. Running the command synchronously.
/// 4. Using PSObject objects to extract properties from the objects
/// returned by the command.
/// </remarks>
private static void Main(string[] args)
{
// Create a PowerShell object. Creating this object takes care of
// building all of the other data structures needed to run the
command.
using (PowerShell powershell = PowerShell.Create().AddCommand("get-
process"))
{
Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Invoke the command synchronously and display the


// ProcessName and HandleCount properties of the
// objects that are returned.
foreach (PSObject result in powershell.Invoke())
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace01 (VB.NET)
Artículo • 24/09/2021

Estos son los ejemplos de código para el espacio de ejecución descritos en Creación de
una aplicación de consola que ejecuta un comando especificado. Para ello, la aplicación
invoca un espacio de ejecución y, a continuación, invoca un comando . (Tenga en cuenta
que esta aplicación no especifica información de configuración del espacio de ejecución
ni crea explícitamente una canalización). El comando que se invoca es el Get-Process
cmdlet .

Ejemplo de código
VB

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports System.Management.Automation
Imports System.Management.Automation.Host
Imports System.Management.Automation.Runspaces

Namespace Microsoft.Samples.PowerShell.Runspaces

Module Runspace01
' <summary>
' This sample uses the RunspaceInvoke class to execute
' the get-process cmdlet synchronously. The name and
' handlecount are then extracted from the PSObjects
' returned and displayed.
' </summary>
' <param name="args">Unused</param>
' <remarks>
' This sample demonstrates the following:
' 1. Creating an instance of the RunspaceInvoke class.
' 2. Using this instance to invoke a PowerShell command.
' 3. Using PSObject to extract properties from the objects
' returned by this command.
' </remarks>
Sub Main()
' Create an instance of the RunspaceInvoke class.
' This takes care of all building all of the other
' data structures needed...
Dim invoker As RunspaceInvoke = New RunspaceInvoke()

Console.WriteLine("Process HandleCount")
Console.WriteLine("--------------------------------")

' Now invoke the runspace and display the objects that are
' returned...
For Each result As PSObject In invoker.Invoke("get-process")
Console.WriteLine("{0,-20} {1}", _
result.Members("ProcessName").Value, _
result.Members("HandleCount").Value)
Next
System.Console.WriteLine("Hit any key to exit...")
System.Console.ReadKey()
End Sub
End Module
End Namespace

Consulte también
Windows PowerShell SDK
Ejemplos de código Runspace02
Artículo • 26/09/2021

Este es el código fuente del ejemplo Runspace02. En este ejemplo se usa la clase
System.Management.Automation.Runspaceinvoke para ejecutar el Get-Process cmdlet
de forma sincrónica. Windows A continuación, los formularios y el enlace de datos se
usan para mostrar los resultados en un control DataGridView.

Para obtener código de ejemplo completo, vea los temas siguientes.

Lenguaje Tema

C# Ejemplo de código Runspace02 (C#)

VB.NET Ejemplo de código Runspace02 (VB.NET)

Consulte también
Windows PowerShell SDK
Ejemplo de código Runspace02 (C#)
Artículo • 26/09/2021

Este es el código fuente de C# para el ejemplo Runspace02. En este ejemplo se usa la


clase System.Management.Automation.Runspaceinvoke para ejecutar el Get-Process
cmdlet de forma sincrónica. Windows A continuación, se usan formularios y enlaces de
datos para mostrar los resultados en un control DataGridView.

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Windows.Forms;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace02
{
/// <summary>
/// This method creates the form where the output is displayed.
/// </summary>
private static void CreateForm()
{
Form form = new Form();
DataGridView grid = new DataGridView();
form.Controls.Add(grid);
grid.Dock = DockStyle.Fill;

// Create a PowerShell object. Creating this object takes care of


// building all of the other data structures needed to run the
command.
using (PowerShell powershell = PowerShell.Create())
{
powershell.AddCommand("get-process").AddCommand("sort-
object").AddArgument("ID");
if (Runspace.DefaultRunspace == null)
{
Runspace.DefaultRunspace = powershell.Runspace;
}
Collection<PSObject> results = powershell.Invoke();

// The generic collection needs to be re-wrapped in an ArrayList


// for data-binding to work.
ArrayList objects = new ArrayList();
objects.AddRange(results);

// The DataGridView will use the PSObjectTypeDescriptor type


// to retrieve the properties.
grid.DataSource = objects;
}

form.ShowDialog();
}

/// <summary>
/// This sample uses a PowerShell object to run the
/// Get-Process cmdlet synchronously. Windows Forms and
/// data binding are then used to display the results in a
/// DataGridView control.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerShell object.
/// 2. Adding commands and arguments to the pipeline of
/// the powershell object.
/// 3. Running the commands synchronously.
/// 4. Using a DataGridView control to display the output
/// of the PowerShell object in a Windows Forms application.
/// </remarks>
private static void Main(string[] args)
{
Runspace02.CreateForm();
}
}
}

Consulte también
Windows PowerShell SDK
Ejemplo de código Runspace02
(VB.NET)
Artículo • 26/09/2021

Este es el código VB.NET del ejemplo Runspace02. En este ejemplo se usa la clase
System.Management.Automation.Runspaceinvoke para ejecutar el Get-Process cmdlet
de forma sincrónica. Windows A continuación, los formularios y el enlace de datos se
usan para mostrar los resultados en un control DataGridView.

Ejemplo de código
VB

Imports System
Imports System.Collections
Imports System.Collections.ObjectModel
Imports System.Windows.Forms
Imports System.Management.Automation.Runspaces
Imports System.Management.Automation

Namespace Microsoft.Samples.PowerShell.Runspaces

Class Runspace02

Shared Sub CreateForm()


Dim form As New Form()
Dim grid As New DataGridView()
form.Controls.Add(grid)
grid.Dock = DockStyle.Fill

' Create an instance of the RunspaceInvoke class.


' This takes care of all building all of the other
' data structures needed...
Dim invoker As New RunspaceInvoke()

Dim results As Collection(Of PSObject) = _


invoker.Invoke("get-process | sort-object ID")

' The generic collection needs to be re-wrapped in an ArrayList


' for data-binding to work...
Dim objects As New ArrayList()
objects.AddRange(results)

' The DataGridView will use the PSObjectTypeDescriptor type


' to retrieve the properties.
grid.DataSource = objects
form.ShowDialog()

End Sub 'CreateForm

''' <summary>
''' This sample uses the RunspaceInvoke class to execute
''' the get-process cmdlet synchronously. Windows Forms and data
''' binding are then used to display the results in a
''' DataGridView control.
''' </summary>
''' <param name="args">Unused</param>
''' <remarks>
''' This sample demonstrates the following:
''' 1. Creating an instance of the RunspaceInvoke class.
''' 2. Using this instance to invoke a PowerShell command.
''' 3. Using the output of RunspaceInvoke in a DataGridView
''' in a Windows Forms application
''' </remarks
Shared Sub Main(ByVal args() As String)
Runspace02.CreateForm()
End Sub 'Main

End Class 'Runspace02

End Namespace

Consulte también
Windows PowerShell SDK
Ejemplos de código Runspace03
Artículo • 26/09/2021

Estos son los ejemplos de código para el espacio de ejecución descritos en "Crear una
aplicación de consola que ejecuta un script especificado".

7 Nota

Puede descargar el archivo de código fuente de C# (runspace03.cs) y el archivo de


origen VB.NET (runspace03.vb) para este ejemplo mediante el Kit de desarrollo de
software de Microsoft Windows para Windows Vista y componentes en tiempo de
ejecución de Microsoft .NET Framework 3.0. Para obtener instrucciones de
descarga, consulte How to Install Windows PowerShell and Download the
Windows PowerShell SDK. Los archivos de origen descargados están disponibles
en el <PowerShell Samples> directorio .

Para obtener código de ejemplo completo, consulte los temas siguientes.

Lenguaje Tema

C# Ejemplo de código Runspace03 (C#)

VB.NET Ejemplo de código Runspace03 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace03 (C#)
Artículo • 26/09/2021

Este es el código fuente de C# para la aplicación de consola descrito en "Crear una


aplicación de consola que ejecuta un script especificado". En este ejemplo se usa la clase
System.Management.Automation.Runspaceinvoke para ejecutar un script que recupera
información del proceso mediante la lista de nombres de proceso pasados al script.
Muestra cómo pasar objetos de entrada a un script y cómo recuperar objetos de error,
así como los objetos de salida.

7 Nota

Puede descargar el archivo de código fuente de C# (runspace03.cs) para este


ejemplo mediante el Kit de desarrollo de software de Microsoft Windows para los
componentes en tiempo de ejecución de Windows Vista y Microsoft .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace03
{
/// <summary>
/// This sample uses the PowerShell class to execute
/// a script that retrieves process information for the
/// list of process names passed into the script.
/// It shows how to pass input objects to a script and
/// how to retrieve error objects as well as the output objects.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating an instance of the PowerSHell class.
/// 2. Using this instance to execute a string as a PowerShell
script.
/// 3. Passing input objects to the script from the calling program.
/// 4. Using PSObject to extract and display properties from the
objects
/// returned by this command.
/// 5. Retrieving and displaying error records that were generated
/// during the execution of that script.
/// </remarks>
private static void Main(string[] args)
{
// Define a list of processes to look for
string[] processNames = new string[]
{
"lsass", "nosuchprocess", "services", "nosuchprocess2"
};

// The script to run to get these processes. Input passed


// to the script will be available in the $input variable.
string script = "$input | get-process -name {$_}";

// Create an instance of the PowerShell class.


using (PowerShell powershell = PowerShell.Create())
{
powershell.AddScript(script);

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Now invoke the PowerShell and display the objects that


are
// returned...
foreach (PSObject result in powershell.Invoke(processNames))
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}

// Now process any error records that were generated while


running the script.
Console.WriteLine("\nThe following non-terminating errors
occurred:\n");
PSDataCollection<ErrorRecord> errors =
powershell.Streams.Error;
if (errors != null && errors.Count > 0)
{
foreach (ErrorRecord err in errors)
{
System.Console.WriteLine(" error: {0}",
err.ToString());
}
}
}

System.Console.WriteLine("\nHit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace03
(VB.NET)
Artículo • 26/09/2021

Este es el código VB.NET de la aplicación de consola que se describe en "Crear una


aplicación de consola que ejecuta un script especificado". En este ejemplo se usa la clase
System.Management.Automation.Runspaceinvoke para ejecutar un script que recupera
información del proceso para la lista de nombres de proceso pasados al script. Muestra
cómo pasar objetos de entrada a un script y cómo recuperar objetos de error, así como
los objetos de salida.

7 Nota

Puede descargar el archivo de código fuente VB.NET (runspace03.vb) para este


ejemplo mediante el Kit de desarrollo de software de Windows para los
componentes en tiempo de ejecución de Windows Vista y Microsoft .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
VB

Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Text
Imports Microsoft.VisualBasic
Imports System.Management.Automation
Imports System.Management.Automation.Host
Imports System.Management.Automation.Runspaces

Namespace Microsoft.Samples.PowerShell.Runspaces

Class Runspace03

''' <summary>
''' This sample uses the RunspaceInvoke class to execute
''' a script that retrieves process information for the
''' list of process names passed into the script.
''' It shows how to pass input objects to a script and
''' how to retrieve error objects as well as the output objects.
''' </summary>
''' <param name="args">Unused</param>
''' <remarks>
''' This sample demonstrates the following:
''' 1. Creating an instance of the RunspaceInvoke class.
''' 2. Using this instance to execute a string as a PowerShell
script.
''' 3. Passing input objects to the script from the calling program.
''' 4. Using PSObject to extract and display properties from the
objects
''' returned by this command.
''' 5. Retrieving and displaying error records that were generated
''' during the execution of that script.
''' </remarks>
Shared Sub Main(ByVal args() As String)
' Define a list of processes to look for
Dim processNames() As String = {"lsass", "nosuchprocess", _
"services", "nosuchprocess2"}

' The script to run to get these processes. Input passed


' to the script will be available in the $input variable.
Dim script As String = "$input | get-process -name {$_}"

' Create an instance of the RunspaceInvoke class.


Dim invoker As New RunspaceInvoke()

Console.WriteLine("Process HandleCount")
Console.WriteLine("--------------------------------")

' Now invoke the runspace and display the objects that are
' returned...
Dim errors As System.Collections.IList = Nothing
Dim result As PSObject
For Each result In invoker.Invoke(script, processNames, errors)
Console.WriteLine("{0,-20} {1}", _
result.Members("ProcessName").Value, _
result.Members("HandleCount").Value)
Next result

' Now process any error records that were generated while
' running the script.
Console.WriteLine(vbCrLf & _
"The following non-terminating errors occurred:" & vbCrLf)
If Not (errors Is Nothing) AndAlso errors.Count > 0 Then
Dim err As PSObject
For Each err In errors
System.Console.WriteLine(" error: {0}",
err.ToString())
Next err
End If
System.Console.WriteLine(vbCRLF & "Hit any key to exit...")
System.Console.ReadKey()

End Sub 'Main


End Class 'Runspace03

End Namespace

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplos de código Runspace04
Artículo • 26/09/2021

Este es un ejemplo de código para un espacio de ejecución que usa la clase


System.Management.Automation.Runspaceinvoke para ejecutar un script que genera un
error de terminación. La aplicación host es responsable de detectar el error e interpretar
el registro de errores.

7 Nota

Puede descargar el archivo de código fuente VB.NET (Runspace04.vb) para este


espacio de ejecución mediante el Kit de desarrollo de software de Windows para
los componentes en tiempo de ejecución de Windows Vista y Microsoft .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK. Los archivos
de origen descargados están disponibles en el <PowerShell Samples> directorio .

Para obtener código de ejemplo completo, vea los temas siguientes.

Lenguaje Tema

VB.NET Ejemplo de código Runspace04 (VB.NET)

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace04
(VB.NET)
Artículo • 26/09/2021

Este es el código VB.NET del ejemplo Runspace04. En este ejemplo se usa la clase
System.Management.Automation.Runspaceinvoke para ejecutar un script que genera un
error de terminación. La aplicación host es responsable de detectar el error e interpretar
el registro de errores.

7 Nota

Puede descargar el archivo de código fuente VB.NET (runspace02.vb) para este


ejemplo mediante el Kit de desarrollo de software de Windows para los
componentes en tiempo de ejecución de Windows Vista y Microsoft .NET
Framework 3.0. Para obtener instrucciones de descarga, consulte How to Install
Windows PowerShell and Download the Windows PowerShell SDK.

Los archivos de origen descargados están disponibles en el <PowerShell Samples>


directorio .

Ejemplo de código
VB

Imports System
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.Text
Imports Microsoft.VisualBasic
Imports System.Management.Automation
Imports System.Management.Automation.Host
Imports System.Management.Automation.Runspaces

Namespace Microsoft.Samples.PowerShell.Runspaces

Class Runspace04

''' <summary>
''' This sample uses the RunspaceInvoke class to execute
''' a script. This script will generate a terminating
''' exception that the caller should catch and process.
''' </summary>
''' <param name="args">Unused</param>
''' <remarks>
''' This sample demonstrates the following:
''' 1. Creating an instance of the RunspaceInvoke class.
''' 2. Using this instance to execute a string as a PowerShell
script.
''' 3. Passing input objects to the script from the calling program.
''' 4. Using PSObject to extract and display properties from the
objects
''' returned by this command.
''' 5. Retrieving and displaying error records that may be generated
''' during the execution of that script.
''' 6. Catching and displaying terminating exceptions generated
''' by the script being run.
''' </remarks>
Shared Sub Main(ByVal args() As String)
' Define a list of patterns to use in matching
' Note that the fourth pattern is not a valid regular
' expression so it will cause a terminating exception to
' be thrown when used in select-string.
Dim patterns() As String = {"aa", "bc", "ab*c", "*", "abc"}

' The script to run to use the patterns. Input passed


' to the script will be available in the $input variable.
Dim script As String = "$input | where {" & _
" select-string $_ -inputobject 'abc' }"

' Create an instance of the RunspaceInvoke class.


Dim invoker As New RunspaceInvoke()

' Invoke the runspace. Because of the bad regular expression,


' no objects will be returned. Instead, an exception will be
' thrown.
Try
Dim errors As System.Collections.IList = Nothing
Dim result As PSObject
For Each result In invoker.Invoke(script, patterns, errors)
Console.WriteLine("'{0}'", result.ToString())
Next result

' Now process any error records that were generated


' while running the script.
Console.WriteLine(vbCrLf & _
"The following non-terminating errors occurred:" &
vbCrLf)
If Not (errors Is Nothing) AndAlso errors.Count > 0 Then
Dim err As PSObject
For Each err In errors
System.Console.WriteLine(" error: {0}",
err.ToString())
Next err
End If
Catch runtimeException As RuntimeException
' Trap any exception generated by the script. These
exceptions
' will all be derived from RuntimeException.
System.Console.WriteLine("Runtime exception: {0}: {1}" & _
vbCrLf + "{2}", _

runtimeException.ErrorRecord.InvocationInfo.InvocationName, _
runtimeException.Message, _

runtimeException.ErrorRecord.InvocationInfo.PositionMessage)
End Try

System.Console.WriteLine(vbCrLf + "Hit any key to exit...")


System.Console.ReadKey()

End Sub 'Main


End Class 'Runspace04

End Namespace

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace05
Artículo • 24/09/2021

Este es el código fuente del ejemplo Runspace05 que se describe en Configuración de


un espacio de ejecución mediante RunspaceConfiguration . En este ejemplo se
muestra cómo crear la información de configuración del espacio de ejecución, crear un
espacio de ejecución, crear una canalización con un solo comando y, a continuación,
ejecutar la canalización. El comando que se ejecuta es el Get-Process cmdlet .

7 Nota

Puede descargar el archivo de código fuente de C# (runspace05.cs) mediante el Kit


de desarrollo de software de Microsoft Windows para los componentes en tiempo
de ejecución de Windows Vista y Microsoft .NET Framework 3.0. Para obtener
instrucciones de descarga, consulte How to Install Windows PowerShell and
Download the Windows PowerShell SDK. Los archivos de origen descargados
están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace05
{
/// <summary>
/// This sample uses an initial session state to create a runspace. The
sample
/// invokes a command from a PowerShell snap-in present in the console
file.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample assumes that user has the GetProcessSample01.dll that is
produced
/// by the GetProcessSample01 sample copied to the current directory.
/// This sample demonstrates the following:
/// 1. Creating a default initial session state.
/// 2. Creating a runspace using the default initial session state.
/// 3. Creating a PowerShell object that uses the runspace.
/// 4. Adding the get-proc cmdlet to the PowerShell object from a
/// snap-in.
/// 5. Using PSObject objects to extract and display properties from
/// the objects returned by the cmdlet.
/// </remarks>
private static void Main(string[] args)
{
// Create the default initial session state. The default initial
// session state contains all the elements provided by Windows
PowerShell.
InitialSessionState iss = InitialSessionState.CreateDefault();
PSSnapInException warning;
iss.ImportPSSnapIn("GetProcPSSnapIn01", out warning);

// Create a runspace. Notice that no PSHost object is supplied to the


// CreateRunspace method so the default host is used. See the Host
// samples for more information on creating your own custom host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss))
{
myRunSpace.Open();

// Create a PowerShell object.


using (PowerShell powershell = PowerShell.Create())
{
// Add the Cmdlet and specify the runspace.
powershell.AddCommand("GetProcPSSnapIn01\\get-proc");
powershell.Runspace = myRunSpace;

// Run the cmdlet synchronously.


Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the results.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

// Close the runspace to release any resources.


myRunSpace.Close();
}
System.Console.WriteLine("Hit any key to exit...");
System.Console.ReadKey();
}
}
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace06
Artículo • 26/09/2021

Este es el código fuente del ejemplo Runspace06 descrito en Configuring a Runspace


Using a Windows PowerShell Snap-in . Esta aplicación de ejemplo crea un espacio de
ejecución basado en un complemento Windows PowerShell, que luego se usa para
ejecutar una canalización con un solo comando. Para ello, la aplicación crea la
información de configuración del espacio de ejecución, crea un espacio de ejecución,
crea una canalización con un solo comando y, a continuación, ejecuta la canalización.

7 Nota

Puede descargar el archivo de código fuente de C# (runspace06.cs) mediante el Kit


de desarrollo de software de Windows para los componentes en tiempo de
ejecución de Windows Vista y Microsoft .NET Framework 3.0. Para obtener
instrucciones de descarga, consulte How to Install Windows PowerShell and
Download the Windows PowerShell SDK. Los archivos de origen descargados
están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace06
{
/// <summary>
/// This sample uses an initial session state to create a runspace.
/// The sample invokes a command from binary module that is loaded by
the
/// initial session state.
/// </summary>
/// <param name="args">Parameter not used.</param>
/// <remarks>
/// This sample assumes that user has the GetProcessSample02.dll that is
/// produced by the GetProcessSample02 sample copied to the current
directory.
/// This sample demonstrates the following:
/// 1. Creating a default initial session state.
/// 2. Creating a runspace using the initial session state.
/// 3. Creating a PowerShell object that uses the runspace.
/// 4. Adding the get-proc cmdlet to the PowerShell object from a
/// module.
/// 5. Using PSObject objects to extract and display properties from
/// the objects returned by the cmdlet.
/// </remarks>
private static void Main(string[] args)
{
// Create an initial session state.
InitialSessionState iss = InitialSessionState.CreateDefault();
iss.ImportPSModule(new string[] { @".\GetProcessSample02.dll" });

// Create a runspace. Notice that no PSHost object is supplied to the


// CreateRunspace method so the default host is used. See the Host
// samples for more information on creating your own custom host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss))
{
myRunSpace.Open();

// Create a PowerShell object.


using (PowerShell powershell = PowerShell.Create())
{
// Add the cmdlet and specify the runspace.
powershell.AddCommand(@"GetProcessSample02\get-proc");
powershell.Runspace = myRunSpace;

Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the results.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

// Close the runspace to release any resources.


myRunSpace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace07
Artículo • 24/09/2021

Este es el código fuente del ejemplo Runspace07 que se describe en Creación de una
aplicación de consola que agrega comandos a una canalización . Esta aplicación de
ejemplo crea un espacio de ejecución, crea una canalización, agrega dos comandos a la
canalización y, a continuación, ejecuta la canalización. Los comandos agregados a la
canalización son los Get-Process Measure-Object cmdlets y .

7 Nota

Puede descargar el archivo de código fuente de C# (runspace07.cs) mediante el Kit


de desarrollo de software de Microsoft Windows para los componentes en tiempo
de ejecución de Windows Vista y Microsoft .NET Framework 3.0. Para obtener
instrucciones de descarga, consulte How to Install Windows PowerShell and
Download the Windows PowerShell SDK. Los archivos de origen descargados
están disponibles en el <PowerShell Samples> directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace07
{
/// <summary>
/// This sample shows how to create a runspace and how to run
/// commands using a PowerShell object. It builds a pipeline
/// that runs the get-process cmdlet, which is piped to the measure-
object
/// cmdlet to count the number of processes running on the system.
/// </summary>
/// <param name="args">Parameter is not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a runspace using the RunspaceFactory class.
/// 2. Creating a PowerShell object
/// 3. Adding individual cmdlets to the PowerShell object.
/// 4. Running the cmdlets synchronously.
/// 5. Working with PSObject objects to extract properties
/// from the objects returned by the cmdlets.
/// </remarks>
private static void Main(string[] args)
{
Collection<PSObject> result; // Will hold the result
// of running the cmdlets.

// Create a runspace. We can not use the RunspaceInvoke class


// because we need to get at the underlying runspace to
// explicitly add the commands. Notice that no PSHost object is
// supplied to the CreateRunspace method so the default host is
// used. See the Host samples for more information on creating
// your own custom host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace())
{
myRunSpace.Open();

// Create a PowerShell object and specify the runspace.


PowerShell powershell = PowerShell.Create();
powershell.Runspace = myRunSpace;

// Use the using statement so we dispose of the PowerShell object


// when we're done.
using (powershell)
{
// Add the get-process cmdlet to the PowerShell object. Notice
// we are specify the name of the cmdlet, not a script.
powershell.AddCommand("get-process");

// Add the measure-object cmdlet to count the number


// of objects being returned. Commands are always added to the end
// of the pipeline.
powershell.AddCommand("measure-object");

// Run the cmdlets synchronously and save the objects returned.


result = powershell.Invoke();
}

// Even after disposing of the pipeLine, we still need to set


// the powershell variable to null so that the garbage collector
// can clean it up.
powershell = null;

// Display the results of running the commands (checking that


// everything is ok first.
if (result == null || result.Count != 1)
{
throw new InvalidOperationException(
"pipeline.Invoke() returned the wrong number of
objects");
}

PSMemberInfo count = result[0].Properties["Count"];


if (count == null)
{
throw new InvalidOperationException(
"The object returned doesn't have a 'count' property");
}

Console.WriteLine(
"Runspace07: The get-process cmdlet returned {0}
objects",
count.Value);

// Close the runspace to release any resources.


myRunSpace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Ejemplo de código Runspace08
Artículo • 27/09/2021

Este es el código fuente del ejemplo Runspace08 descrito en Creación de una aplicación
de consola que agrega parámetros a un comando . Esta aplicación de ejemplo crea un
espacio de ejecución, crea una canalización, agrega dos comandos a la canalización,
agrega dos parámetros al segundo comando y, a continuación, ejecuta la canalización.
Los comandos que se agregan a la canalización son los Get-Process Sort-Object
cmdlets y .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace08
{
/// <summary>
/// This sample shows how to use a PowerShell object to run commands.
The
/// PowerShell object builds a pipeline that include the get-process
cmdlet,
/// which is then piped to the sort-object cmdlet. Parameters are added
to the
/// sort-object cmdlet to sort the HandleCount property in descending
order.
/// </summary>
/// <param name="args">Parameter is not used.</param>
/// <remarks>
/// This sample demonstrates:
/// 1. Creating a PowerShell object
/// 2. Adding individual commands to the PowerShell object.
/// 3. Adding parameters to the commands.
/// 4. Running the pipeline of the PowerShell object synchronously.
/// 5. Working with PSObject objects to extract properties
/// from the objects returned by the commands.
/// </remarks>
private static void Main(string[] args)
{
Collection<PSObject> results; // Holds the result of the pipeline
execution.

// Create the PowerShell object. Notice that no runspace is specified


so a
// new default runspace is used.
PowerShell powershell = PowerShell.Create();

// Use the using statement so that we can dispose of the PowerShell


object
// when we are done.
using (powershell)
{
// Add the get-process cmdlet to the pipeline of the PowerShell
object.
powershell.AddCommand("get-process");

// Add the sort-object cmdlet and its parameters to the pipeline of


// the PowerShell object so that we can sort the HandleCount
property
// in descending order.
powershell.AddCommand("sort-
object").AddParameter("descending").AddParameter("property", "handlecount");

// Run the pipeline of the Powerhell object synchronously.


results = powershell.Invoke();
}

// Even after disposing of the PowerShell object, we still


// need to set the powershell variable to null so that the
// garbage collector can clean it up.
powershell = null;

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the results returned by the commands.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}
Consulte también
Windows PowerShell SDK
Ejemplo de código Runspace09
Artículo • 24/09/2021

Esta aplicación de ejemplo crea y abre un espacio de ejecución, crea e invoca de forma
asincrónica una canalización y, a continuación, usa eventos de canalización para
procesar el script de forma asincrónica. El script que ejecuta esta aplicación crea los
enteros de 1 a 10 en intervalos de 0,5 segundos (500 ms).

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace09
{
/// <summary>
/// This sample shows how to use a PowerShell object to run a
/// script that generates the numbers from 1 to 10 with delays
/// between each number. The pipeline of the PowerShell object
/// is run asynchronously and events are used to handle the output.
/// </summary>
/// <param name="args">This parameter is not used.</param>
/// <remarks>
/// This sample demonstrates the following:
/// 1. Creating a PowerShell object.
/// 2. Adding a script to the pipeline of the PowerShell object.
/// 3. Using the BeginInvoke method to run the pipeline asynchronosly.
/// 4. Using the events of the PowerShell object to process the
/// output of the script.
/// 5. Using the PowerShell.Stop() method to interrupt an executing
pipeline.
/// </remarks>
private static void Main(string[] args)
{
Console.WriteLine("Print the numbers from 1 to 10. Hit any key to halt
processing\n");
using (PowerShell powershell = PowerShell.Create())
{
// Add a script to the PowerShell object. The script generates the
// numbers from 1 to 10 in half second intervals.
powershell.AddScript("1..10 | foreach {$_ ; start-sleep -milli
500}");

// Add the event handlers. If we did not care about hooking the
DataAdded
// event, we would let BeginInvoke create the output stream for us.
PSDataCollection<PSObject> output = new PSDataCollection<PSObject>
();
output.DataAdded += new EventHandler<DataAddedEventArgs>
(Output_DataAdded);
powershell.InvocationStateChanged += new
EventHandler<PSInvocationStateChangedEventArgs>
(Powershell_InvocationStateChanged);

// Invoke the pipeline asynchronously.


IAsyncResult asyncResult = powershell.BeginInvoke<PSObject,
PSObject>(null, output);

// Wait for things to happen. If the user hits a key before the
// script has completed, then call the PowerShell Stop() method
// to halt processing.
Console.ReadKey();
if (powershell.InvocationStateInfo.State !=
PSInvocationState.Completed)
{
// Stop the execution of the pipeline.
Console.WriteLine("\nStopping the pipeline!\n");
powershell.Stop();

// Wait for the Windows PowerShell state change messages to be


displayed.
System.Threading.Thread.Sleep(500);
Console.WriteLine("\nPress a key to exit");
Console.ReadKey();
}
}
}

/// <summary>
/// The output data added event handler. This event is called when
/// data is added to the output pipe. It reads the data that is
/// available and displays it on the console.
/// </summary>
/// <param name="sender">The output pipe this event is associated with.
</param>
/// <param name="e">Parameter is not used.</param>
private static void Output_DataAdded(object sender, DataAddedEventArgs
e)
{
PSDataCollection<PSObject> myp = (PSDataCollection<PSObject>)sender;
Collection<PSObject> results = myp.ReadAll();
foreach (PSObject result in results)
{
Console.WriteLine(result.ToString());
}
}

/// <summary>
/// This event handler is called when the pipeline state is changed.
/// If the state change is to Completed, the handler issues a message
/// asking the user to exit the program.
/// </summary>
/// <param name="sender">This parameter is not used.</param>
/// <param name="e">The PowerShell state information.</param>
private static void Powershell_InvocationStateChanged(object sender,
PSInvocationStateChangedEventArgs e)
{
Console.WriteLine("PowerShell object state changed: state: {0}\n",
e.InvocationStateInfo.State);
if (e.InvocationStateInfo.State == PSInvocationState.Completed)
{
Console.WriteLine("Processing completed, press a key to exit!");
}
}
}
}

Consulte también
Windows PowerShell SDK
Ejemplo de código Runspace10
Artículo • 27/09/2021

Este es el código fuente del ejemplo Runspace10. Esta aplicación de ejemplo agrega un
cmdlet a System.Management.Automation.Runspaces.Runspaceconfiguration y, a
continuación, usa la información de configuración modificada para crear el espacio de
ejecución.

7 Nota

Puede descargar el archivo de código fuente de C# (runspace10.cs) mediante el Kit


de desarrollo de software de Windows para Windows Vista y Componentes en
tiempo de ejecución de Microsoft .NET Framework 3.0. Para obtener instrucciones
de descarga, consulte How to Install Windows PowerShell and Download the
Windows PowerShell SDK. Los archivos de origen descargados están disponibles
en el <PowerShell Samples> directorio .

Ejemplo de código
C#

namespace Microsoft.Samples.PowerShell.Runspaces
{
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using PowerShell = System.Management.Automation.PowerShell;

#region GetProcCommand

/// <summary>
/// Class that implements the GetProcCommand.
/// </summary>
[Cmdlet(VerbsCommon.Get, "Proc")]
public class GetProcCommand : Cmdlet
{
#region Cmdlet Overrides

/// <summary>
/// For each of the requested process names, retrieve and write
/// the associated processes.
/// </summary>
protected override void ProcessRecord()
{
// Get the current processes.
Process[] processes = Process.GetProcesses();

// Write the processes to the pipeline making them available


// to the next cmdlet. The second argument (true) tells the
// system to enumerate the array, and send one process object
// at a time to the pipeline.
WriteObject(processes, true);
}

#endregion Overrides
} // End GetProcCommand class.

#endregion GetProcCommand

/// <summary>
/// This class contains the Main entry point for this host application.
/// </summary>
internal class Runspace10
{
/// <summary>
/// This sample shows how to add a cmdlet to an InitialSessionState
object and then
/// uses the modified InitialSessionState object when creating a
Runspace object.
/// </summary>
/// <param name="args">Parameter is not used.</param>
/// This sample demonstrates:
/// 1. Creating an InitialSessionState object.
/// 2. Adding a cmdlet to the InitialSessionState object.
/// 3. Creating a runspace that uses the InitialSessionState object.
/// 4. Craeting a PowerShell object tht uses the Runspace object.
/// 5. Running the pipeline of the PowerShell object synchronously.
/// 6. Working with PSObject objects to extract properties
/// from the objects returned by the pipeline.
private static void Main(string[] args)
{
// Create a default InitialSessionState object. The default
// InitialSessionState object contains all the elements provided
// by Windows PowerShell.
InitialSessionState iss = InitialSessionState.CreateDefault();

// Add the get-proc cmdlet to the InitialSessionState object.


SessionStateCmdletEntry ssce = new SessionStateCmdletEntry("get-proc",
typeof(GetProcCommand), null);
iss.Commands.Add(ssce);

// Create a Runspace object that uses the InitialSessionState object.


// Notice that no PSHost object is specified, so the default host is
used.
// See the Hosting samples for information on creating your own custom
host.
using (Runspace myRunSpace = RunspaceFactory.CreateRunspace(iss))
{
myRunSpace.Open();

using (PowerShell powershell = PowerShell.Create())


{
powershell.Runspace = myRunSpace;

// Add the get-proc cmdlet to the pipeline of the PowerShell


object.
powershell.AddCommand("get-proc");

Collection<PSObject> results = powershell.Invoke();

Console.WriteLine("Process HandleCount");
Console.WriteLine("--------------------------------");

// Display the output of the pipeline.


foreach (PSObject result in results)
{
Console.WriteLine(
"{0,-20} {1}",
result.Members["ProcessName"].Value,
result.Members["HandleCount"].Value);
}
}

// Close the runspace to release resources.


myRunSpace.Close();
}

System.Console.WriteLine("Hit any key to exit...");


System.Console.ReadKey();
}
}
}

Consulte también
Guía del programador de Windows PowerShell

Windows PowerShell SDK


Contribución a la documentación de
PowerShell
Artículo • 01/03/2022

Gracias por su apoyo a PowerShell.

La Guía del colaborador es una colección de artículos que describen las herramientas y
los procesos que usamos para crear documentación en Microsoft. Algunas de estas
guías cubren información que es común a cualquier conjunto de documentación
publicado en docs.microsoft.com . Otras son específicas de los procedimientos para
escribir la documentación de PowerShell.

Los artículos comunes están disponibles en la guía del colaborador centralizada. Las
guías específicas de PowerShell están disponibles aquí.

Formas de colaborar
Hay dos maneras de contribuir. Ambas son valiosas para nosotros.

La presentación de incidencias nos ayuda a identificar problemas y deficiencias en


nuestra documentación. A veces, las incidencias son difíciles de resolver, lo que
requiere una investigación más a fondo. El proceso de las incidencias nos permite
tener una conversación sobre los problemas y desarrollar una solución
satisfactoria.

El envío de una solicitud de extracción para agregar o cambiar contenido es un


proceso más implicado. En la siguiente información se describen las herramientas,
los procesos y los estándares para enviar contenido a la documentación.

Preparación para realizar una contribución


La colaboración con la documentación requiere una cuenta de GitHub. Use la siguiente
lista de comprobación para instalar y configurar las herramientas que necesita para
realizar contribuciones.

1. Registrarse en GitHub
2. Instalar las herramientas de Git y Markdown
3. Instalar el paquete de creación de documentos
4. Instalar Posh-Git (aunque no es necesario, se recomienda)
5. Configurar un repositorio de Git local
6. Revisar los aspectos básicos de Git y GitHub

Introducción a la escritura en Docs


Hay dos maneras de contribuir a los cambios en la documentación:

1. Ediciones rápidas en los documentos existentes

Correcciones menores, corrección de errores tipográficos o pequeñas


adiciones

2. Flujo de trabajo completo de GitHub para los documentos

Cambios mayores, varias versiones, agregar o cambiar imágenes o contribuir


a nuevos artículos

Además, lea la sección Aspectos fundamentales de escritura de la guía del colaborador


centralizada. Otro recurso excelente es la guía de estilo de escritura de Microsoft. El
objetivo de esta guía es ayudar a los editores, escritores técnicos, desarrolladores,
vendedores y cualquier persona de TI a escribir contenido mejor.

Las correcciones menores o aclaraciones realizadas a la documentación y los ejemplos


de código de los repositorios públicos se rigen por las Condiciones de uso.

Use el flujo de trabajo completo de GitHub cuando vaya a realizar cambios importantes.
Si no es empleado de Microsoft, los cambios importantes generan un comentario en la
solicitud de incorporación de cambios que le pide que envíe un contrato de licencia de
colaboración (CLA) en línea. Es necesario que cumplimente el formulario en línea para
revisar o aceptar su solicitud de incorporación de cambios.

Código de conducta
Todos los repositorios que publican en docs.microsoft.com han adoptado el código de
conducta de código abierto de Microsoft o el código de conducta de .NET
Foundation . Para más información, consulte las preguntas frecuentes sobre el código
de conducta .

Pasos siguientes
En los artículos siguientes se trata información específica de la documentación de
PowerShell. En aquellos casos en que se solape con las instrucciones de la guía del
colaborador centralizada, se indicará cómo difieren esas reglas en el contenido de
PowerShell.

Consulte los documentos siguientes:

Registrar una incidencia


Introducción a la escritura de documentos
Envío de una solicitud de incorporación de cambios
Guía de estilo de PowerShell-Docs

Recursos adicionales

Lista de comprobación editorial


Administración de incidencias
Administración de solicitudes de incorporación de cambios
Comenzar contribuir a la
documentación de PowerShell
Artículo • 05/05/2022

En este artículo se ofrece información general sobre cómo empezar a trabajar como
colaborador en la documentación de PowerShell.

estructura de PowerShell-Docs
El repositorio PowerShell-Docs se divide en dos grupos de contenido: referencia y
conceptual.

Contenido de referencia
El contenido de referencia es la referencia del cmdlet de PowerShell para los cmdlets
que se incluyen en PowerShell. La referencia se recopila en carpetas de versiones (5.1,
7.0, 7.1 y 7.2). Este contenido contiene solo referencia de cmdlet para los módulos que
se incluyen con PowerShell. Este contenido también se usa para crear la información de
ayuda que muestra el Get-Help cmdlet .

Contenido conceptual
La documentación conceptual incluye el siguiente contenido:

Notas de la versión
Instrucciones de instalación
Ejemplos de scripts y artículos de procedimientos
Documentación de DSC
Documentación del SDK

La documentación conceptual no está organizada por versión. Todos los artículos se


muestran para cada versión de PowerShell. Estamos trabajando para crear artículos
específicos de la versión.

7 Nota

Cada vez que se agregue, quite o cambie el nombre de un artículo conceptual, el


TOC se debe actualizar e incluir en la solicitud de incorporación de cambios.
Creación de nuevos artículos
Se debe crear un GitHub problema para cualquier documento nuevo que desee
contribuir. Compruebe si hay problemas existentes para asegurarse de que no está
duplicando los esfuerzos. Los problemas asignados se consideran in progress como . Si
desea colaborar en un problema, póngase en contacto con la persona asignada al
problema.

De forma similar al proceso rfC de PowerShell, cree un problema antes de escribir el


contenido. El problema garantiza que no pierda tiempo ni esfuerzo en el trabajo que el
equipo de PowerShell-Docs rechace. El problema nos permite consultarle en el ámbito
del contenido y dónde cabe en la documentación de PowerShell. Todos los artículos
deben incluirse en la Tabla de contenido (TOC). La ubicación propuesta de la TCI debe
incluirse en la discusión del problema.

7 Nota

El sistema de publicación genera automáticamente el TOC para el contenido de


referencia. No es necesario actualizar el TC.

Actualización de artículos existentes


Si procede, los artículos de referencia de cmdlet se duplican en todas las versiones de
PowerShell mantenidas en este repositorio. Al notificar un problema sobre una
referencia de cmdlet o un About_ artículo, debe especificar qué versiones se ven
afectadas por el problema. La plantilla de problema de GitHub incluye una lista de
comprobación de las versiones. Use las casillas para especificar qué versiones del
contenido se ven afectadas.

Compruebe toda la versión del artículo para ver si se necesita el mismo cambio en las
otras versiones. Aplique el cambio adecuado a cada versión del archivo.

Contenido localizado
La documentación de PowerShell se escribe en inglés y se traduce a 17 otros idiomas. El
contenido en inglés se almacena en el repositorio GitHub denominado
MicrosoftDocs/PowerShell-Docs . El contenido localizado se almacena en un repositorio
independiente para cada idioma. Los repositorios usan el mismo nombre base, pero
agregan el nombre de configuración regional al final. Por ejemplo,
MicrosoftDocs/PowerShell-Docs.de-de contiene el contenido traducido al alemán.
En general, los problemas y los cambios deben enviarse al repositorio en inglés. Todas
las traducciones comienzan primero desde el contenido en inglés. Usamos tanto la
traducción humana como la traducción automática.

Método de traducción Idiomas

Traducción humana de-DE, es-ES, fr-FR, it-IT, ja-JP, ko-KR, pt-BR, ru-RU, zh-CN, zh-TW

Traducción automática cs-CZ, hu-HU, nl-NL, pl-PL, pt-PT, sv-SE, tr-TR

Es posible que el contenido traducido por traducción automática no siempre resulte en


la gramática y las opciones de palabra correctas. Si encuentra un error en la traducción
de cualquier idioma, en lugar de en los detalles técnicos del artículo, abra un problema
en el repositorio localizado. Explique por qué cree que la traducción es incorrecta.
Nuestro equipo de localización revisa y responde a estos problemas.

Pasos siguientes
Hay dos formas comunes de enviar cambios en GitHub. Ambos métodos se describen
en la Guía central del colaborador:

1. Puede realizar modificaciones rápidas en los documentos existentes en la interfaz


web de GitHub.
2. Use el flujo de trabajo completo de GitHub para agregar nuevos artículos,
actualizar varios archivos u otros cambios grandes.

Antes de iniciar los cambios, debe crear una bifurcación del repositorio de PowerShell-
Docs. Los cambios se deben realizar en una rama de trabajo en la copia de PowerShell-
Docs. Si usa el método de edición rápida en GitHub, estos pasos se controlan por usted.
Si usa el flujo de trabajo completo de GitHub, debe estar configurado para que
funcione localmente.

Ambos métodos terminan con la creación de una solicitud de incorporación de cambios


(PR). Consulte Envío de una solicitud de incorporación de cambios para obtener más
información y procedimientos recomendados.
Contribute using GitHub Codespaces
Article • 05/17/2023

GitHub has a feature called Codespaces that you can use to contribute to the
PowerShell documentation without having to install or configure any software locally.
When you use a codespace, you get the same authoring tools the team uses for writing
and editing.

You can use a codespace in your browser, making your contributions in VS Code hosted
over the internet. If you have VS Code installed locally, you can connect to the
codespace there too.

Available tools
When you use a codespace to contribute to the PowerShell documentation, your editor
has these tools already available for you:

Markdownlint for checking your Markdown syntax.


cSpell for checking your spelling.
Vale for checking your prose.
The Learn Authoring Pack for inserting platform-specific syntax, previewing your
contribution, and more.
The Reflow Markdown extension for wrapping your Markdown as needed,
making reading and editing easier.
The Table Formatter extension for making your tables more readable without
having to manually align columns.
The change-case extension for converting the casing of your headings and
prose.
The GitLens extension for reviewing historical file changes.
The PowerShell extension for interacting authoring PowerShell examples.
The Gremlins tracker for Visual Studio Code for finding problematic characters in
your Markdown.

Cost
GitHub Codespaces can be used for free up to 120 core-hours per month. With the
configuration we recommend in this article, that means up to 60 hours of free usage per
month. The monthly usage is calculated across all your repositories, not just
documentation.
For more information about pricing, see About billing for GitHub Codespaces .

 Tip

If you're comfortable using containers and Docker, you can get the same
experience as using GitHub Codespaces in VS Code by using the devcontainer
defined for the PowerShell documentation repositories. There's no cost associated
with using devcontainers. For more information, see the Dev Containers tutorial .

Creating your GitHub Codespace


To create your GitHub Codespace for contributing to PowerShell documentation, follow
these steps:

1. Open https://github.com/codespaces in your browser.


2. Select the "New codespace" button in the top right of the page.
3. In the "Create a new codespace" page, select the "Select a repository" button and
type the name of the repository you want to contribute to, like
MicrosoftDocs/PowerShell-Docs .
4. Leave all other settings as their default.
5. Select the "Create codespace" button.

After following these steps, GitHub creates a new codespace for that repository and sets
it up for you. When the codespace is ready, the page refreshes and shows the web
editor UI for the codespace. The UI is based on VS Code and works the same way.

Opening your GitHub Codespace


To open your GitHub Codespace in the browser, follow these steps:

1. Open https://github.com/codespaces in your browser.


2. The page lists your codespaces. Find the created codespace for the repository you
want to contribute to and select it.

After you select your codespace, GitHub opens it in the same window. From here, you're
ready to contribute.

To open your GitHub Codespace in VS Code, follow the steps in Using GitHub
Codespaces in Visual Studio Code .
Authoring in your GitHub Codespace
Once you have your GitHub Codespace open in your browser or VS Code, contributing
to the documentation follows the same process.

The rest of this article describes a selection of tasks you can do in your GitHub
Codespace while writing or editing your contribution.

Extract a reference link


When you want to turn an inline link, like [some text](destination.md) , into a reference
link like [some text][01] , select the link destination in the editor. Then you can either:

1. Right click on the link destination and select "Refactor..." in the context menu.
2. Press Ctrl + Shift + R .

Either action raises the refactoring context menu. Select "Extract to link definition" in the
context menu. This replaces the (destination.md) in the link with [def] . You can
rename the definition by typing a name in.

For the PowerShell documentation, we use two-digit numerical reference link definitions,
like [01] or [31] . Only use reference link definitions in about topics and conceptual
documentation. Don't use reference link definitions in cmdlet reference documentation.

Fix prose style violations


When you review an article in your codespace, Vale automatically checks the article
when you first open it and every time you save it. If Vale finds any style violations, it
highlights them in the document with colored squiggles.

Hover over a violation to see more information about it.

Select the rule's name in the hover information to open a web page that explains the
rule. Select the rule's filename (ending in .yml ) to open the rule and review its
implementation.

If the rule supports a quick fix, you can select "Quick Fix..." in the hover information for
the violation and apply one of the suggested fixes by selecting it from the context
menu. You can also press Ctrl + . when your cursor is on a highlighted problem to
apply a quick fix if the rule supports it.

If the rule doesn't support quick fixes, read the rule's message and fix it if you can. If
you're not sure how to fix it, the editors can make a suggestion when reviewing your PR.
Fix syntax problems
When you review an article in your codespace, Markdownlint automatically checks the
article when you open it and as you type. If Markdownlint finds any syntax problems, it
highlights them in the document with colored squiggles.

Hover over a violation to see more information about it.

Select the rule's ID in the hover information to open a web page that explains the rule.

If the rule supports a quick fix, you can select "Quick Fix..." in the hover information for
the violation and apply one of the suggested fixes by selecting it from the context
menu. You can also press Ctrl + . when your cursor is on a highlighted problem to
apply a quick fix if the rule supports it.

If the rule doesn't support quick fixes, read the rule's message and fix it if you can. If
you're not sure how to fix it, the editors can make a suggestion when reviewing your PR.

You can also apply fixes to all syntax violations in an article. To do so, open the
command palette and type Fix all supported markdownlint violations in the
document . As you type, the command palette filters the available commands. Select the
"Fix all supported markdownlint violations in the document" command. When you do,
Markdownlint updates the document to resolve any violations it has a quick fix for.

Format a table
To format a Markdown table, place your cursor in or on the table in your Markdown.
Open the Command Palette and search for the Table: Format Current command. When
you select that command, it updates the Markdown for your table to align and pad the
table for improved readability.

It converts a table defined like this:

markdown

| foo | bar | baz |


|:--:|:--|-:|
| a | b | c |

Into this:

markdown
| foo | bar | baz |
| :---: | :--- | ---: |
| a | b | c |

Insert an alert
The documentation uses alerts to make information more notable to a reader.

To insert an alert, you can, open the Command Palette and search for the Learn: Alert
command. When you select that command, it opens a context menu. Select the alert
type you want to add. When you do, the command inserts the alert's Markdown at your
cursor in the document.

Make a heading use sentence casing


To convert a heading's casing, highlight the heading's text except for the leading #
symbols, which set the heading level. When you have the text highlighted, open the
Command Palette and search for the Change case sentence command. When you select
that command, it converts the casing of the highlighted text.

You can also use the casing commands for any text in the document.

Open the Command Palette


You can use VS Code's Command Palette to run many helpful commands.

To open the Command Palette in the UI, select "View" in the top menu bar. Then select
"Command Palette..." in the context menu.

To open the Command Palette with your keyboard, press the key combination for your
operating system:

Windows and Linux: Ctrl + Shift + P

macOS: Cmd + Shift + P

Preview your contribution


To preview your contribution, open the Command Palette and search for the Markdown:
Open Preview command. When you select that command, VS Code opens a preview of

the active document. The preview's style matches the Learn platform.
7 Note

Site-relative and cross-reference links won't work in the preview.

Reflow your content


To limit the line lengths for a paragraph in a document, place your cursor on the
paragraph. Then open the Command Palette and search for the Reflow Markdown
command. When you select the command, it updates the current paragraph's line
lengths to the configured length. For our repositories, that length is 99 characters.

When using this command for block quotes, make sure the paragraph in the block
quote you're reflowing is surrounded by blank lines. Otherwise, the command reflows
every paragraph together.

U Caution

Don't use this command when editing about topics. The lines in those documents
must not be longer than 80 characters. There's currently no way for a repository to
configure different line lengths by folder or filename, so reflow doesn't work for
about topic documents.

Review all problems in a document


To review all syntax and style rule violations in a document, open the Problems View.

To open the Problems View in the UI, select "View" in the top menu bar. Then select
"Problems" in the context menu.

To open the Problems View with your keyboard, press the key combination for your
operating system:

Windows and Linux: Ctrl + Shift + M

macOS: Cmd + Shift + M

The Problems View displays all errors, warnings, and suggestions for the open
document. Select a problem to scroll to it in the document.

You can filter the problems by type or text matching.

Updating the ms.date metadata


To update the ms.date metadata for an article, open the Command Palette and search
for the Learn: Update "ms.date" Metadata Value command. When you select the
command, it updates the metadata to the current date.

Additional resources
The tasks and commands described in this article don't cover everything you can do
with VS Code or the installed extensions.

For more information on using VS Code, see these articles:

Visual Studio Code Tips and Tricks


Basic Editing
Using Git source control in VS Code
Markdown and Visual Studio Code

For more information about the installed extensions, see their documentation:

change-case
GitLens
Gremlins tracker for Visual Studio Code
Learn Authoring Pack
markdownlint
Reflow Markdown
Table Formatter
Markdown best practices
Article • 09/27/2022

This article provides specific guidance for using Markdown in our documentation. This is
not a tutorial for Markdown, but list specific rules and best practice for Markdown in the
PowerShell docs. If you need a tutorial for Markdown, see this Markdown cheatsheet .

Markdown specifics
The Microsoft Open Publishing System (OPS) that builds our documentation uses
markdig to process the Markdown documents. Markdig parses the documents based
on the rules of the latest CommonMark specification.

The CommonMark spec is much stricter about the construction of some Markdown
elements. Pay close attention to the details provided in this document.

We use the markdownlint extension in VS Code to enforce our style and formatting
rules. This extension is installed as part of the Learn Authoring Pack.

Blank lines, spaces, and tabs


Blank lines also signal the end of a block in Markdown.

There should be a single blank between Markdown blocks of different types -- for
example, between a paragraph and a list or header.
Don't use more than one blank line. Multiple blank lines render as a single blank
line in HTML and serve no purpose.
Within a code block, consecutive blank lines break the code block.

Spacing is significant in Markdown.

Remove extra spaces at the end of lines. Trailing spaces can change how
Markdown renders.
Always uses spaces instead of hard tabs.

Titles and headings


Only use ATX headings (# style, as opposed to = or - style headers).

Use sentence case - only proper nouns and the first letter of a title or header
should be capitalized
There must be a single space between the # and the first letter of the heading
Headings should be surrounded by a single blank line
Only one H1 per document
Header levels should increment by one -- don't skip levels
Avoid using bold or other markup in headers

Limit line length to 100 characters


This applies to conceptual articles and cmdlet reference. Limiting the line length
improves the readability of git diffs and history. It also makes it easier for other writers
to make contributions.

Use the Reflow Markdown extension in VS Code to reflow paragraphs to fit the
prescribed line length.

About_topics are limited to 80 characters. For more specific information, see Formatting
About_ files.

Lists
If your list has multiple sentences or paragraphs, consider using a sublevel header rather
than a list.

List should be surrounded by a single blank line.

Unordered lists
Don't end list items with a period unless they contain multiple sentences.
Use the hyphen character ( - ) for list item bullets. This avoids confusion with bold
or italic markup that uses the asterisk ( * ).
To include a paragraph or other elements under a bullet item, insert a line break
and align indentation with the first character after the bullet.

For example:

markdown

This is a list that contain child elements under a bullet item.

- First bullet item

Sentence explaining the first bullet.

- Child bullet item


Sentence explaining the child bullet.

- Second bullet item


- Third bullet item

This is a list that contains child elements under a bullet item.

First bullet item

Sentence explaining the first bullet.

Child bullet item

Sentence explaining the child bullet.

Second bullet item

Third bullet item

Ordered lists

All items in a numbered listed should use the number 1. rather than incrementing
each item.
Markdown rendering increments the value automatically.
This makes reordering items easier and standardizes the indentation of
subordinate content.
To include a paragraph or other elements under a numbered item, align
indentation with the first character after the item number.

For example:

markdown

1. For the first element, insert a single space after the 1. Long sentences
should be wrapped to the
next line and must line up with the first character after the numbered
list marker.

To include a second element, insert a line break after the first and
align indentations. The
indentation of the second element must line up with the first character
after the numbered list
marker.

1. The next numbered item starts here.


The resulting Markdown is rendered as follows:

1. For the first element, insert a single space after the 1. Long sentences should be
wrapped to the next line and must line up with the first character after the
numbered list marker.

To include a second element, insert a line break after the first and align
indentations. The indentation of the second element must line up with the first
character after the numbered list marker.

2. The next numbered item starts here.

Images
The syntax to include an image is:

markdown

![[alt text]](<folderPath>)

Example:
![Introduction](./media/overview/Introduction.png)

Where alt text is a brief description of the image and <folderPath> is a relative path
to the image.

Alternate text is required to support screen readers for the visually impaired.
Images should be stored in a media/<article-name> folder within the folder
containing the article.
Create a folder that matches the filename of your article under the media folder.
Copy the images for that article to that new folder.
Don't share images between articles.
If an image is used by multiple articles, each folder must have a copy of that
image.
This prevents a change to an image in one article affecting another article.

The following image file types are supported: *.png , *.gif , *.jpeg , *.jpg , *.svg

Markdown extensions supported by Open Publishing


The Learn Authoring Pack contains tools that support features unique to our publishing
system. Alerts are a Markdown extension to create blockquotes that render with colors
and icons highlighting the significance of the content. The following alert types are
supported:

markdown

> [!NOTE]
> Information the user should notice even if skimming.

> [!TIP]
> Optional information to help a user be more successful.

> [!IMPORTANT]
> Essential information required for user success.

> [!CAUTION]
> Negative potential consequences of an action.

> [!WARNING]
> Dangerous certain consequences of an action.

These alerts look like this on Microsoft Learn:

Note block

7 Note

Information the user should notice even if skimming.

Tip block

 Tip

Optional information to help a user be more successful.

Important block

) Important

Essential information required for user success.

Caution block

U Caution
Negative potential consequences of an action.

Warning block

2 Warning

Dangerous certain consequences of an action.

Hyperlinks
Hyperlinks must use Markdown syntax [friendlyname](url-or-path) .

Link references are supported.

The publishing system supports three types of links:


URL links
File links
Cross-reference links

All URLs to external websites should use HTTPS unless that isn't valid for the target
site.

Links must have a friendly name, usually the title of the linked article

Don't use backticks, bold, or other markup inside the brackets of a hyperlink.

Bare URLs may be used when you're documenting a specific URI and must be
enclosed in backticks. For example:

markdown

By default, if you don't specify this parameter, the DMTF standard


resource URI
`http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/` is used and the
class name is appended to it.

URL-type Links

URL links to other articles on learn.microsoft.com must use site-relative paths. The
simplest way to create a relative link is to copy the URL from your browser then
remove https://learn.microsoft.com/en-us from the value you paste into
markdown.
Don't include locales in URLs on Microsoft properties (remove /en-us from URL).
Remove any unnecessary query parameters from the URL. Examples that should be
removed:
?view=powershell-5.1 - used to link to a specific version of PowerShell
?redirectedfrom=MSDN - added to the URL when you get redirected from an old

article to its new location


If you need to link to a specific version of a document, you must add the
&preserve-view=true parameter to the query string. For example: ?

view=powershell-5.1&preserve-view=true
URL links don't contain file extensions (for example, no .md )

File-type links
A file link is used to link from one reference article to another, or from one
conceptual article to another. If you need to link from a conceptual article to a
reference article you must use a URL link.
Use relative filepaths (for example: ../folder/file.md )
All file paths use forward-slash ( / ) characters
Include the file extension (for example, .md )

Cross-reference links
Cross-reference links are a special feature supported by the publishing system. You can
use cross-reference links in conceptual articles to link to .NET API or cmdlet reference.

For links to .NET API reference, see Use links in documentation in the central
Contributor Guide.

Links to cmdlet reference have the following format: xref:<module-name>.<cmdlet-


name> . For example, to link to the Get-Content cmdlet in the

Microsoft.PowerShell.Management module.

[Get-Content](xref:Microsoft.PowerShell.Management.Get-Content)

Deep linking

Deep linking is allowed on both URL and file links.

The anchor text must be lowercase


Add the anchor to the end of the target path. For example:
[about_Splatting](about_Splatting.md#splatting-with-arrays)
[custom key bindings]

(https://code.visualstudio.com/docs/getstarted/keybindings#_custom-
keybindings-for-refactorings)

For more information, see Use links in documentation.

Next steps
PowerShell style guide
Guía de estilo de PowerShell y Docs
Artículo • 01/03/2022

En este artículo se proporcionan instrucciones de estilo específicas para PowerShell-


Docs contenido. Se basa en la información que se describe en Información general.

Terminología del producto


Hay diferentes variantes de PowerShell.

PowerShell: es el predeterminado. Consideramos que PowerShell 7 y posteriores


es el único y verdadero de PowerShell.

PowerShell Core : PowerShell basado en .NET Core. El uso del término Core debe
limitarse a los casos en los que sea necesario diferenciarlo de Windows PowerShell.

Windows PowerShell: PowerShell basado en .NET Framework.


Windows PowerShell solo se distribuye en Windows y requiere el marco completo.

En general, las referencias a "Windows PowerShell" en la documentación se


pueden cambiar a PowerShell. "Windows PowerShell" debe usarse cuando Windows
PowerShell comportamiento específico del usuario.

Productos relacionados

Visual Studio Code (VS Code): este es el editor de código abierto gratuito de
Microsoft. En la primera mención, se debe usar el nombre completo. Después,
puede usar VS Code. No use "VSCode".
Extensión de PowerShell para Visual Studio Code: la extensión convierte VS Code
en el IDE preferido para PowerShell. En la primera mención, se debe usar el
nombre completo. Después, puede usar la extensión de PowerShell.
Azure PowerShell: esta es la colección de módulos de PowerShell que se usan para
administrar los servicios de Azure.
Azure Stack PowerShell: esta es la colección de módulos de PowerShell que se
usan para administrar la solución de nube híbrida de Microsoft.

Detalles de Markdown
Microsoft Open Publishing System (OPS) que compila nuestra documentación usa
markdig para procesar los documentos de Markdown. Markdig analiza los
documentos en función de las reglas de la especificación de CommonMark más
reciente.

La nueva especificación de CommonMark es mucho más estricta sobre la construcción


de algunos elementos Markdown. Preste mucha atención a los detalles proporcionados
en este documento.

Líneas en blanco, espacios y tabulaciones


Además, en Markdown las líneas en blanco señalan el final de un bloque. Debe haber un
único espacio en blanco entre los bloques de Markdown de tipos diferentes (por
ejemplo, entre un párrafo y una lista o encabezado).

Varias líneas en blanco consecutivas se representan como una sola línea en blanco en
HTML. No sirven para nada. Dentro de un bloque de código, las líneas en blanco
consecutivas rompen el bloque de código.

Quite los espacios adicionales al final de las líneas.

7 Nota

En Markdown, el espaciado es importante. Use siempre espacios en lugar de


tabulaciones. Los espacios finales pueden cambiar el modo en que se representa
Markdown.

Títulos y encabezados
Use solo encabezados ATX (de estilo #, en lugar de los encabezados de estilo = o - ).

Use el tipo oración: solo deben estar en mayúscula los nombres propios y la
primera letra de un título o encabezado.
Debe haber un solo espacio entre # y la primera letra del encabezado
Los encabezados deben estar rodeados por una sola línea en blanco
Solo un nivel H1 por documento
Los niveles de encabezado deben incrementarse en uno. No omitir niveles
No use negrita u otro marcado en los encabezados

Limitación de la longitud de las líneas a 100 caracteres


Esto se aplica a los artículos conceptuales y a la referencia de cmdlets. Limitar la
longitud de línea mejora la legibilidad de las diferencias y el historial de Git. También
facilita que otros escritores realicen contribuciones.

Use la extensión Reflow Markdown en Visual Studio Code para cambiar fácilmente los
párrafos para ajustarse a la longitud de línea prescrita.

About_topics están limitados a 80 caracteres. Para obtener información más específica,


vea Formato About_ archivos.

Listas
Si la lista contiene varias oraciones o párrafos, considere la posibilidad de usar un
encabezado de subnivel en lugar de una lista.

Las listas se deben rodear con una sola línea en blanco.

Listas sin ordenar


No termine los elementos de lista con un punto a menos que contengan varias
oraciones. Use el carácter de guión ( - ) para las viñetas de elementos de lista. Esto evita
la confusión con el marcado en negrita o cursiva que usa el asterisco [ * ]. Para incluir un
párrafo u otros elementos bajo un elemento de viñeta, inserte un salto de línea y alinee
la sangría con el primer carácter después de la viñeta.

Por ejemplo:

markdown

This is a list that contain child elements under a bullet item.

- First bullet item

Sentence explaining the first bullet.

- Child bullet item

Sentence explaining the child bullet.

- Second bullet item


- Third bullet item

Se trata de una lista que contiene elementos secundarios bajo un elemento de viñeta.

Primer elemento de viñeta

Frase en la que se explica la primera viñeta.


Elemento de viñeta secundario

Frase que explica la viñeta secundaria.

Segundo elemento de viñeta

Tercer elemento de viñeta

Listas ordenadas

Para incluir un párrafo u otros elementos bajo un elemento numerado, alinee la sangría
con el primer carácter después del número de elemento. Todos los elementos de una
lista numerada deben usar el número en 1. lugar de incrementar cada elemento. La
representación de Markdown incrementa el valor de forma automática. Esto facilita la
reordenación de los elementos y normaliza la sangría del contenido subordinado.

Por ejemplo:

markdown

1. For the first element, insert a single space after the 1. Long sentences
should be
wrapped to the next line and must line up with the first character after
the numbered
list marker.

To include a second element (like this one), insert a line break after
the first
and align indentations. The indentation of the second element must line
up with
the first character after the numbered list marker. For single digit
items, like
this one, you indent to column 4. For double digits items, for example
item number
10, you indent to column 5.

1. The next numbered item starts here.

El Markdown resultante se representa de la siguiente manera:

1. Para el primer elemento, inserte un solo espacio después del 1. Las oraciones
largas se deben ajustar a la línea siguiente y alinearse con el primer carácter
después del marcador de lista numerada.

Para incluir un segundo elemento (como este), insertar un salto de línea después
de la primera y alinee las sangrías. La sangría del segundo elemento se debe
alinear con el primer carácter después del marcador de lista numerada. En el caso
de los elementos de un solo dígito, como este, se aplica sangría a la columna 4. En
el caso de los elementos de dígitos dobles, por ejemplo, el número de
elemento 10, se aplica sangría a la columna 5.

2. El siguiente elemento numerado empieza aquí.

Imágenes
La sintaxis para incluir una imagen es:

markdown

![[alt text]](<folderPath>)

Example:
![Introduction](./media/overview/Introduction.png)

Donde alt text es una breve descripción de la imagen y <folder path> es una ruta de
acceso relativa a la imagen. El texto alternativo es obligatorio para los lectores de
pantalla destinados a usuarios con discapacidad visual.

Las imágenes deben almacenarse en una media/<article-name> carpeta dentro de la


carpeta que contiene el artículo. No comparta imágenes entre artículos. Cree una
carpeta que coincida con el nombre de archivo del artículo en la carpeta media . Copie
las imágenes para ese artículo en esa carpeta nueva. Si una imagen se usa en varios
artículos, cada carpeta de imagen debe tener una copia de ese archivo de imagen. Esto
impide que se produzca un cambio en una imagen de un artículo que afecte a otro.

Se admiten los siguientes tipos de archivo de imagen: *.png , *.gif , *.jpeg , *.jpg ,
*.svg

Extensiones de Markdown admitidas en Open Publishing


El Microsoft Docs Authoring Pack contiene herramientas que admiten características
exclusivas de nuestro sistema de publicación. Las alertas son una extensión de
Markdown para crear comillas de bloque que se representan en docs.microsoft.com con
colores e iconos que resaltan la importancia del contenido. Se admiten los tipos de
alerta siguientes:

markdown

> [!NOTE]
> Information the user should notice even if skimming.
> [!TIP]
> Optional information to help a user be more successful.

> [!IMPORTANT]
> Essential information required for user success.

> [!CAUTION]
> Negative potential consequences of an action.

> [!WARNING]
> Dangerous certain consequences of an action.

Estas alertas tienen este aspecto en docs.microsoft.com:

Bloque de notas

7 Nota

Information the user should notice even if skimming.

Bloque de sugerencias

 Sugerencia

Optional information to help a user be more successful.

Bloque importante

) Importante

Essential information required for user success.

Bloque de precaución

U Precaución

Negative potential consequences of an action.

Bloque de advertencia

2 Advertencia
Consecuencias peligrosas concretas de una acción.

Hipervínculos
Los hipervínculos deben usar la sintaxis de Markdown [friendlyname](url-or-
path) . Se admiten referencias de vínculo.

El sistema de publicación admite tres tipos de vínculos:


Vínculos url
Vínculos de archivo
Vínculos de referencia cruzada

Los vínculos a otros artículos docs.microsoft.com deben ser rutas de acceso


relativas al sitio

Todas las direcciones URL de sitios web externos deben usar HTTPS a menos que
no sea válido para el sitio de destino.

Los vínculos deben tener un nombre descriptivo, normalmente el título del artículo
vinculado

Todos los elementos de la sección Vínculos relacionados de la parte inferior deben


estar hipervínculos.

No use marcas de respaldo, negrita u otro marcado dentro de los corchetes de un


hipervínculo.

Se pueden usar direcciones URL sin sistema al documentar un URI específico. El


URI debe incluirse entre comillas. Por ejemplo:

markdown

By default, if you don't specify this parameter, the DMTF standard


resource URI
`http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/` is used and the
class name is appended to it.

Vinculación a otro contenido en docs.microsoft.com

Los vínculos URL a otros artículos docs.microsoft.com deben ser rutas de acceso
relativas al sitio. La manera más sencilla de crear un vínculo relativo es copiar la
dirección URL https://docs.microsoft.com/en-us del explorador y, a continuación,
quitar del valor que pegue en Markdown. No incluya configuraciones regionales
en direcciones URL en las propiedades de Microsoft (quite de /en-us la dirección
URL). Quite los parámetros de consulta innecesarios de la dirección URL. Ejemplos
que se deben quitar:
?view=powershell-5.1 : se usa para vincular a una versión específica de
PowerShell.
?redirectedfrom=MSDN : se agrega a la dirección URL cuando se le redirige desde

un artículo antiguo a su nueva ubicación.

Si necesita vincular a una versión específica de un documento, deberá agregar


&preserve-view=true el parámetro a la cadena de consulta. Por ejemplo: ?
view=powershell-5.1&preserve-view=true

Un vínculo de archivo se usa para vincular de un artículo de referencia a otro, o de


un artículo conceptual a otro. Si necesita vincular a un artículo de referencia para
una versión específica de PowerShell, debe usar un vínculo de dirección URL.
Los vínculos de archivo contienen una ruta de acceso de archivo relativa (por
ejemplo: ../folder/file.md )
Todas las rutas de acceso de archivo usan caracteres de barra diagonal ( / )

Los vínculos de referencia cruzada son una característica especial compatible con
el sistema de publicación. Puede usar vínculos entre referencias en artículos
conceptuales para vincular a la API de .NET o a la referencia de cmdlets.

Para obtener vínculos a la referencia de API de .NET, consulte Uso de vínculos en la


documentación de la Guía central para colaboradores.

Los vínculos a la referencia de cmdlet tienen el formato siguiente: xref:<module-


name>.<cmdlet-name> . Por ejemplo, para vincular al Get-Content cmdlet en el

módulo Microsoft.PowerShell.Management .

[Get-Content](xref:Microsoft.PowerShell.Management.Get-Content)

La vinculación profunda se permite tanto en la dirección URL como en los vínculos de


archivo. Agregue el delimitador al final de la ruta de acceso de destino. Por ejemplo:

[about_Splatting](about_Splatting.md#splatting-with-arrays)

[custom key bindings]


(https://code.visualstudio.com/docs/getstarted/keybindings#_custom-

keybindings-for-refactorings)

Para obtener más información, vea Usar vínculos en la documentación.


Aplicación de formato a elementos de sintaxis
de comandos
Use siempre el nombre completo para los cmdlets y parámetros. Evite usar alias a
menos que esté demostrando específicamente el alias.

La propiedad, el parámetro, el objeto, los nombres de tipo, los nombres de clase y


los métodos de clase deben estar en negrita.
Los valores de propiedad y parámetro deben encapsularse en valores de
referencia ( ` ).
Al hacer referencia a tipos que usan el estilo entre corchetes, use los
subrayados. Por ejemplo: [System.Io.FileInfo]

Las palabras clave del lenguaje, nombres de cmdlets, funciones, variables, EXE
nativos, rutas de acceso de archivo y ejemplos de sintaxis insertadas deben
ajustarse en caracteres de inserción ( ` ).

Por ejemplo:

markdown

The following code uses `Get-ChildItem` to list the contents of


`C:\Windows` and assigns
the output to the `$files` variable.

```powershell
$files = Get-ChildItem C:\Windows
```

Las palabras clave y los operadores de PowerShell deben estar en minúsculas

Uso de mayúsculas y minúsculas (Pascal) adecuadas para los nombres y


parámetros de los cmdlets

Al hacer referencia a un parámetro por su nombre, el nombre debe estar en


negrita. Al ilustrar el uso de un parámetro con el prefijo de guión, el parámetro
se debe encapsular entre acentos graves. Por ejemplo:

markdown

The parameter's name is **Name**, but it's typed as `-Name` when


used on the command
line as a parameter.
Cuando se muestra la utilización de ejemplo de un comando externo, el
ejemplo se debe encapsular entre acentos graves. Incluya siempre la extensión
de archivo en el comando nativo. Por ejemplo:

markdown

To start the spooler service on a remote computer named DC01, you


type `sc.exe \\DC01 start spooler`.

La inclusión de la extensión de archivo garantiza que el comando correcto se


ejecuta según la precedencia de comandos de PowerShell.

Al escribir un artículo conceptual (en lugar de contenido de referencia), la primera


instancia de un nombre de cmdlet debe ser un hipervínculo a la documentación
del cmdlet. No use marcas de respaldo, negrita u otro marcado dentro de los
corchetes de un hipervínculo.

Por ejemplo:

markdown

This [Write-Host]
(/powershell/module/Microsoft.PowerShell.Utility/Write-Host) cmdlet
uses the **Object** parameter to ...

Para obtener más información, vea la sección Hipervínculos de este artículo.

Markdown para ejemplos de código


Markdown admite dos estilos de código diferentes:

Intervalos de código (en línea): marcados por un solo carácter de carácter de


signo de respaldo ( ` ). Se usa dentro de un párrafo en lugar de como un bloque
independiente.
Bloques de código: un bloque de varias líneas rodeado de cadenas de triple tick
( ``` ). Los bloques de código también pueden tener una etiqueta de idioma que
sigue a los signos de respaldo. La etiqueta de lenguaje habilita el resaltado de
sintaxis para el contenido del bloque de código.

Todos los bloques de código se deben delimitar. No use nunca la sangría para los
bloques de código. Markdown permite este patrón, pero puede ser problemático y debe
evitarse.
Un bloque de código es una o varias líneas de código rodeados por una barrera de
código de triple tick ( ``` ). Los marcadores de delimitación de código deben estar en
una línea propia antes y después del código de ejemplo. El marcador situado al
principio del bloque de código puede tener una etiqueta de idioma opcional. Open
Publishing System (OPS) de Microsoft usa la etiqueta de idioma para admitir la
característica de resaltado de sintaxis.

Para obtener una lista completa de las etiquetas de idioma admitidas, consulte Bloques
de código con barrera en la guía para colaboradores centralizados.

OPS también agrega un botón Copy (Copiar) que copia el contenido del bloque de
código en el Portapapeles. Esto le permite pegar rápidamente el código en un script
para probar el ejemplo de código. Sin embargo, no todos los ejemplos de nuestra
documentación están diseñados para ejecutarse tal y como están. Algunos bloques de
código son ilustraciones sencillas de un concepto de PowerShell.

En nuestra documentación se usan tres tipos de bloques de código:

1. Bloques de sintaxis
2. Ejemplos ilustrativos
3. Ejemplos ejecutables

Bloques de código de sintaxis


Los bloques de código de sintaxis se usan para describir la estructura sintáctica de un
comando. No use una etiqueta de idioma en la barrera de código. En este ejemplo se
muestran todos los parámetros posibles del cmdlet Get-Command .

markdown

```
Get-Command [-Verb <String[]>] [-Noun <String[]>] [-Module <String[]>]
[-FullyQualifiedModule <ModuleSpecification[]>] [-TotalCount <Int32>] [-
Syntax]
[-ShowCommandInfo] [[-ArgumentList] <Object[]>] [-All] [-ListImported]
[-ParameterName <String[]>] [-ParameterType <PSTypeName[]>]
[<CommonParameters>]
```

En este ejemplo se describe la instrucción for en términos generalizados:

markdown

```
for (<init>; <condition>; <repeat>)
{<statement list>}
```

Ejemplos ilustrativos
Los ejemplos ilustrativos se usan para explicar un concepto de PowerShell. No están
diseñados para copiarse en el Portapapeles para su ejecución. Se usan normalmente
para ejemplos sencillos que son fáciles de escribir y fáciles de entender. El bloque de
código puede incluir el símbolo del sistema de PowerShell y la salida de ejemplo.

Este es un ejemplo sencillo que ilustra los operadores de comparación de PowerShell. En


este caso, no se pretende que el lector copie y ejecute este ejemplo.

markdown

```powershell
PS> 2 -eq 2
True

PS> 2 -eq 3
False

PS> 1,2,3 -eq 2


2

PS> "abc" -eq "abc"


True

PS> "abc" -eq "abc", "def"


False

PS> "abc", "def" -eq "abc"


abc
```

Ejemplos ejecutables
Los ejemplos complejos, o ejemplos que están diseñados para copiarse y ejecutarse,
deben usar el siguiente marcado de estilo de bloque:

markdown

```powershell
<Your PowerShell code goes here>
```
La salida que muestran los comandos de PowerShell se debe incluir en un bloque de
código Output (Salida) para evitar el resaltado de sintaxis. Por ejemplo:

markdown

```powershell
Get-Command -Module Microsoft.PowerShell.Security
```

```Output
CommandType Name Version Source
----------- ---- ------- ------
Cmdlet ConvertFrom-SecureString 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet ConvertTo-SecureString 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Get-Acl 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Get-AuthenticodeSignature 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Get-CmsMessage 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Get-Credential 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Get-ExecutionPolicy 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Get-PfxCertificate 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet New-FileCatalog 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Protect-CmsMessage 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Set-Acl 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Set-AuthenticodeSignature 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Set-ExecutionPolicy 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Test-FileCatalog 3.0.0.0
Microsoft.PowerShell.Security
Cmdlet Unprotect-CmsMessage 3.0.0.0
Microsoft.PowerShell.Security
```

La etiqueta Código de salida no es un "lenguaje" oficial compatible con el sistema de


resaltado de sintaxis. Sin embargo, esta etiqueta es útil porque OPS agrega la etiqueta
"Salida" al marco del cuadro de código en la página web. El cuadro de código "Salida"
no tiene resaltado de sintaxis.

Reglas de estilo de codificación


Evitar la continuación de línea en los ejemplos de código
Evite el uso de caracteres de continuación de línea ( ` ) en los ejemplos de código de
PowerShell. Son difíciles de ver y pueden causar problemas si hay espacios adicionales al
final de la línea.

Use la extensión de PowerShell para reducir la longitud de línea de los cmdlets que
tienen varios parámetros.
Aproveche las oportunidades de salto de línea natural de PowerShell, como los
caracteres de barra vertical ( | ), las llaves de apertura ( { ), los paréntesis ( ( ) y los
corchetes ( [ ).

Evitar el uso de símbolos del sistema de PowerShell en los


ejemplos
No se recomienda usar la cadena de símbolo del sistema y debe limitarse a escenarios
diseñados para ilustrar el uso de la línea de comandos. En la mayoría de estos ejemplos,
la cadena del símbolo del sistema debe ser PS> . Este símbolo del sistema es
independiente de los indicadores específicos del sistema operativo.

En los ejemplos se requieren avisos para ilustrar los comandos que modifican el símbolo
del sistema o cuando la ruta de acceso mostrada es significativa para el escenario. En el
ejemplo siguiente se muestra cómo cambia el símbolo del sistema cuando se usa el
proveedor del Registro.

PowerShell

PS C:\> cd HKCU:\System\
PS HKCU:\System\> dir

Hive: HKEY_CURRENT_USER\System

Name Property
---- --------
CurrentControlSet
GameConfigStore GameDVR_Enabled : 1
GameDVR_FSEBehaviorMode : 2
Win32_AutoGameModeDefaultProfile : {2, 0, 1,
0...}
Win32_GameModeRelatedProcesses : {1, 0, 1,
0...}
GameDVR_HonorUserFSEBehaviorMode : 0
GameDVR_DXGIHonorFSEWindowsCompatible : 0
No usar alias en ejemplos
Use el nombre completo de todos los cmdlets y parámetros a menos que esté
documentando específicamente el alias. Los nombres de cmdlet y parámetro deben usar
los nombres correctos con mayúsculas y minúsculas Pascal.

Uso de parámetros en los ejemplos


Evite el uso de parámetros posicionales. En general, siempre debe incluir el nombre del
parámetro en un ejemplo, incluso si el parámetro es posicional. Esto reduce la
posibilidad de confusión en los ejemplos.

Artículos de referencia de cmdlets de formato


Los artículos de referencia de cmdlet tienen una estructura específica. Esta estructura se
define mediante PlatyPS . PlatyPS genera la ayuda del cmdlet para los módulos de
PowerShell en Markdown. Después de editar los archivos Markdown, PlatyPS se usa para
crear los archivos de ayuda MAML que usa el cmdlet Get-Help .

PlatyPS tiene un esquema codificado de forma rígida para la referencia de cmdlets que
se escribe en el código. En el documento platyPS.schema.md se intenta describir esta
estructura. Las infracciones de esquema causan errores de compilación que se deben
corregir antes de que podamos aceptar su contribución.

No quite ninguna de las estructuras de encabezado ATX. PlatyPS espera un


conjunto específico de encabezados.
Los encabezados Input type (Tipo de entrada) y Output type (Tipo de salida)
deben tener un tipo. Si el cmdlet no toma la entrada o devuelve un valor, use el
valor None .
Los intervalos de código insertado se pueden usar en cualquier párrafo.
Los bloques de código cercados solo se permiten en la sección EXAMPLES .

En el esquema PlatyPS, EXAMPLES es un encabezado H2. Cada ejemplo es un


encabezado H3. En un ejemplo, el esquema no permite que los bloques de código se
separen por párrafos. El esquema permite la siguiente estructura:

### Example X - Title sentence

0 or more paragraphs
1 or more code blocks
0 or more paragraphs.
Numere cada ejemplo y agregue un título breve.

Por ejemplo:

markdown

### Example 1: Get cmdlets, functions, and aliases

This command gets the PowerShell cmdlets, functions, and aliases that are
installed on the
computer.

```powershell
Get-Command
```

### Example 2: Get commands in the current session

```powershell
Get-Command -ListImported
```

Formato de los archivos About_


About_* Los archivos se escriben en Markdown, pero se envían como archivos de texto
sin formato. Usamos Pandoc para convertir Markdown en texto sin formato. About_*
Los archivos tienen el formato para obtener la mejor compatibilidad en todas las
versiones de PowerShell y con las herramientas de publicación.

Instrucciones de formato básicas:

Limitar líneas normales a 80 caracteres

Los bloques de código están limitados a 76 caracteres

Las comillas en bloque (y alertas) tienen 78 caracteres limitados

Cuando se usan estos meta-caracteres especiales \``$ , y < :

Dentro de un encabezado, estos caracteres deben tener caracteres de escape


mediante un carácter \ inicial o incluirse entre intervalos de código mediante
caracteres de escape ( ` )

Dentro de un párrafo, estos caracteres deben colocarse en intervalos de código.


Por ejemplo:
markdown

### The purpose of the \$foo variable

The `$foo` variable is used to store ...

Las tablas deben caber en 76 caracteres

Ajustar manualmente el contenido de las celdas en varias líneas

Usar caracteres | de apertura y cierre en cada línea

En el ejemplo siguiente se muestra cómo construir correctamente una tabla que


contiene información que se ajusta en varias líneas dentro de una celda.

markdown

```
|Operator|Description |Example
|
|--------|---------------------------|------------------------------
---|
|`-is` |Returns TRUE when the input|`(get-date) -is [DateTime]`
|
| |is an instance of the |`True`
|
| |specified .NET type. |
|
|`-isNot`|Returns TRUE when the input|`(get-date) -isNot [DateTime]`
|
| |not an instance of the |`False`
|
| |specified.NET type. |
|
|`-as` |Converts the input to the |`"5/7/07" -as [DateTime]`
|
| |specified .NET type. |`Monday, May 7, 2007 12:00:00
AM`|
```

7 Nota

La limitación de 76 columnas solo se aplica a los About_* temas. Puede


usar columnas anchas en artículos conceptuales o de referencia de
cmdlets.
Pasos siguientes
Lista de comprobación editorial
Lista de comprobación del editor
Artículo • 01/03/2022

Este es un resumen de las reglas que se deben aplicar al escribir artículos nuevos o
actualizar los existentes. Consulte otros artículos de la Guía del colaborador para
obtener explicaciones detalladas y ejemplos de estas reglas.

Metadatos
ms.date : debe tener el formato MM/DD/YYYY

Cambiar la fecha en que hay una actualización significativa o objetiva


Reorganización del artículo
Corrección de errores de corrección
Adición de nueva información
No cambie la fecha si la actualización es insignificante.
Corrección de errores tipográficos y formato
title : cadena única de 43-59 caracteres, incluidos los espacios

No incluya el identificador de sitio (se genera automáticamente).


Uso de mayúsculas y minúsculas de oración: solo se usa la primera palabra y los
nombres adecuados
description : de 115 a 145 caracteres, incluidos los espacios: este resumen se
muestra en el resultado de la búsqueda.

Aplicación de formato
Backtick syntax elements that appear, inline, within a paragraph
Nombres de cmdlet Verb-Noun
Variable $counter
Ejemplos sintácticos Verb-Noun -Parameter
Rutas de acceso de C:\Program Files\PowerShell archivo , /usr/bin/pwsh
Direcciones URL que no están pensadas para que se pueda hacer clic en el
documento
Valores de propiedad o parámetro
Use negrita para los nombres de propiedad, los nombres de parámetro, los
nombres de clase, los nombres de módulo, los nombres de entidad, los nombres
de objeto o de tipo.
Negrita se usa para el marcado semántico, no para el énfasis.
Negrita: uso de asteriscos **
Cursiva: uso de caracteres de subrayado _
Solo se usa para el énfasis, no para el marcado semántico.
Saltos de línea en 100 columnas (o en 80 para about_Topics)
Sin pestañas duras: usar solo espacios
Sin espacios finales en las líneas
Las palabras clave y los operadores de PowerShell deben estar en minúsculas
Uso de mayúsculas y minúsculas (Pascal) adecuadas para los nombres y
parámetros de los cmdlets

encabezados
H1 es primero: solo un H1 por artículo
Usar solo encabezados ATX
Uso de mayúsculas y minúsculas para todos los encabezados
No omitir niveles: no hay H3 sin H2
Profundidad máxima de H3 o H4
Línea en blanco antes y después
PlatyPS aplica encabezados específicos en su esquema: no agregue ni quite
encabezados.

Bloques de código
Línea en blanco antes y después
Uso de barreras de código etiquetadas : powershell, salida u otro identificador de
idioma adecuado
Barrera sin etiquetar: bloques de sintaxis u otros shells
Coloque la salida en un bloque de código independiente, excepto para ejemplos
sencillos en los que no pretende que el lector use el botón Copiar.
Consulte la lista de idiomas admitidos.

Listas
Con sangría correcta
Línea en blanco antes del primer elemento y después del último elemento
Viñeta: use guion ( - ) no asterisco ( * ): demasiado fácil de confundir con énfasis
Para las listas numeradas, todos los números son "1".

Terminología
PowerShell frente a Windows PowerShell frente a PowerShell Core
Consulte Terminología del producto.

Ejemplos de referencia de cmdlets


Debe tener al menos un ejemplo en la referencia de cmdlet

Los ejemplos deben ser suficiente código para demostrar el uso

Sintaxis de PowerShell
Uso de nombres completos de cmdlets y parámetros: sin alias
Uso de la extensión para los parámetros cuando la línea de comandos es
demasiado larga
Evite el uso de los ticos de continuación de línea: use solo cuando sea
necesario.

Quite o simplifique el símbolo del sistema de PowerShell ( PS> ), excepto cuando


sea necesario para el ejemplo.

El ejemplo de referencia de cmdlet debe seguir el siguiente esquema platyPS

Markdown

### Example 1 - Descriptive title

Zero or more short descriptive paragraphs explaining the context of the


example followed by one or
more code blocks. Recommend at least one and no more than two.

```powershell
... one or more PowerShell code statements ...
```

```Output
Example output of the code above.
```

Zero or more optional follow up paragraphs that explain the details of


the code and output.

No coloque párrafos entre los bloques de código. Todo el contenido descriptivo


debe ir antes o después de los bloques de código.

Vinculación a otros documentos


Vinculación fuera del conjunto de documentos o entre la referencia de cmdlet y
conceptual
Usar direcciones URL relativas al vincular a docs.microsoft.com (quitar
https://docs.microsoft.com/en-us )
No incluya configuraciones regionales en direcciones URL en las propiedades de
Microsoft (por ejemplo, quitar /en-us de la dirección URL)
Todas las direcciones URL de sitios web externos deben usar HTTPS a menos
que no sea válido para el sitio de destino.
Dentro del conjunto de documentos
Vínculo a la ruta de acceso del archivo (por ejemplo, ../folder/file.md )
Todas las rutas de acceso de archivo usan caracteres de barra diagonal ( / )
Los vínculos de imagen deben tener texto alternativo único
Product terminology and branding
guidelines
Article • 11/15/2022

When writing about any product it's important to correctly and consistently use product
names and terminology. This guide defines product names and terminology related to
PowerShell. Note the capitalization of specific words or use cases.

PowerShell (collective name)


Use PowerShell to describe the scripting language and an interactive shell.

PowerShell (product name)


The cross-platform version of PowerShell that's built on .NET (core), rather than the .NET
Framework. PowerShell can be installed on Windows, Linux, and macOS.

PowerShell Core (product deprecated)


The name used for PowerShell v6, built on .NET Core. This name shouldn't be used.

Windows PowerShell (product name)


The version of PowerShell that ships in Windows, which requires the full .NET
Framework.

Guidelines

First mention - use "Windows PowerShell"

Subsequent mentions - Use "PowerShell" unless the use case requires "Windows
PowerShell" to be more specific:

In PowerShell, the Invoke-WebRequest cmdlet returns


BasicHtmlWebResponseObject

In Windows PowerShell, the Invoke-WebRequest cmdlet returns


HtmlWebResponseObject
PowerShell modules
PowerShell modules are add-ons that containing PowerShell cmdlets that manage
specific products or services.

For example:

Azure PowerShell
Az.Accounts module
Windows management module
Hyper-V module
Microsoft Graph PowerShell SDK
Exchange PowerShell

Guidelines

Always use the collective name or the more specific module name when referring
to a PowerShell module
Never refer to a module as "PowerShell"

Azure PowerShell (collective name)


The branded group of products containing PowerShell modules used to manage Azure.

There are several versions of Azure PowerShell products available. Each product contains
multiple named modules.

Guidelines

Use "Azure PowerShell" as the collective name for the product


Always use the collective name, never just "PowerShell"
Use the more specific product name when referring to a specific version

Az PowerShell (product name)


The currently supported collection of modules for use with Azure.

AzureRM PowerShell (product name)


The earlier collection of modules that use the Azure Resource Manager model for
managing Azure resources. This product is deprecated and will not be supported after
February 29, 2024.
Azure Service Management PowerShell (product name)
The earliest collection of modules is for managing legacy Azure resources that use
Service Management APIs.

Azure PowerShell-related products


These products are used to manage Azure resources but aren't included in one of the
Azure PowerShell product collections.

Azure Active Directory PowerShell


Azure Information Protection PowerShell
Azure Deployment Manager PowerShell
Azure Elastic Database Jobs PowerShell
Azure Service Fabric PowerShell
Azure Stack PowerShell

Guidelines

Always use the full proper name of the product or the specific PowerShell module
name

Other PowerShell-related products

Visual Studio Code (VS Code)


This is Microsoft's free, open source editor.

Guidelines

First mention - use the full name


Subsequent mentions - you can use "VS Code"
Never use "VSCode"

PowerShell Extension for Visual Studio Code


The extension turns VS Code into the preferred IDE for PowerShell.

Guidelines

First mention - use the full name


Subsequent mentions - you can use "PowerShell extension"
Cómo presentar un problema
PowerShell-Docs datos
Artículo • 01/03/2022

Hay dos maneras de crear un problema:

1. Use los controles de comentarios en la parte inferior de la página.


2. Archivo de un problema en GitHub directamente

Uso de los controles de comentarios


Para obtener una descripción completa de los controles de comentarios, consulte el
blog del equipo de Docs que anuncia esta característica.

En la parte inferior de la mayoría de las páginas docs.microsoft.com de , verá dos


botones de comentarios. Uno es un vínculo para los comentarios del producto y otro es
para los comentarios de documentación. Los comentarios de la documentación
requieren GitHub cuenta. Al hacer clic en el botón, GitHub muestra una plantilla de
problema prepopulada. Escriba sus comentarios y envíe el formulario.

7 Nota

No se trata de un canal de soporte técnico. Se trata de una manera de hacer


preguntas aclarantes sobre la documentación o de notificar errores y omisiones. Si
necesita soporte técnico, consulte Community recursos.

Presentación de problemas en GitHub


Para presentar un GitHub problema directamente, puede hacer clic en el botón Nuevo
problema en el repositorio PowerShell-Docs . Haga clic en el botón Introducción
para el tipo de problema que desea crear. El nuevo GitHub problema se ha prepoblado
con una plantilla. La plantilla le ayuda a proporcionar la información necesaria para
solucionar el problema que está informando.

Antes de presentar un nuevo problema, lea los problemas existentes para ver si el
problema ya se ha notificado. Esto ayuda a evitar la duplicación y es posible que el
problema ya se haya respondido. Si encuentra un problema existente, puede agregar
sus comentarios, preguntas relacionadas o respuestas.
Pasos siguientes
Consulte Introducción a la escritura.

Recursos adicionales
Administración de incidencias
Cómo enviar solicitudes de
incorporación de cambios
Artículo • 05/05/2022

Para realizar cambios en el contenido, envíe una solicitud de incorporación de cambios


(PR) desde la bifurcación. Se debe revisar una solicitud de incorporación de cambios
para poder combinarla. Para obtener los mejores resultados, revise la lista de
comprobación editorial antes de enviar su solicitud de incorporación de cambios.

Uso de ramas de Git


La rama predeterminada para PowerShell-Docs es la main rama. Los cambios realizados
en las ramas de trabajo se combinan en la main rama antes de publicarse. La main rama
se combina en la live rama cada día de la semana a las 3:00 p. m. (hora del Pacífico). La
live rama contiene el contenido que se publica en docs.microsoft.com.

Antes de iniciar los cambios, cree una rama de trabajo en la copia local del repositorio
de PowerShell-Docs. Al trabajar localmente, asegúrese de sincronizar el repositorio local
antes de crear la rama de trabajo. La rama de trabajo debe crearse a partir de una copia
actualizada de la main rama.

Todas las solicitudes de incorporación de cambios deben concentrarse en la rama main .


No envíe el cambio a la live rama. Los cambios realizados en la rama main se
combinan en live , sobrescribiendo cualquier cambio realizado en live .

Hacer que el proceso de solicitud de


incorporación de cambios funcione mejor para
todos
Cuanto más sencilla y enfocada pueda realizar su PR, más rápido podrá revisarse y
combinarse.

Evitar solicitudes de incorporación de cambios que


actualicen un gran número de archivos o contengan
cambios no relacionados
Evite crear PR que incluyan cambios no relacionados. Separe las actualizaciones
secundarias de los artículos existentes de los artículos nuevos o las reescrituras
principales. Trabaje en estos cambios en ramas de trabajo independientes.

Los cambios masivos crean PR con un gran número de archivos modificados. Limite sus
PR a un máximo de 50 archivos modificados. Las PR de gran tamaño son difíciles de
revisar y son más propensas a incluir errores.

Cambiar el nombre de archivos o eliminarlos


Al cambiar el nombre o eliminar archivos, debe haber un problema asociado a la
solicitud de incorporación de cambios. Esta incidencia debe tratar la necesidad de
cambiar el nombre de los archivos o eliminarlos.

Evite mezclar el cambio o las adiciones de contenido con los cambios de nombre y las
eliminaciones de los archivos. Cualquier archivo cuyo nombre se cambie o elimine debe
agregarse al archivo de redireccionamiento global. Cuando sea posible, actualice los
archivos que se vinculan al contenido cambiado o eliminado, incluidos los archivos TOC.

Servicio de validación de PR de documentos


El servicio de validación de pr de Docs es una aplicación de GitHub que ejecuta reglas
de validación en los cambios. Debe corregir los errores o advertencias notificados por el
servicio de validación.

Visualizará el siguiente comportamiento:

1. Envía una PR.

2. En el comentario de GitHub que indica el estado de su PR, verá el estado de las


"comprobaciones" habilitadas en el repositorio. En este ejemplo, hay dos
comprobaciones habilitadas, "Commit Validation" y "OpenPublishing.Build":
La compilación puede pasar incluso si se produce un error en la validación de
confirmación.

3. Haga clic en Detalles para obtener más información.

4. En la página Detalles, verá todas las comprobaciones de validación en las que se


produjo un error, con información sobre cómo corregir las incidencias.

5. Cuando la validación de realice correctamente, se agregará el siguiente comentario


a la PR:
7 Nota

Si es colaborador externo (no empleado de Microsoft), no tiene que obtener acceso


a los informes de compilación detallados ni a la vista previa de vínculos.

Cuando se revisa la solicitud de incorporación de cambios, es posible que se le pida que


realice cambios o corrija los mensajes de advertencia de validación. El equipo de
PowerShell-Docs puede ayudarle a comprender los errores de validación y los requisitos
editoriales.

Pasos siguientes
Guía de estilo de PowerShell-Docs

Recursos adicionales
Cómo se administran las solicitudes de incorporación de cambios
Contributing quality improvements
Article • 06/28/2023

For Hacktoberfest 2022 , we piloted a process for contributing quality improvements


to the PowerShell content. This guide continues and generalizes that process, providing
a low-friction way for community members to contribute and collaborate on GitHub
through enhancing the quality of documentation.

We're focusing on these quality areas:

Formatting code samples


Formatting command syntax
Link References
Markdown linting
Spelling

Project Tracking
We're tracking contributions with the PowerShell Docs Quality Contributions GitHub
Project.

The project page has several views for the issues and PRs related to this effort:

The Open issues view shows all open issues.


The Completed view shows merged PRs.
The PowerShell view shows open issues for documentation in the PowerShell-
Docs , PowerShell-Docs-DSC , and PowerShell-Docs-Modules repositories.
The Windows PowerShell view shows open issues for documentation in the
windows-powershell-docs repository .
The Azure PowerShell view shows open issues for documentation in the azure-
docs-powershell repository .
The Open PRs view shows all open PRs.

Formatting code samples


All code samples should follow the style guidelines for PowerShell content. Those rules
are repeated in abbreviated form here for convenience:

All code blocks should be contained in a triple-backtick code fence ( ``` ).


Line length for code blocks is limited to 90 characters except in About topics,
where it's limited to 76 characters.
Avoid using line continuation characters ( ` ) in PowerShell code examples.
Use splatting or natural line break opportunities, like after pipe ( | ) characters,
opening braces ( } ), parentheses ( ( ), and brackets ( [ ) to limit line length.
Only include the PowerShell prompt for illustrative examples where the code is not
intended for copy-pasting.
Don't use aliases in examples unless you're specifically documenting the alias.
Avoid using positional parameters. Use the parameter name, even if the parameter
is positional.

Formatting command syntax


All prose should follow the style guidelines for PowerShell content. Those rules are
repeated here for convenience:

Always use the full name for cmdlets and parameters. Avoid using aliases unless
you're specifically demonstrating the alias.
Property, parameter, object, type names, class names, class methods should be
bold.
Property and parameter values should be wrapped in backticks ( ` ).
When referring to types using the bracketed style, use backticks. For example:
[System.Io.FileInfo]

PowerShell module names should be bold.


PowerShell keywords and operators should be all lowercase.
Use proper (Pascal) casing for cmdlet names and parameters.
When referring to a parameter by name, the name should be bold. When
illustrating the use of a parameter with the hyphen prefix, the parameter should be
wrapped in backticks.
When showing example usage of an external command, the example should be
wrapped in backticks. Always include the file extension of the external command.

Link references
For maintainability and readability of the markdown source for our documentation,
we're converting our conceptual documentation to use link references instead of inline
links.

For example, instead of:


Markdown

The [Packages tab][31] displays all available


packages in the PowerShell Gallery.

It should be:

Markdown

The [Packages tab][31] displays all available packages in the PowerShell


Gallery.

7 Note

When you replace an inline link, reflow the content to wrap at 100 characters. You
can use the reflow-markdown VS Code extension to do this quickly.

At the bottom of the file, add a markdown comment before the definition of the links.

Markdown

<!-- Link references -->


[01]: https://www.powershellgallery.com/packages

Make sure that:

1. The links are defined in the order they appear in the document.
2. Every link points to the correct location.
3. The link reference definitions are at the bottom of the file after the markdown
comment and are in the correct order.

Markdown linting
For any article in one of the participating repositories, opening the article in VS Code
displays linting warnings. Address any of these warnings you find, except:

MD022/blanks-around-headings/blanks-around-headers for the Synopsis


header in cmdlet reference documents. For those items, the rule violation is
intentional to ensure the documentation builds correctly with PlatyPS.

Make sure of the line lengths and use the Reflow Markdown extension to fix any long
lines.
Spelling
Sometimes, despite our best efforts, typos and misspellings get through and end up in
the documentation. These mistakes make documentation harder to follow and localize.
Fixing these mistakes makes the documentation more readable, especially for non-
English speakers who rely on accurate translations.

Process
We encourage you to choose one or more of the quality areas and an article (or group
of articles) to improve. Once you've decided what articles and content areas you want to
work on, follow these steps:

1. Check the project for issues filed for this effort to avoid duplicating efforts.

2. Open a new issue in the appropriate repository:

Open an issue in MicrosoftDocs/PowerShell-Docs for PowerShell reference


and conceptual content.
Open an issue in MicrosoftDocs/PowerShell-Docs-Dsc for DSC content
Open an issue in MicrosoftDocs/PowerShell-Docs-Modules for Crescendo,
PlatyPS, PSScriptAnalyzer, SecretManagement, and SecretStore content.
Open an issue in MicrosoftDocs/azure-docs-powershell for Azure
PowerShell content.
Open an issue in MicrosoftDocs/windows-powershell-docs for Windows
PowerShell module content.

3. Follow our contributor's guide to get setup for making your changes.

4. Submit your pull request. Ensure:

a. Your PR title has the Quality: prefix.

b. Your PR body references the issue it resolves as an unordered list item and uses
one of the linking keywords .

For example, if you're working on issue 123 , the body of your PR should include
the following Markdown:

Markdown

- resolves #123
The content developers will review your work as soon as they can to help you get it
merged.
Hacktoberfest and other hack-a-thon
events
Article • 10/04/2022

Hacktoberfest is an annual worldwide event held during October. The event encourages
open source developers to contribute to repositories through pull requests (PR). GitHub
hosts many open source repositories that contribute to Microsoft Learn content. Several
repositories actively participate in Hacktoberfest.

How to contribute
Before you can contribute to an open source repo, you must first configure your
account to contribute to Microsoft Learn. If you have never completed this process, start
by signing up for a GitHub account. Be sure to install Git and the Markdown tools.

To get credit for participation, register with Hacktoberfest and read their participation
guide .

Find a repo that needs your help


The PowerShell-Docs team is supporting Hacktoberfest contributions for several
PowerShell documentation repositories. We have defined a set of cleanup tasks
designed to be simple for first time contributors. Full information can be found in the
Hacktoberfest meta-issue .

To be successful with these tasks, you should:

Have a general understanding of PowerShell syntax


Have an understanding of splatting
Be able to read and follow the PowerShell-Docs style guide and Editorial checklist
Basic familiarity with Markdown

Before contributing should read the meta-issue. When you are ready to start, open a
new issue using the Hacktoberfest issue template (linked below):

MicrosoftDocs/PowerShell-Docs
MicrosoftDocs/PowerShell-Docs-DSC
MicrosoftDocs/PowerShell-Docs-Modules
MicrosoftDocs/windows-powershell-docs
MicrosoftDocs/azure-docs-powershell
Quality expectations
To have a successful contribution to an open source Microsoft Learn repository, create a
meaningful and impactful PR. The following examples from the official Hacktoberfest
site are considered low-quality contributions:

PRs that are automated (for example, scripted opening PRs to remove whitespace,
fix typos, or optimize images)
PRs that are disruptive (for example, taking someone else's branch or commits and
making a PR)
PRs that are regarded by a project maintainer as a hindrance vs. helping
A submission that's clearly an attempt to simply +1 your PR count for October

Finally, one PR to fix a typo is fine, but five PRs to remove a stray whitespace are not.

For more information, see Hacktoberfest: Values .

Open a PR
A PR provides a convenient way for a contributor to propose a set of changes. When
opening a PR, specify in the original comment that it's intended to contribute to
hacktoberfest. Successful PRs have these common characteristics:

The PR adds value.


The contributor is receptive to feedback.
The intended changes are well articulated.
The changes are related to an existing issue.

If you're proposing a PR without a corresponding issue, create an issue first. For more
information, see GitHub: About pull requests .

See also
Git and GitHub essentials for Microsoft Learn documentation
Official Hacktoberfest site
Cómo se administran las incidencias
Artículo • 01/03/2022

En este artículo se describe cómo se administran las incidencias en el repositorio de


PowerShell-Docs. Este artículo está concebido como una ayuda al trabajo para los
miembros del equipo de PowerShell-Docs. Se publica aquí para proporcionar
transparencia del proceso a nuestros colaboradores públicos.

Orígenes de las incidencias


Colaboradores de la comunidad
Colaboradores internos
Transcripciones de comentarios de canales de redes sociales
Comentarios a través del formulario de comentarios de Docs

Destinos de tiempo de respuesta


El 80 % de los nuevos problemas se cierran en un plazo de 3 días laborables.

Triaged : 1 día laborable


Corrección o cambio: 10 días laborables

Etiquetado e hitos

Tipos de etiqueta

Tipo Descripción

Área Se usa para indicar la parte de PowerShell o los documentos que explica la incidencia.
Útil para que los propietarios de características encuentren incidencias relativas a su
característica.

Problema Indica el tipo de problema

Prioridad Indica la prioridad del problema. Intervalo de valores 0 (alto) -4 (bajo)

Status Indica el estado del elemento de trabajo o por qué se cerró.

Etiqueta Etiquetas usadas para la clasificación adicional

En espera Indica que estamos esperando a alguien o a algún otro evento


Hitos
Las incidencias y las PR deben etiquetarse con el hito adecuado. Si el problema no se
aplica a una versión específica, no se usa ningún hito. Las PR y los problemas
relacionados con los cambios que aún no se han combinado en la base de código de
PowerShell deben asignarse al hito Futuro. Una vez que se haya combinado el cambio
de código, cambie el hito a la versión adecuada.

Hito Descripción

7.0.0 Elementos de trabajo relacionados con PowerShell 7.0

7.1.0 Elementos de trabajo relacionados con PowerShell 7.1

7.2.0 Elementos de trabajo relacionados con PowerShell 7.2

Futuro Elementos de trabajo relacionados con una versión futura de PowerShell

Proceso de evaluación de prioridades


Los miembros del equipo de documentación de PowerShell revisan los problemas
diariamente y analizan los nuevos problemas a medida que llegan. El equipo se reúne
semanalmente para analizar los problemas que necesitan una trijecución o permanecen
sin resolver.

Comentarios sobre el producto ubicados incorrectamente


Escriba un comentario que redirija al cliente al canal de comentarios correcto.

Opcional: copie la incidencia en la ubicación de comentarios sobre el producto


adecuada, agregue un vínculo al elemento copiado y cierre la incidencia.

La ubicación predeterminada para los problemas de PowerShell es


https://github.com/PowerShell/PowerShell/issues/new/choose .

Solicitudes de soporte técnico


Si la pregunta de soporte técnico es sencilla, respóndala de forma educada y cierre
la incidencia.

Si la pregunta es más complicada o el remitente responde con más preguntas,


rediríjales a foros y canales de soporte técnico. Texto sugerido para redirigirles a
foros:
Markdown

> This is not the right forum for these kinds of questions. Try posting
your question in a
> community support forum. For a list of community forums see:
> https://docs.microsoft.com/powershell/scripting/community/community-
support

Infracciones del código de conducta


Edite el problema para quitar cualquier contenido ofensivo, en caso necesario.
Escriba un comentario indicando que la incidencia es correo no deseado, ciérrela y,
a continuación, bloquéela para evitar comentarios adicionales.
Cada infracción debe tratarse en la información de referencia semanal para
determinar la necesidad de realizar más acciones (informe a GitHub o Microsoft
Legal).
Administración de solicitudes de
incorporación de cambios
Artículo • 05/05/2022

En este artículo se describe cómo se administran las solicitudes de incorporación de


cambios en el repositorio de PowerShell-Docs. Este artículo está concebido como una
ayuda al trabajo para los miembros del equipo de PowerShell-Docs. Se publica aquí para
proporcionar transparencia del proceso a nuestros colaboradores públicos.

Procedimientos recomendados
La persona que envía la solicitud de incorporación de cambios no debe combinar
la solicitud de incorporación de cambios sin una revisión del mismo nivel.
Asigne el revisor homólogo cuando se envíe la solicitud de incorporación de
cambios. La asignación temprana permite al revisor responder antes con
comentarios editoriales.
Use los comentarios para describir la naturaleza del cambio o el tipo de revisión
que se solicita. Asegúrese de @mencionar (@mention) al revisor. Por ejemplo, si el
cambio es menor y no necesita una revisión técnica completa, explique esto en un
comentario.

Pasos del proceso de una solicitud de


incorporación de cambios
1. Escritor: crea la solicitud de incorporación de cambios.

Vincula los problemas que resuelve la solicitud de incorporación de cambios.


Usa la característica autoclose de GitHub para cerrar el problema.

2. Escritor: asigna el revisor homólogo.


3. Revisor: corrige y realiza comentarios (según sea necesario).
4. Escritor: incorpora los comentarios de revisión.
5. Ambos: revisan la representación de la versión preliminar.
6. Ambos: revisan el informe de validación: corrigen advertencias y errores.
7. Escritor: agrega comentarios finales (incluye información de Acrolinx).
8. Revisor: marca la revisión como "aprobada".
9. Administrador del repositorio: fusiona mediante combinación la solicitud de
incorporación de cambios (consulte a continuación los criterios),
Lista de comprobación del revisor de contenido
Puede encontrar una lista más completa en la lista de comprobación editorial.

Corrige la gramática, el estilo, la concisión y la precisión técnica.


Se asegura de que se siguen aplicando ejemplos a la versión de destino.
Comprueba la representación de la versión preliminar.
Comprueba los metadatos: ms.date, quita ms.assetid y garantiza los campos
obligatorios.
Valida la exactitud de Markdown.
Consulte la guía de estilo para obtener reglas de formato específicas del
contenido.
Reorganiza los ejemplos de la manera siguiente:
Frase(s) de introducción
Código y salida
Explicación detallada del código (según sea necesario)
Comprueba la exactitud de los hipervínculos.
Reemplaza o quita vínculos de TechNet/MSDN.
Garantiza el número mínimo de redireccionamientos al destino.
Garantiza HTTPS.
Corrige el tipo de vínculo.
Vínculos de archivo para archivos locales.
Vínculos de dirección URL para archivos fuera del conjunto de documentos.
Quita configuraciones regionales de las direcciones URL.
Simplifica las direcciones URL que apuntan a docs.microsoft.com .

Proceso de fusión mediante combinación de


ramas
La main rama es la única rama que se combina en live . Las fusiones mediante
combinación de ramas de corta duración (trabajo) deben tener aplicado squash.

Fusionar mediante release-branch principal live


combinación de/a

working-branch aplicar squash y fusionar aplicar squash y fusionar No


mediante combinación mediante combinación permitida

release-branch — merge No
permitida
Fusionar mediante release-branch principal live
combinación de/a

principal fusionar mediante cambio — merge


de base

Lista de comprobación de fusión mediante combinación


de las solicitudes de incorporación de cambios
Revisión del contenido finalizada
Rama de destino correcta para el cambio
Sin conflictos de fusión mediante combinación
Todos los pasos de validación y compilación aprobados
Se deben corregir las advertencias y sugerencias (consulte la sección Notas para
conocer las excepciones).
Sin vínculos rotos
Fusión mediante combinación según la tabla

Notas
Se pueden pasar por alto las siguientes advertencias:

Can't find service name for `<version>/<modulepath>/About/About.md`

Metadata with following name(s) are not allowed to be set in Yaml header, or
as file level
metadata in docfx.json, or as global metadata in docfx.json: `locale`. They
are generated by
Docs platform, so the values set in these 3 places will be ignored. Please
remove them from all
3 places to resolve the warning.

Cuando se fusiona mediante combinación una solicitud de incorporación de cambios, se


cambia el encabezado de la rama de destino. Las solicitudes de incorporación de
cambios basadas en el encabezado anterior ahora están obsoletas. La solicitud de
incorporación de cambios no actualizada puede fusionarse mediante combinación con
los derechos de administrador para invalidar las advertencias de fusión mediante
combinación en GitHub. Este procedimiento se puede hacer de forma segura si las
solicitudes de incorporación de cambios anteriormente fusionadas mediante
combinación no han tocado los mismos archivos. Sin embargo, hacer clic en el botón
Actualizar rama es la opción más segura. Es posible que tenga conflictos sin resolver
que deban corregirse.

Publicación en vivo
Los cambios acumulados en la rama main se deben publicar periódicamente en el sitio
web en vivo.

La main rama se combina con live cada día de la semana a las 3pm PST.
La rama main se debe fusionar mediante combinación con live después de algún
cambio importante.
Cambios en 50 o más archivos
Tras fusionar mediante combinación una rama de versión
Cambios en las configuraciones del repositorio o del conjunto de documentos
(docfx.json, configuraciones de OPS, compilación de scripts, etc.)
Cambios en el archivo de redireccionamiento
Cambios realizados en la Tabla de contenidos
Tras fusionar mediante combinación una rama de "proyecto" (reorganización de
contenido, actualización masiva, etc.)
Labelling in GitHub
Article • 02/03/2023

This article documents how we label issues and pull requests in the PowerShell-Docs
repository. This article is designed to be a job aid for members of the PowerShell-Docs
team. It's published here to provide process transparency for our public contributors.

Labels always have a name and a description that is prefixed with their type.

Area labels
Area labels identify the parts of PowerShell or the documentation that the issue relates
to.

Label Related Content

area-about The about_* topic articles.

area-archive The Microsoft.PowerShell.Archive module.

area-cim The CimCmdlets module.

area-community Community-facing projects, including the contributor's guide and monthly


updates.

area-conceptual Conceptual (non-reference) articles.

area-console The console host

area-core The Microsoft.PowerShell.Core module.

area-crescendo The Crescendo module.

area-debugging Debugging PowerShell.

area-diagnostics The Microsoft.PowerShell.Diagnostics module.

area-dsc PowerShell Desired State Configuration.

area-editorsvcs The PowerShell editor services.

area-engine The PowerShell engine.

area-error- Error handling in PowerShell


handling

area-experimental PowerShell's experimental features


Label Related Content

area-gallery The PowerShell Gallery.

area-helpsystem The Help services, including the pipeline and *-Help cmdlets.

area-host The Microsoft.PowerShell.Host module.

area-ise The PowerShell ISE.

area-jea The Just Enough Administration feature.

area-language The PowerShell syntax and keywords.

area-learn The structured training content for PowerShell.

area-localaccounts The Microsoft.PowerShell.LocalAccounts module.

area-localization Localization problems or opportunities for the content.

area-management The Microsoft.PowerShell.Management module.

area-native-cmds Using native commands in PowerShell.

area-omi Open Management Infrastructure & CDXML.

area-ops-issue Building and rendering the content on the site.

area-other Miscellaneous modules.

area-overview The overview section in the conceptual content.

area- The PackageManagement module.


packagemanagement

area-parallelism Content covering parallel processing, such as using ForEach-Object or


PowerShell Jobs.

area-platyps The PlatyPS module.

area-portability Cross-platform compatibility.

area-powershellget The PowerShellGet module.

area-providers PowerShell providers.

area-psreadline The PSReadline module.

area-release-notes The PowerShell release notes.

area-remoting The PowerShell remoting feature and cmdlets.


Label Related Content

area- The PSScriptAnalyzer module.


scriptanalyzer

area-sdk-docs The conceptual documentation for the PowerShell SDK.

area-sdk-ref The .NET API reference documentation for the PowerShell SDK.

area-security The Microsoft.PowerShell.Security module and security concepts in


general.

area-setup Installing and configuring PowerShell.

area-threadjob The ThreadJob module.

area-utility The Microsoft.PowerShell.Utility module.

area-versions Issues with the versioning of the documentation.

area-vscode The VS Code PowerShell extension.

area-wincompat The Windows Compatibility feature.

area-wmf The Windows Management Framework.

area-workflow The Windows PowerShell Workflow feature.

Issue labels
Issue labels distinguish issues by purpose.

Label Issue Category

issue-doc-bug Errors or ambiguities in the content

issue-doc-idea Requests for new content

issue-kudos Praise, positive feedback, or thanks rather than work items

issue-product-feedback Feedback or problems with the product itself

issue-question Support questions

Priority labels
Priority labels rank which work items need to be worked on before others. These labels
are only used when needed to manage large sets of work items.
Label Priority Level

Pri0 Highest

Pri1 High

Pri2 Medium

Pri3 Low

Project Labels
Project labels indicate what ongoing GitHub Project a work item is related to. These
labels are used for automatically adding work items to a project on creation.

Label Project

project-quality The quality improvement project

Quality labels
Quality labels categorize work items for the quality improvement effort.

Label Improvement

quality-aliases Ensure cmdlet aliases are documented

quality-format-code- Ensure proper casing, line length, and other formatting in code
samples samples

quality-format-command- Ensure proper casing and formatting for command syntax


syntax

quality-link-references Ensure links in conceptual docs are defined as numbered


references

quality-markdownlint Ensure content follows markdownlint rules

quality-spelling Ensure proper casing and spelling for words

Status labels
Status labels indicate why a work item was closed or shouldn't be merged. Issues are
only given status labels when they're closed without a related PR.
Label Status

resolution-answered Closed by existing documentation

resolution-duplicate Closed as duplicate issue

resolution-external Closed by customer or outside resource

resolution-no-repro Unable to reproduce the reported issue

resolution-refer-to-support Closed and referred to community or product support

resolution-wont-fix Closed as won't fix

Tag labels
Tag labels add independent context for work items.

Label Purpose

in-progress Someone is actively working on the item

go-live The work item is related to a specific release

doc-a-thon The work item is related to a doc-a-thon

up-for-grabs Any contributor may volunteer to resolve the work item

hacktoberfest-accepted The PR is accepted for inclusion in #hacktoberfest

hacktoberfest- The PR is a candidate for inclusion in #hacktoberfest


candidate

needs-triage The issue needs to be triaged by the team before it is ready to be


worked

code-of-conduct Closed for spam, trolling, or code of conduct violations

do-not-merge The PR isn't meant to be merged

Waiting labels
Waiting labels indicate that a work item can't be resolved until an external condition is
met.

Label Waiting For


Label Waiting For

hold-for-pr Upstream PR to be merged

hold-for-release Upstream product to release

needs-investigation Waiting for team member to verify or research

needs-more-info Additional details or clarification from work item author

needs-response Response from work item author

review-shiproom Shiproom discussion with the PowerShell team


Ciclo de vida de soporte técnico de
PowerShell
Artículo • 07/09/2023

7 Nota

Este documento trata sobre el soporte técnico de PowerShell.


Windows PowerShell (1.0 a 5.1) es un componente del sistema operativo Windows.
Los componentes tienen la misma compatibilidad que el producto o la plataforma
principales. Para obtener más información, vea la información sobre el ciclo de
vida de los productos y servicios.

PowerShell se admite en la Directiva moderna de ciclo de vida de Microsoft, pero las


fechas de soporte técnico están vinculadas a la directiva de soporte técnico de .NET y
.NET Core . En este enfoque de mantenimiento, los clientes pueden elegir entre
versiones de soporte técnico a largo plazo (LTS) o versiones actuales.

Una versión de LTS de PowerShell se basa en una versión de LTS de .NET. Las
actualizaciones a una versión de LTS solo contienen actualizaciones críticas de seguridad
y correcciones de mantenimiento diseñadas para minimizar el impacto en las cargas de
trabajo existentes. Las versiones de LTS de PowerShell se admiten hasta el final del
soporte técnico de .NET.

Una versión actual es aquella que se lanza entre versiones de LTS. Las versiones actuales
pueden contener correcciones críticas, innovaciones y nuevas características. Una
versión actual se admite durante seis meses después de la siguiente versión (Current o
LTS).

) Importante

Debe tener instalada la actualización de revisión más reciente para poder obtener
soporte técnico. Por ejemplo, si está ejecutando PowerShell 7.3 y se ha publicado la
versión 7.3.1, debe actualizar a 7.3.1 para optar al soporte técnico.

Plataformas compatibles
PowerShell se ejecuta en varios sistemas operativos (SO) y arquitecturas de procesador.
Para recibir soporte técnico de Microsoft, el SO debe cumplir los criterios siguientes:
.NET Core admite la versión y la arquitectura de procesador del sistema operativo.
La versión del sistema operativo se admite durante al menos un año.
La versión del sistema operativo no es una versión provisional ni equivalente.
El publicador del sistema operativo admite actualmente la versión del sistema
operativo.
El equipo de PowerShell ha probado la versión de la distribución.

Cuando una versión de la plataforma llega al final de la vida útil definida por el
propietario de la plataforma, PowerShell también deja de ofrecer soporte técnico a esa
versión de la plataforma. Los paquetes previamente publicados siguen estando
disponibles para los clientes que necesitan acceso, pero ya no se proporcionan soporte
técnico formal ni actualizaciones de ningún tipo.

Windows
En la tabla siguiente se muestra una lista de las versiones de PowerShell y las versiones
de Windows en las que se admiten. Estas versiones se admitirán hasta que la versión de
PowerShell o la de Windows lleguen al final del soporte técnico.

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Windows 7.2 (LTS- 7.3 7.4 (versión


Current) preliminar)

Windows Server 2016, 2019, o 2022

Windows Server 2012 R2

Windows Server Core (2012 R2 o


posterior)

Windows Server Nano (1809 o posterior)

Windows 11
Windows 7.2 (LTS- 7.3 7.4 (versión
Current) preliminar)

Windows 10 1607+

7 Nota

La compatibilidad con una versión específica de Windows la determinan las


directivas de ciclo de vida de Soporte técnico de Microsoft. Para más información,
consulte:

Preguntas más frecuentes sobre el ciclo de vida del cliente Windows


Preguntas más frecuentes sobre la directiva moderna de ciclo de vida

PowerShell recibe soporte técnico en Windows para las arquitecturas de procesador


siguientes.

Windows 7.2 (LTS- 7.3 7.4 (versión


Current) preliminar)

Nano Server, versión 1803+ x64 x64 x64

Windows Server 2012 R2+ x64, x86 x64, x86 x64, x86

Windows Server Core 2012 x64, x86 x64, x86 x64, x86
R2+

Cliente de Windows 10 u 11 x64, x86, Arm64 x64, x86, x64, x86, Arm64
Arm64

macOS
La tabla siguiente contiene una lista de versiones de PowerShell y el estado de
compatibilidad con versiones de macOS. Estas versiones se seguirán admitiendo hasta
que la versión de macOS o la de PowerShell llegue al final del soporte técnico.

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

macOS 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

con Big Sur 11.5

macOS 12 (Monterey) y macOS 13 (Ventura) no se han probado.

Apple define la compatibilidad con macOS. Para más información, consulte:

Notas de la versión de macOS


Actualizaciones de seguridad de Apple

PowerShell recibe soporte técnico en macOS para las siguientes arquitecturas de


procesador:

macOS 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

macOS Big Sur 11.5 x64, Arm64 x64, Arm64 x64, Arm64

Alpine Linux
En la tabla siguiente se muestra una lista de versiones de PowerShell admitidas y las
versiones de Alpine en las que se admiten. Estas versiones recibirán soporte técnico
hasta que la versión de PowerShell o la de Alpine lleguen al final de la vida útil .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

3.15
Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

3.14

Alpine 3.15 se está probando.

PowerShell recibe soporte técnico en Alpine para las siguientes arquitecturas de


procesador.

Alpine 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64 x64 x64

PowerShell no se ha probado en Alpine con procesadores ARM.

Debian Linux
En la tabla siguiente se muestra una lista de versiones de PowerShell actualmente
compatibles y las versiones de Debian en las que se admiten. Estas versiones se seguirán
admitiendo hasta que la versión de PowerShell o la de Debian lleguen al final del ciclo
de vida .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

Debian 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

11

10

PowerShell recibe soporte técnico en Debian para las siguientes arquitecturas de


procesador.
Debian 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Versión 9+ x64 x64 x64

Red Hat Enterprise Linux (RHEL)


En la tabla siguiente se muestra una lista de las versiones admitidas actualmente de
PowerShell y las versiones de RHEL en las que se admiten. Estas versiones se siguen
admitiendo hasta que la versión de PowerShell o la de RHEL lleguen al final del soporte
técnico .

El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible

RHEL 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

PowerShell recibe soporte técnico en RHEL para las siguientes arquitecturas de


procesador.

RHEL 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64 x64 x64

Ubuntu Linux
En la tabla siguiente se muestra una lista de las versiones de PowerShell admitidas
actualmente y las versiones de Ubuntu en las que se admiten. Estas versiones se
seguirán admitiendo hasta que la versión de PowerShell o la de Ubuntu lleguen al final
del soporte técnico .
El icono indica que la versión del sistema operativo o PowerShell todavía recibe
soporte técnico.
El icono indica que la versión de PowerShell ya no se admite en esa versión del
sistema operativo
El icono indica que no hemos terminado de probar PowerShell en ese sistema
operativo
El icono indica que la versión del sistema operativo o PowerShell no es
compatible
Cuando la versión del sistema operativo y la de PowerShell tienen un icono , esa
combinación es compatible.

Ubuntu 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

con la versión 22.04 (LTS)

con la versión 20.04 (LTS)

con la versión 18.04 (LTS)

Solo se admiten oficialmente las versiones LTS de Ubuntu. Microsoft no ofrece soporte
técnico para las versiones provisionales ni sus equivalentes. La comunidad sí admite
las versiones provisionales. Para obtener más información, vea Distribuciones admitidas
por la comunidad.

PowerShell recibe soporte técnico en Ubuntu para las siguientes arquitecturas de


procesador.

Ubuntu 7.2 (LTS-Current) 7.3 7.4 (versión preliminar)

Todas las versiones compatibles x64, Arm32 x64, Arm32 x64, Arm32

Compatibilidad de Windows PowerShell


El ciclo de vida de soporte técnico de PowerShell no comprende a los módulos no
incluidos en el paquete de la versión de PowerShell. Por ejemplo, el uso del módulo
ActiveDirectory que se suministra como parte de Windows Server es un escenario que

no se admite en el ciclo de vida de soporte técnico de Windows.

Características experimentales
Las características experimentales no están diseñadas para usarse en entornos de
producción. Apreciamos los comentarios sobre las características experimentales y
proporcionamos el mejor soporte posible para ellas.

Notas sobre las licencias


PowerShell se publica bajo la licencia de MIT . De acuerdo con esta licencia y sin un
contrato de soporte técnico de pago, los usuarios están limitados al soporte técnico de
la comunidad. Con el soporte técnico de la comunidad, Microsoft no garantiza la
capacidad de respuesta ni correcciones para el usuario.

Obtención de soporte técnico


El soporte técnico de PowerShell se ofrece en virtud de contratos de soporte técnico
tradicionales de Microsoft, incluido el soporte técnico de pago , los Contratos
Enterprise de Microsoft y Microsoft Software Assurance . También existe la opción
de pagar para obtener soporte técnico asistido para PowerShell. Basta con enviar una
solicitud de soporte técnico para su problema.

Existen múltiples opciones de soporte de la comunidad. Puede presentar un problema,


un error o una solicitud de característica en GitHub. Además, puede encontrar ayuda en
otros miembros de la PowerShell Tech Community de Microsoft o en cualquiera de los
foros de la comunidad que aparecen en la página central de PowerShell. Si tiene algún
problema que requiera atención inmediata, deberá usar las opciones convencionales de
soporte técnico de pago.

) Importante

Debe tener instalada la actualización de revisión más reciente para poder obtener
soporte técnico. Por ejemplo, si está ejecutando PowerShell 7.3 y se ha publicado la
versión 7.3.1, debe actualizar a 7.3.1 para optar al soporte técnico.

Fechas de finalización de soporte técnico de


PowerShell
En función de estas directivas de ciclo de vida, en la tabla siguiente se enumeran las
fechas en las que finaliza la compatibilidad con las versiones actuales de PowerShell:

Versión Fecha de la versión Finalización de soporte técnico

7.4 (versión preliminar) TBD TBD


Versión Fecha de la versión Finalización de soporte técnico

7.3 (estable) 9 de noviembre de 2022 8 de mayo de 2024

7.2 (LTS-Current) 8 de noviembre de 2021 8 de noviembre de 2024

El soporte técnico de PowerShell en una plataforma determinada se basa en la directiva


de soporte técnico de la versión de .NET usada.

PowerShell 7.3 (estable) se basa en la directiva de ciclo de vida del sistema


operativo con soporte técnico de .NET 7.0
PowerShell 7.2 (LTS-Current) se basa en la directiva de ciclo de vida del sistema
operativo con soporte técnico de .NET 6.0 .

Las fechas de finalización del soporte técnico para las versiones ya retiradas eran:

Versión Fecha de la versión Finalización de soporte técnico

7.0 (LTS) 4 de marzo de 2020 3 de diciembre de 2022

7.1 11 de noviembre de 2020 8 de mayo de 2022

6.2 28 de marzo de 2019 4 de septiembre de 2020

6.1 13 de septiembre de 2018 28 de septiembre de 2019

6.0 20 de enero de 2018 13 de febrero de 2019

Historial de versiones
La tabla siguiente contiene una escala de tiempo de las versiones principales de
PowerShell. Esta tabla se proporciona como referencia histórica. No está prevista para
determinar el ciclo de vida de soporte técnico.

Versión Fecha de la Nota:


versión

PowerShell 7.4 (versión Basado en .NET 8.0.0 (versión preliminar)


preliminar)

PowerShell 7.3 Noviembre de Basado en .NET 7.0.


2022

PowerShell 7.2 (LTS-Current) Noviembre de Basado en .NET 6.0 (LTS-Current).


2021
Versión Fecha de la Nota:
versión

PowerShell 7.1 Noviembre de Basado en .NET 5.0.


2020

PowerShell 7.0 (LTS) Marzo de 2020 Basado en .NET Core 3.1 (LTS)

PowerShell 6.2 Marzo de 2019 Basado en .NET Core 2.1.

PowerShell 6.1 Septiembre de Basado en .NET Core 2.1.


2018

PowerShell 6.0 Enero de 2018 Primera versión, compilada en .NET Core 2.0.
Instalable en Windows, Linux y macOS

Windows PowerShell 5.1 Agosto de Publicado en Windows 10 Anniversary Update y


2016 Windows Server 2016, WMF 5.1

Windows PowerShell 5.0 Febrero de Publicado en Windows Management Framework


2016 (WMF) 5.0

Windows PowerShell 4.0 Octubre de Integrado en Windows 8.1 y con


2013 Windows Server 2012 R2, WMF 4.0

Windows PowerShell 3.0 Octubre de Integrado en Windows 8 y con


2012 Windows Server 2012, WMF 3.0

Windows PowerShell 2.0 Julio de 2009 Integrado en Windows 7 y


Windows Server 2008 R2, WMF 2.0

Windows PowerShell 1.0 Noviembre de Componente opcional de Windows Server 2008


2006

Ejecute el comando siguiente para ver el número de versión completo de .NET que usa
la versión de PowerShell que está ejecutando:

PowerShell

[System.Runtime.InteropServices.RuntimeInformation]::FrameworkDescription

6 Collaborate with us on
PowerShell
GitHub
A cross-platform task automation
The source for this content can solution made up of a command-
be found on GitHub, where you line shell and a scripting language.
can also create and review
issues and pull requests. For  Open a documentation issue
more information, see our
contributor guide.  Provide product feedback

También podría gustarte