¿Equivalente a la palabra clave "using" de C # en powershell?

80

Cuando utilizo otro objeto en .net-Framework en C #, puedo ahorrar mucho tipeo usando la directiva using.

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

...


  var blurb = new Thingamabob();

...

Entonces, ¿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.

froh42
fuente
1
Sé que esta es una pregunta antigua, pero PowerShell 5 presentó la usingdeclaración. Puede utilizar esto para espacios de nombres .net o módulos (que es una de las únicas formas de importar clases personalizadas). La sintaxis es using namespace Name.Space.Hereor using module C:\Path\to\manifest. El único requisito es que esté antes de cualquier otra declaración en su guión (incluso el bloque param)
Maximilian Burszley

Respuestas:

43

PowerShell 5.0 (incluido en WMF5 o Windows 10 en adelante) agrega la using namespaceconstrucción al lenguaje. Puedes usarlo en tu script así:

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

( #RequireNo es necesario utilizar la declaración de la primera línea using namespace, pero evitará que el script se ejecute en PS 4.0 y en versiones anteriores, donde using namespacehay un error de sintaxis).

Brant Bobby
fuente
1
Esa declaración #Require es algo útil de saber, gracias.
Simon Tewsi
Esto funciona en scripts generales, pero la tarea de Azure DevOps PowerShell con script en línea dice que usar no es la primera declaración.
Andrii
57

Realmente no hay nada en el nivel del espacio de nombres como eso. A menudo asigno tipos de uso común a las variables y luego las instanciado:

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

Probablemente no valga la pena si el tipo no se usa repetidamente, pero creo que es lo mejor que puede hacer.

Dalbyk
fuente
A veces necesito convertir SecureStrings de nuevo a texto sin formato. Lo siguiente es útil: $ns = [System.Runtime.InteropServices.Marshal]entonces puedes $ns::PtrToStringAuto($ns::SecureStringToBSTR($ss)).
petrsnd
1
Nota para aquellos que buscan la respuesta mejor calificada: PowerShell 5.0 corrige esto.
Dave Markle
@petrsnd or use([pscredential]::new('+',$ss)).GetNetworkCredential().Password
Nicolas Melay
12

Consulte esta publicación de blog de 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í está add-types.ps1, extraído de ese 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 ensamblado en busca de tipos no triviales, luego escribir un "constructor" que use Add-Member y agregarlos (de forma estructurada) a los objetos que me interesan.

Vea también esta publicación de seguimiento: http://richardberg.net/blog/?p=38

Richard Berg
fuente
Parece que es necesario utilizar el nombre de ensamblado (por ejemplo, mscorlib) en lugar de un nombre de tipo (por ejemplo, System.IO.Path).
Micha Wiedenmann
Si no tiene un objeto para pasarlo a la función, puede crear uno usando New-Object PSObject.
Micha Wiedenmann
7

esto es solo 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
Pete
fuente
¿Alguien puede explicar el doble `` 1 en el tipo, me resulta difícil buscar.
Pete
Eso sería el equivalente a la instrucción using de C #, no a la directiva using.
Paulo Morgado
Me gusta cómo se ve esto. Si tuviera que comprometerse con él, esta me parece una solución bastante elegante. La flexibilidad de PowerShell para crear una nueva sintaxis me hace muy feliz.
Programador Paul
@ProgrammerPaul Si le parece divertido, pruebe un lenguaje funcional; algunos de ellos se implementan try..catchcomo una biblioteca , como Haskell y IIRC Clojure.
jpaugh
@ProgrammerPaul (wrt. Lenguajes funcionales) lol, acabo de leer esto mientras envuelve un F # lib (DSL Parser a través de FParsec). Sé / me gusta Haskell, Clojure, Scala, y todavía no puedo retener el comentario. Aquí viene: tal vez pruebe algún lenguaje verdaderamente orientado a objetos, como Smalltalk; implementa If / Else como biblioteca ;-)))
Miloslav Raus
5

Aquí hay un código que funciona 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 "anular la importación" de los espacios de nombres, pero esto debería ayudarlo a comenzar bien.

##############################################################################
#.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)
            }
        }

    }

}
Josh
fuente
Josh, gracias. Todavía no había pensado en ampliar los aceleradores de tipos. Esto es muy interesante, creo que jugaré un poco con eso.
froh42
Es útil, pero utilícelo con precaución. Nada peor que escribir un guión que no funciona en la máquina de otra persona. Por eso nunca puse estos aceleradores en mi perfil. En todo caso, los pondré en la parte superior de un script de esa manera fallará en Add-TypeAccelerator de inmediato.
Josh
5

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

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

No es tan poderoso como la usingdirectiva en C #, pero al menos es muy fácil de usar.

bouvierr
fuente
2

Gracias a todos por sus comentarios. He marcado la contribución de Richard Berg como una respuesta, porque se parece más a lo que estoy buscando.

Todas sus respuestas me llevaron por el camino que parece más prometedor: en su publicación de blog, Keith Dahlby propone un comando Get-Type que permite una fácil construcción de tipos para métodos genéricos.

Creo que no hay razón para no extender esto para buscar también un tipo en una ruta predefinida de ensamblados.

Descargo de responsabilidad: no lo he construido, todavía ...

Así es como se podría usar:

$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 resultaría en una buena lista genérica de Thingamabob. Por supuesto, terminaría todo sin la definición de la ruta en otra función de utilidad. El get-type extendido incluiría un paso para resolver cualquier tipo dado contra la ruta.

froh42
fuente
0
#Requires -Version 5
using namespace System.Management.Automation.Host
#using module
Jaqueline Vanek
fuente
-2

Me doy cuenta de que esta es una publicación antigua, pero estaba buscando lo mismo y encontré esto: http://weblogs.asp.net/adweigert/powershell-adding-the-using-statement

Editar: supongo que debería especificar que le permite usar la sintaxis familiar de ...

using ($x = $y) { ... }
haliphax
fuente
1
Eso sería el equivalente a la instrucción using de C #, no a la directiva using.
Paulo Morgado