Odpowiednik słowa kluczowego „using” w języku C # w programie PowerShell?

80

Kiedy używam innego obiektu w .net-Framework w C #, mogę zaoszczędzić dużo pisania, używając dyrektywy using.

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

...


  var blurb = new Thingamabob();

...

Czy zatem w Powershell można zrobić coś podobnego? Uzyskuję dostęp do wielu obiektów .net i nie jestem zadowolony, że muszę pisać

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

cały czas.

froh42
źródło
1
Wiem, że to stare pytanie, ale PowerShell 5 wprowadził usingoświadczenie. Możesz to wykorzystać dla przestrzeni nazw .net lub modułów (co jest jednym z jedynych sposobów importowania klas niestandardowych). Składnia to using namespace Name.Space.Herelub using module C:\Path\to\manifest. Jedynym wymaganiem jest to, że pojawia się przed jakimikolwiek innymi instrukcjami w skrypcie (nawet blokiem parametrów)
Maximilian Burszley

Odpowiedzi:

43

PowerShell 5.0 (zawarty w WMF5 lub Windows 10 i nowszych) dodaje using namespacekonstrukcję do języka. Możesz go użyć w swoim skrypcie w następujący sposób:

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

( #RequireInstrukcja w pierwszym wierszu nie jest konieczna using namespace, ale uniemożliwi uruchomienie skryptu w wersji PS 4.0 i niższych, gdzie using namespacewystępuje błąd składni).

Brant Bobby
źródło
1
To stwierdzenie #Require jest przydatne, dzięki.
Simon Tewsi
Działa to w ogólnych skryptach, ale zadanie Azure DevOps PowerShell ze skryptem wbudowanym mówi, że using nie jest pierwszą instrukcją.
Andrii,
57

Tak naprawdę na poziomie przestrzeni nazw nie ma nic takiego. Często przypisuję często używane typy do zmiennych, a następnie tworzę je:

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

Prawdopodobnie nie warto, jeśli ten typ nie będzie używany wielokrotnie, ale uważam, że to najlepsze, co możesz zrobić.

dahlbyk
źródło
Czasami muszę przekonwertować SecureStrings z powrotem na zwykły tekst. Przydatne jest: $ns = [System.Runtime.InteropServices.Marshal]wtedy możesz $ns::PtrToStringAuto($ns::SecureStringToBSTR($ss)).
petrsnd
1
Uwaga dla tych, którzy patrzą na najwyżej ocenioną odpowiedź: PowerShell 5.0 rozwiązuje ten problem.
Dave Markle
@petrsnd or use([pscredential]::new('+',$ss)).GetNetworkCredential().Password
Nicolas Melay
12

Sprawdź ten post na blogu sprzed kilku lat: http://blogs.msdn.com/richardb/archive/2007/02/21/add-types-ps1-poor-man-s-using-for-powershell.aspx

Oto add-types.ps1fragment tego artykułu:

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

Aby z niego skorzystać:

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

Zasadniczo przeszukuję zestaw pod kątem nietrywialnych typów, a następnie piszę „konstruktora”, który używa Add-Member i dodaje je (w uporządkowany sposób) do obiektów, na których mi zależy.

Zobacz także następujący post: http://richardberg.net/blog/?p=38

Richard Berg
źródło
Wygląda na to, że zamiast nazwy typu (np. System.IO.Path) należy użyć nazwy zestawu (np. Mscorlib).
Micha Wiedenmann
Jeśli nie masz w pobliżu obiektu, który mógłby przekazać go do funkcji, możesz go utworzyć za pomocą New-Object PSObject.
Micha Wiedenmann
7

to tylko żart, żart ...

$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
źródło
Czy ktoś może wyjaśnić podwójne `` 1 w typie, trudno mi jest szukać.
Pete,
Byłoby to odpowiednikiem instrukcji using C #, a nie dyrektywy using.
Paulo Morgado
Podoba mi się sposób, w jaki to wygląda. Gdybyś się do tego zobowiązał, wydaje mi się to całkiem eleganckie rozwiązanie. Elastyczność PowerShell w tworzeniu nowej składni bardzo mnie cieszy.
Programmer Paul
@ProgrammerPaul Jeśli uważasz to za zabawne, wypróbuj język funkcjonalny - niektóre z nich są implementowane try..catchjako biblioteka , w tym Haskell i IIRC Clojure.
jpaugh
@ProgrammerPaul (wrt. Języki funkcyjne) lol, po prostu czytam to podczas pakowania F # lib (parser DSL przez FParsec). Znam / lubię Haskella, Clojure, Scalę i nadal nie mogę znieść komentarza. Oto nadchodzi: Może spróbuj jakiegoś prawdziwie zorientowanego obiektowo języka, takiego jak Smalltalk - implementuje If / Else jako bibliotekę ;-)))
Miloslav Raus
5

Oto kod, który działa w programie PowerShell 2,0, aby dodać aliasy typów. Ale problem polega na tym, że nie ma określonego zakresu. Przy odrobinie dodatkowej pracy można „cofnąć import” przestrzeni nazw, ale powinno to zapewnić dobry początek.

##############################################################################
#.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
źródło
Josh, dzięki, że jeszcze nie rozważałem możliwości rozszerzenia akceleratorów typu. To bardzo interesujące, myślę, że trochę się tym pobawię.
froh42
Jest poręczny, ale używaj go ostrożnie. Nie ma nic gorszego niż napisanie scenariusza, który nie działa na cudzej maszynie. Z tego powodu nigdy nie umieszczałem tych akceleratorów w swoim profilu. Jeśli już, umieszczę je na górze skryptu, dzięki czemu od razu zakończy się niepowodzeniem w Add-TypeAccelerator.
Josh
5

Jeśli potrzebujesz tylko utworzyć instancję swojego typu, możesz zapisać nazwę długiej przestrzeni nazw w ciągu:

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

Nie jest tak potężny jak usingdyrektywa w C #, ale przynajmniej jest bardzo łatwy w użyciu.

bouvierr
źródło
2

Dziękuję wszystkim za wkład. Oznaczyłem wkład Richarda Berga jako odpowiedź, ponieważ najbardziej przypomina to, czego szukam.

Wszystkie twoje odpowiedzi przyniosły mi drogę, która wydaje się najbardziej obiecująca: w swoim poście na blogu Keith Dahlby proponuje komendę Get-Type, która umożliwia łatwe konstruowanie typów dla metod ogólnych.

Myślę, że nie ma powodu, aby nie rozszerzać tego, aby przeszukiwać również wstępnie zdefiniowaną ścieżkę zestawów dla typu.

Zastrzeżenie: nie zbudowałem tego - jeszcze ...

Oto jak można to wykorzystać:

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

Spowodowałoby to ładną ogólną Listę Thingamabob. Oczywiście wszystko poza definicją ścieżki zawarłbym w jeszcze jednej funkcji narzędzia. Rozszerzony typ pobierania obejmowałby krok rozstrzygania dowolnego typu ze ścieżki.

froh42
źródło
0
#Requires -Version 5
using namespace System.Management.Automation.Host
#using module
Jaqueline Vanek
źródło