Entspricht dem Schlüsselwort "using" von C # in Powershell?


80

Wenn ich ein anderes Objekt im .net-Framework in C # verwende, kann ich mithilfe der using-Direktive viel Tipparbeit sparen.

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

...


  var blurb = new Thingamabob();

...

Gibt es in Powershell also eine Möglichkeit, etwas Ähnliches zu tun? Ich greife auf viele .net-Objekte zu und bin nicht glücklich, tippen zu müssen

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

die ganze Zeit.


1
Ich weiß, dass dies eine alte Frage ist, aber PowerShell 5 hat die usingAnweisung eingeführt. Sie können dies für .net-Namespaces oder Module verwenden (dies ist eine der wenigen Möglichkeiten, benutzerdefinierte Klassen zu importieren). Die Syntax lautet using namespace Name.Space.Hereoder using module C:\Path\to\manifest. Die einzige Voraussetzung ist, dass es vor allen anderen Anweisungen in Ihrem Skript steht (sogar vor dem Parameterblock)
Maximilian Burszley

Antworten:


43

PowerShell 5.0 (in WMF5 oder Windows 10 und höher enthalten) fügt das using namespaceKonstrukt der Sprache hinzu. Sie können es in Ihrem Skript folgendermaßen verwenden:

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

(Die #RequireAnweisung in der ersten Zeile muss nicht verwendet werden using namespace, verhindert jedoch, dass das Skript in PS 4.0 und darunter ausgeführt wird, wo using namespaceein Syntaxfehler vorliegt.)


1
Diese # Require-Anweisung ist eine nützliche Sache, danke.
Simon Tewsi

Dies funktioniert in allgemeinen Skripten, aber die Azure DevOps PowerShell-Aufgabe mit Inline-Skript besagt, dass die Verwendung nicht die erste Anweisung ist.
Andrii

57

Auf der Namespace-Ebene gibt es wirklich nichts dergleichen. Ich weise Variablen häufig verwendete Typen zu und instanziiere sie dann:

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

Wahrscheinlich nicht wert, wenn der Typ nicht wiederholt verwendet wird, aber ich glaube, es ist das Beste, was Sie tun können.


Manchmal muss ich SecureStrings wieder in einfachen Text konvertieren. Folgendes ist nützlich: $ns = [System.Runtime.InteropServices.Marshal]dann können Sie $ns::PtrToStringAuto($ns::SecureStringToBSTR($ss)).
Petrsnd

1
Hinweis für diejenigen, die sich die am besten bewertete Antwort ansehen: PowerShell 5.0 behebt dieses Problem.
Dave Markle

@petrsnd oder verwenden([pscredential]::new('+',$ss)).GetNetworkCredential().Password
Nicolas Melay

12

Schauen Sie sich diesen Blog-Beitrag von vor ein paar Jahren an: http://blogs.msdn.com/richardb/archive/2007/02/21/add-types-ps1-poor-man-s-using-for-powershell.aspx

Hier ist ein add-types.ps1Auszug aus diesem Artikel:

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
        }
    }
}

Und um es zu benutzen:

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

Grundsätzlich durchsuche ich die Assembly nach nicht trivialen Typen und schreibe dann einen "Konstruktor", der Add-Member verwendet, um sie (strukturiert) zu den Objekten hinzuzufügen, die mir wichtig sind.

Siehe auch diesen Folgebeitrag: http://richardberg.net/blog/?p=38


Es scheint, dass man den Assemblernamen (zB mscorlib) anstelle eines Typnamens (zB System.IO.Path) verwenden muss.
Micha Wiedenmann

Wenn Sie kein Objekt haben, um es an die Funktion zu übergeben, können Sie eines mit erstellen New-Object PSObject.
Micha Wiedenmann

7

Das ist nur ein Witz, ein Witz ...

$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

Kann jemand bitte die doppelte `` 1 im Typ erklären, ich finde es schwierig, danach zu suchen.
Pete

Dies entspricht der Anweisung C # using und nicht der Anweisung using.
Paulo Morgado

Mir gefällt, wie das aussieht. Wenn Sie sich dazu verpflichten, scheint mir dies eine ziemlich elegante Lösung zu sein. Die Flexibilität von PowerShell bei der Erstellung einer neuen Syntax macht mich sehr glücklich.
Programmierer Paul

@ProgrammerPaul Wenn Sie das amüsant finden, probieren Sie eine funktionale Sprache aus - einige davon werden try..catchals Bibliothek implementiert , einschließlich Haskell und IIRC Clojure.
Jpaugh

@ProgrammerPaul (für funktionale Sprachen) lol, lesen Sie dies einfach, während Sie eine F # lib (DSL-Parser über FParsec) verpacken. Ich kenne / mag Haskell, Clojure, Scala und kann den Kommentar immer noch nicht halten. Hier kommt es: Vielleicht versuchen Sie es mit einer wirklich objektorientierten Sprache wie Smalltalk - es implementiert If / Else als Bibliothek ;-)))
Miloslav Raus

5

Hier ist ein Code, der in PowerShell 2.0 zum Hinzufügen von Typaliasnamen funktioniert. Das Problem ist jedoch, dass es keinen Umfang hat. Mit etwas zusätzlicher Arbeit könnten Sie die Namespaces "de-importieren", aber dies sollte Ihnen einen guten Start ermöglichen.

##############################################################################
#.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, danke, ich hatte noch nicht daran gedacht, die Typbeschleuniger zu erweitern. Das ist sehr interessant, ich denke, ich werde ein bisschen damit herumspielen.
froh42

Es ist praktisch, aber mit Vorsicht zu verwenden. Nichts schlimmeres als ein Skript zu schreiben, das auf dem Computer eines anderen nicht funktioniert. Aus diesem Grund habe ich diese Beschleuniger nie in mein Profil aufgenommen. Wenn überhaupt, werde ich sie an die Spitze eines Skripts setzen, damit sie beim Add-TypeAccelerator sofort fehlschlagen.
Josh

5

Wenn Sie nur eine Instanz Ihres Typs erstellen müssen, können Sie den Namen des langen Namespace in einer Zeichenfolge speichern:

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

Es ist nicht so mächtig wie die usingDirektive in C #, aber zumindest sehr einfach zu bedienen.


2

Vielen Dank an alle für Ihre Beiträge. Ich habe Richard Bergs Beitrag als Antwort markiert, weil er dem, was ich suche, am ähnlichsten ist.

Alle Ihre Antworten haben mich auf den Weg gebracht, der am vielversprechendsten erscheint: In seinem Blog-Beitrag schlägt Keith Dahlby ein Get-Type-Commandlet vor, das die einfache Erstellung von Typen für generische Methoden ermöglicht.

Ich denke, es gibt keinen Grund, dies zu erweitern, um auch einen vordefinierten Pfad von Assemblys nach einem Typ zu durchsuchen.

Haftungsausschluss: Das habe ich noch nicht gebaut ...

Hier ist, wie man es benutzen könnte:

$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()

Dies würde zu einer schönen generischen Liste von Thingamabob führen. Natürlich würde ich alles ohne Pfaddefinition in nur einer anderen Dienstprogrammfunktion zusammenfassen. Der erweiterte get-Typ würde einen Schritt zum Auflösen eines bestimmten Typs gegen den Pfad enthalten.


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

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.