Búsqueda de sitios web

Formatee archivos de PowerShell de forma sencilla


Siempre que enseño o presento secuencias de comandos de PowerShell, siempre hablo de escribir objetos en la canalización. La mayoría de las veces, simplemente puede dejar que PowerShell formatee y muestre la salida de su comando lo mejor que pueda. Sin embargo, es posible que desees tomar el asunto en tus propias manos y crear resultados personalizados. Por ejemplo, cuando ejecuta Get-Process PowerShell muestra una tabla formateada. Pero sabes que no es necesario mostrar el objeto subyacente que ves con Get-Member. PowerShell define una vista predeterminada para los objetos de proceso. Puedes hacer lo mismo con tus comandos.

Crear salida personalizada

Aquí hay un script relativamente simple que escribe un objeto personalizado en la canalización con propiedades derivadas de varias clases WMI.

Function Get-SysInfo {

    [cmdletbinding()]

    Param(
        [Parameter(Position = 0, ValueFromPipeline)]
        [ValidateNotNullorEmpty()]
        [string]$Computername = $env:computername,
        [PSCredential]$Credential
    )

    Begin {
        $cimParams = @{
            Classname   = ""
            CimSession  = ""
            Property    = "*"
            ErrorAction = "stop"
        }
    }

    Process {
        Try {
            $sess = New-CimSession @PSBoundParameters
            $cimParams.cimSession = $sess
        }
        Catch {
            Throw $_
        }

        $cimParams.Classname = "Win32_Operatingsystem"
        $cimParams.Property = "CSName", "Caption","Version"
        Try {
            $os = Get-CimInstance @cimParams
        }
        Catch {
            Throw $_
        }
        $cimParams.Classname = "Win32_Computersystem"
        $cimParams.Property = "Manufacturer", "Model"
        $cs = Get-CimInstance @cimParams

        $cimParams.Classname = "Win32_Process"
        $cimParams.Property = "Name"
        $procs = Get-CimInstance @cimParams

        $cimParams.Classname = "Win32_Service"
        $cimParams.Filter = "State = 'running'"
        $running = Get-Ciminstance @cimParams

        [PSCustomobject]@{
            PSTypeName   = "mySysInfo"
            Computername = $os.CSName
            OS           = $os.Caption
            Version      = $os.Version
            System       = ("{0} {1}" -f $cs.Manufacturer.Trim(), $cs.Model.Trim())
            Services     = $Running.Count
            Processes    = $Procs.count
        }

        $cimParams.remove("filter")
        Remove-CimSession $sess

    } #close Process
    End {
        #not used
    }
} #close function

Estoy definiendo un nombre de tipo personalizado como parte del objeto personalizado.

Digamos que prefiero que la salida predeterminada sea una tabla en lugar de una lista. Esto requerirá una definición de tabla almacenada en un archivo format.ps1xml. Estos archivos pueden ser difíciles de crear. Solía encontrar algo en un archivo existente como $PSHome\DotnetTypes.format.ps1xml y lo copiaba en un archivo nuevo que luego actualizaba. Pero ahora tengo una solución mucho mejor.

Nuevo-PSFormatXML

Mi módulo PSScriptTools (que puede instalar desde la Galería de PowerShell) ahora incluye un comando llamado New-PSFormatXML. El comando está diseñado para analizar un objeto y, de forma predeterminada, crear una vista de tabla de todas las propiedades, aunque puede especificar qué propiedades incluir. El archivo format.ps1xml ajustará automáticamente el tamaño de la tabla, pero puede eliminar la directiva y utilizar los anchos que sean mejores. Espere algo de prueba y error al definir una nueva vista.

Crear un nuevo archivo es tan fácil como esto:

Get-SysInfo | New-PSFormatXML -Path .\mySysInfo.format.ps1xml

Sólo necesitas una única instancia de un objeto. Puede canalizar varios objetos a New-PSFormatXML, pero los siguientes se ignorarán. El comando generará un archivo xml como este:

<?xml version="1.0" encoding="UTF-8"?>
<!--
format type data generated 02/18/2019 12:19:49
by BOVINE320\Jeff
-->
<Configuration>
  <ViewDefinitions>
    <View>
      <!--Created 02/18/2019 12:19:49 by BOVINE320\Jeff-->
      <Name>default</Name>
      <ViewSelectedBy>
        <TypeName>mySysInfo</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths.-->
        <AutoSize />
        <TableHeaders>
          <TableColumnHeader>
            <Label>Computername</Label>
            <Width>15</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>OS</Label>
            <Width>27</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Version</Label>
            <Width>13</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>System</Label>
            <Width>20</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Services</Label>
            <Width>11</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Processes</Label>
            <Width>12</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <!--
            By default the entries use property names, but you can replace them with scriptblocks.
            <Scriptblock>$_.foo /1mb -as [int]</Scriptblock>
