2009-06-26 22 views
63

Cuando uso otro objeto en .net-Framework en C#, puedo guardar muchos tipos usando la directiva using.¿Equivalente a la palabra clave "using" de C# en powershell?

using FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It; 

... 


    var blurb = new Thingamabob(); 

... 

¿Hay alguna forma en Powershell de hacer algo similar? Estoy accediendo a muchos objetos .net y no estoy contento de tener que escribir

$blurb = new-object FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It.Thingamabob; 

todo el tiempo.

Respuesta

11

Salida esta entrada del blog desde hace un par de años: http://blogs.msdn.com/richardb/archive/2007/02/21/add-types-ps1-poor-man-s-using-for-powershell.aspx

Aquí es add-types.ps1, extraído de dicho artículo:

param(
    [string] $assemblyName = $(throw 'assemblyName is required'), 
    [object] $object 
) 

process { 
    if ($_) { 
     $object = $_ 
    } 

    if (! $object) { 
     throw 'must pass an -object parameter or pipe one in' 
    } 

    # load the required dll 
    $assembly = [System.Reflection.Assembly]::LoadWithPartialName($assemblyName) 

    # add each type as a member property 
    $assembly.GetTypes() | 
    where {$_.ispublic -and !$_.IsSubclassOf([Exception]) -and $_.name -notmatch "event"} | 
    foreach { 
     # avoid error messages in case it already exists 
     if (! ($object | get-member $_.name)) { 
      add-member noteproperty $_.name $_ -inputobject $object 
     } 
    } 
} 

Y, para usarlo:

RICBERG470> $tfs | add-types "Microsoft.TeamFoundation.VersionControl.Client" 
RICBERG470> $itemSpec = new-object $tfs.itemspec("$/foo", $tfs.RecursionType::none) 

Básicamente lo que hago es rastrear el ensamblaje para tipos no triviales, luego escribo un " structor "que usa Add-Member, agréguelos (de forma estructurada) a los objetos que me interesan.

Ver también este post seguimiento: http://richardberg.net/blog/?p=38

+0

Parece que uno necesita usar el nombre del ensamblado (por ejemplo, mscorlib) en lugar de un nombre de tipo (por ejemplo, System.IO.Path). –

+0

Si no tiene un objeto alrededor para pasarlo a la función, puede crear uno usando 'Objeto-Nuevo PSObject'. –

53

Realmente no hay nada en el nivel de espacio de nombres así. A menudo asignar tipos utilizados comúnmente para las variables y luego instanciarlas:

$thingtype = [FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It.Thingamabob]; 
$blurb = New-Object $thingtype.FullName 

Probablemente no vale la pena si el tipo no será utilizado en varias ocasiones, pero creo que es lo mejor que puede hacer.

+0

A veces necesito convertir SecureStrings a texto sin formato. Lo siguiente es útil: '$ ns = [System.Runtime.InteropServices.Marshal]' luego puedes '$ ns :: PtrToStringAuto ($ ns :: SecureStringToBSTR ($ ss))'. – petrsnd

+0

Nota para quienes buscan la respuesta mejor valorada: PowerShell 5.0 corrige esto. –

6

esto es sólo una broma, broma ...

$fullnames = New-Object ([System.Collections.Generic.List``1].MakeGenericType([String])); 

function using ($name) { 
foreach ($type in [Reflection.Assembly]::LoadWithPartialName($name).GetTypes()) 
    { 
     $fullnames.Add($type.fullname); 
    } 
} 

function new ($name) { 
    $fullname = $fullnames -like "*.$name"; 
    return , (New-Object $fullname[0]); 
} 

using System.Windows.Forms 
using FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It 
$a = new button 
$b = new Thingamabob 
+0

¿Puede alguien explicar el doble '' 1 en el tipo, me resulta difícil buscar. – Pete

+0

Eso sería el equivalente a la instrucción de uso de C#, no la directiva using. –

+0

Me gusta cómo se ve esto. Si te comprometieras con esto, esta me parece una solución bastante elegante. La flexibilidad de PowerShell en la elaboración de una nueva sintaxis me hace muy feliz. –

2

Gracias a todos por sus comentarios. Marqué la contribución de Richard Berg como respuesta, porque se parece mucho a lo que estoy buscando.

