Crear objetos .NET y COM

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:

New-Object -TypeName System.Diagnostics.EventLog
  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:

New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application
Max(K) Retain OverflowAction        Entries Name
------ ------ --------------        ------- ----
16,384      7 OverwriteOlder          2,160 Application

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:

$AppLog = New-Object -TypeName System.Diagnostics.EventLog -ArgumentList Application

Si luego escribe $AppLog, puede ver que contiene el registro de aplicaciones:

$AppLog
  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.

$RemoteAppLog = New-Object -TypeName System.Diagnostics.EventLog Application, 192.168.1.81
$RemoteAppLog
  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:

$RemoteAppLog | Get-Member -MemberType Method
   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:

$RemoteAppLog.Clear()
$RemoteAppLog
  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:

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:

$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:

$WshShell | Get-Member
   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:

$a = 1,2,"three"
Get-Member -InputObject $a
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:

$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:

"$HOME\Desktop\PSHome.lnk"
C:\Documents and Settings\aka\Desktop\PSHome.lnk
'$HOME\Desktop\PSHome.lnk'
$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:

$lnk | Get-Member
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:

$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:

$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.

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:

$ie.Visible = $true

A continuación, puede navegar a una dirección web específica mediante el método Navigate:

$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:

$ie.Document.Body.InnerText

Para cerrar Internet Explorer desde PowerShell, llame a su método Quit():

$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:

$ie | Get-Member
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:

Remove-Variable ie

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:

$xl = New-Object -ComObject Excel.Application -Strict
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.