-->
              <TableColumnItem>
                <PropertyName>Computername</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>OS</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Version</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>System</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Services</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Processes</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

Desde aquí podría editar el archivo según sea necesario. Pero como me gusta mostrar todas las propiedades en una tabla, actualizaré PowerShell con esta información.

Update-FormatData -AppendPath .\mySysInfo.format.ps1xml

Ahora, cuando ejecuto mi función, obtengo una visualización de tabla de forma predeterminada.

Agregar más vistas

También puedo crear vistas adicionales.

Get-SysInfo | New-PSFormatXML -Path .\mySysInfo.format.ps1xml -Properties "Computername","OS","Version" -ViewName OS -Append

Nuevamente modifico la vista, incluso agregando propiedades personalizadas. Aquí está mi archivo de formato revisado.

<?xml version="1.0" encoding="UTF-8"?>
<!--
format type data generated 02/18/2019 12:30:50
by BOVINE320\Jeff
-->
<Configuration>
  <ViewDefinitions>
    <View>
      <!--Created 02/18/2019 12:30:50 by BOVINE320\Jeff-->
      <Name>default</Name>
      <ViewSelectedBy>
        <TypeName>mySysInfo</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <!--Delete the AutoSize node if you want to use the defined widths.-->
        <AutoSize />
        <TableHeaders>
          <TableColumnHeader>
            <Label>Computername</Label>
            <Width>15</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>OS</Label>
            <Width>27</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Version</Label>
            <Width>13</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>System</Label>
            <Width>20</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Services</Label>
            <Width>11</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Processes</Label>
            <Width>12</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <!--
            By default the entries use property names, but you can replace them with scriptblocks.
            <Scriptblock>$_.foo /1mb -as [int]</Scriptblock>
-->
              <TableColumnItem>
                <PropertyName>Computername</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>OS</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Version</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>System</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Services</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Processes</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
    <View>
      <!--Created 02/18/2019 12:31:00 by BOVINE320\Jeff-->
      <Name>OS</Name>
      <ViewSelectedBy>
        <TypeName>mySysInfo</TypeName>
      </ViewSelectedBy>
      <TableControl>
        <TableHeaders>
          <TableColumnHeader>
            <Label>Computername</Label>
            <Width>15</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>OS</Label>
            <Width>40</Width>
            <Alignment>left</Alignment>
          </TableColumnHeader>
          <TableColumnHeader>
            <Label>Version</Label>
            <Width>13</Width>
            <Alignment>right</Alignment>
          </TableColumnHeader>
        </TableHeaders>
        <TableRowEntries>
          <TableRowEntry>
            <TableColumnItems>
              <!--
            By default the entries use property names, but you can replace them with scriptblocks.
            <Scriptblock>$_.foo /1mb -as [int]</Scriptblock>
-->
              <TableColumnItem>
                <PropertyName>Computername</PropertyName>
              </TableColumnItem>
              <TableColumnItem>
                <Scriptblock>$($_.OS -replace "^Microsoft","").trim()</Scriptblock>
              </TableColumnItem>
              <TableColumnItem>
                <PropertyName>Version</PropertyName>
              </TableColumnItem>
            </TableColumnItems>
          </TableRowEntry>
        </TableRowEntries>
      </TableControl>
    </View>
  </ViewDefinitions>
</Configuration>

En esta vista, estoy usando un bloque de script para definir la propiedad del sistema operativo que elimina "Microsoft" del nombre. Para usarlo, actualizo los datos de formato y canalizo el comando a Format-Table especificando el nombre de la vista.

Hazlo bonito

Ahora bien, no hay ninguna razón para no obtener resultados bonitos o al menos significativos de sus funciones. Si está escribiendo objetos personalizados en la canalización, siempre que defina un nombre de tipo, ahora debería ser mucho más fácil crear las directivas de formato. En el manifiesto de su módulo, especifique sus archivos format.ps1xml en la sección FormatsToProcess.

Espero que encuentre esto como una adición útil a su caja de herramientas de PowerShell. Sé que esto es algo que usaré todo el tiempo en mi trabajo.

Artículos relacionados