Todas sus respuestas me llevaron a la pista que parece más prometedora: en his blog post Keith Dahlby propone un comando Get-Type que permite el fácil uso de tipos para métodos genéricos.

Creo que no hay ninguna razón para evitar que esto también busque a través de una ruta de ensamblaje predefinida para un tipo.

exención de responsabilidad: No he incorporado que - sin embargo ...

Aquí es cómo se puede utilizar:

$path = (System.Collections.Generic, FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It) 

$type = get-type -Path $path List Thingamabob 
$obj = new-object $type 
$obj.GetType() 

Esto daría lugar a un buen genérica Lista de thingamabob. Por supuesto, terminaría todo sin la definición de ruta en otra función de utilidad. El tipo de obtención extendida incluiría un paso para resolver cualquier tipo dado contra la ruta.

5

Aquí hay algunos códigos que funcionan en PowerShell 2.0 para agregar alias de tipo. Pero el problema es que no tiene alcance. Con un poco de trabajo adicional, podría "des-importar" los espacios de nombres, pero esto debería tener un buen comienzo.

############################################################################## 
#.SYNOPSIS 
# Add a type accelerator to the current session. 
# 
#.DESCRIPTION 
# The Add-TypeAccelerator function allows you to add a simple type accelerator 
# (like [regex]) for a longer type (like [System.Text.RegularExpressions.Regex]). 
# 
#.PARAMETER Name 
# The short form accelerator should be just the name you want to use (without 
# square brackets). 
# 
#.PARAMETER Type 
# The type you want the accelerator to accelerate. 
# 
#.PARAMETER Force 
# Overwrites any existing type alias. 
# 
#.EXAMPLE 
# Add-TypeAccelerator List "System.Collections.Generic.List``1" 
# $MyList = New-Object List[String] 
############################################################################## 
function Add-TypeAccelerator { 

    [CmdletBinding()] 
    param(

     [Parameter(Position=1,Mandatory=$true,ValueFromPipelineByPropertyName=$true)] 
     [String[]]$Name, 

     [Parameter(Position=2,Mandatory=$true,ValueFromPipeline=$true)] 
     [Type]$Type, 

     [Parameter()] 
     [Switch]$Force 

    ) 

    process { 

     $TypeAccelerators = [Type]::GetType('System.Management.Automation.TypeAccelerators') 

     foreach ($a in $Name) { 
      if ($TypeAccelerators::Get.ContainsKey($a)) { 
       if ($Force) { 
        $TypeAccelerators::Remove($a) | Out-Null 
        $TypeAccelerators::Add($a,$Type) 
       } 
       elseif ($Type -ne $TypeAccelerators::Get[$a]) { 
        Write-Error "$a is already mapped to $($TypeAccelerators::Get[$a])" 
       } 
      } 
      else { 
       $TypeAccelerators::Add($a, $Type) 
      } 
     } 

    } 

} 
+0

Josh, gracias. Aún no había mirado extender los aceleradores de tipo. Esto es muy interesante, creo que jugaré un poco con eso. – froh42

+0

Es práctico, pero úselo con precaución. Nada peor que escribir un guión que no funciona en la máquina de otra persona. Por esa razón, nunca puse estos aceleradores en mi perfil. En todo caso, los pondré en la parte superior de un script de esa manera, fallará en el Add-TypeAccelerator de inmediato. – Josh

4

Si sólo necesita para crear una instancia de su tipo, puede almacenar el nombre del largo espacio de nombres en una cadena:

$st = "System.Text" 
$sb = New-Object "$st.StringBuilder" 

No es tan potente como la directiva using en C#, pero al menos es muy fácil de usar.

24

PowerShell 5.0 (incluido en WMF5 o Windows 10 en adelante), se suma la using namespace construir el lenguaje. Se puede utilizar en el script de esta manera:

#Require -Version 5.0 
using namespace FooCompany.Bar.Qux.Assembly.With.Ridiculous.Long.Namespace.I.Really.Mean.It 
$blurb = [Thingamabob]::new() 

(La declaración #Require en la primera línea no es necesario el uso de using namespace, pero evitará que la secuencia de comandos se ejecute en PS 4.0 y por debajo de donde using namespace es una sintaxis error).

0
#Requires -Version 5 
using namespace System.Management.Automation.Host 
#using module 
Cuestiones relacionadas