Tương đương với từ khóa “using” của C # trong powershell?


80

Khi tôi sử dụng một đối tượng khác trong .net-Framework trong C #, tôi có thể tiết kiệm rất nhiều thao tác nhập bằng cách sử dụng chỉ thị using.

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

...


  var blurb = new Thingamabob();

...

Vậy có cách nào trong Powershell để làm điều gì đó tương tự không? Tôi đang truy cập rất nhiều đối tượng .net và không hài lòng khi phải nhập

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

mọi lúc.


1
Tôi biết đây là một câu hỏi cũ, nhưng PowerShell 5 đã giới thiệu usingtuyên bố. Bạn có thể sử dụng điều này cho không gian tên .net hoặc mô-đun (đây là một trong những cách duy nhất để nhập các lớp tùy chỉnh). Cú pháp là using namespace Name.Space.Herehoặc using module C:\Path\to\manifest. Yêu cầu duy nhất là nó đi kèm trước khi bất kỳ báo cáo khác trong kịch bản của bạn (ngay cả những khối param)
Maximilian Burszley

Câu trả lời:


43

PowerShell 5.0 (có trong WMF5 hoặc Windows 10 trở lên), thêm using namespacecấu trúc vào ngôn ngữ. Bạn có thể sử dụng nó trong script của mình như sau:

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

(Câu #Requirelệnh trên dòng đầu tiên là không cần thiết để sử dụng using namespace, nhưng nó sẽ ngăn tập lệnh chạy trong PS 4.0 và bên dưới using namespacelà lỗi cú pháp.)


1
Câu lệnh #Require đó là một điều hữu ích cần biết, cảm ơn.
Simon Tewsi

Điều này hoạt động trong các tập lệnh chung nhưng tác vụ Azure DevOps PowerShell với tập lệnh nội tuyến nói rằng việc sử dụng không phải là câu lệnh đầu tiên.
Andrii

57

Thực sự không có gì ở cấp độ không gian tên như vậy. Tôi thường gán các kiểu thường dùng cho các biến và sau đó khởi tạo chúng:

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

Có lẽ không đáng nếu loại này không được sử dụng nhiều lần, nhưng tôi tin rằng đó là điều tốt nhất bạn có thể làm.


Đôi khi tôi cần chuyển đổi SecureStrings trở lại văn bản thuần túy. Sau đây là hữu ích: $ns = [System.Runtime.InteropServices.Marshal]sau đó bạn có thể $ns::PtrToStringAuto($ns::SecureStringToBSTR($ss)).
petrsnd

1
Lưu ý với những người đang xem câu trả lời được xếp hạng cao nhất: PowerShell 5.0 sửa lỗi này.
Dave Markle

@petrsnd hoặc sử dụng([pscredential]::new('+',$ss)).GetNetworkCredential().Password
Nicolas Melay

12

Kiểm tra bài đăng trên blog này từ vài năm trước: http://blogs.msdn.com/richardb/archive/2007/02/21/add-types-ps1-poor-man-s-using-for-powershell.aspx

Đây là add-types.ps1, trích từ bài báo đó:

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

Và, để sử dụng nó:

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

Về cơ bản những gì tôi làm là thu thập dữ liệu lắp ráp cho các kiểu không tầm thường, sau đó viết một "phương thức khởi tạo" sử dụng Add-Member để thêm chúng (theo cách có cấu trúc) vào các đối tượng mà tôi quan tâm.

Xem thêm bài đăng tiếp theo này: http://richardberg.net/blog/?p=38


Có vẻ như người ta cần sử dụng tên hợp ngữ (ví dụ: mscorlib) thay vì tên kiểu (ví dụ: System.IO.Path).
Micha Wiedenmann

Nếu bạn không có đối tượng để chuyển nó vào hàm, bạn có thể tạo một đối tượng bằng cách sử dụng New-Object PSObject.
Micha Wiedenmann

7

đây chỉ là một trò đùa, một trò đùa ...

$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

Ai đó có thể vui lòng giải thích kép `` 1 trong loại, tôi thấy khó tìm kiếm.
Pete

Điều đó sẽ tương đương với câu lệnh using C #, không phải lệnh using.
Paulo Morgado

Tôi thích cách này trông. Nếu bạn đã cam kết với nó, đây có vẻ là một giải pháp khá thanh lịch đối với tôi. Sự linh hoạt của PowerShell trong việc tạo ra một cú pháp mới khiến tôi rất vui.
Lập trình viên Paul

@ProgrammerPaul Nếu bạn thấy thú vị, hãy thử một ngôn ngữ chức năng - một số ngôn ngữ trong số đó triển khai try..catchdưới dạng thư viện , bao gồm Haskell và IIRC Clojure.
jpaugh

@ProgrammerPaul (wrt. Các ngôn ngữ chức năng) lol, chỉ cần đọc nó trong khi gói F # lib (DSL Parser qua FParsec). Tôi biết / thích Haskell, Clojure, Scala, và vẫn không thể giữ bình luận. Đây là nó: Có thể thử một số ngôn ngữ hướng đối tượng thực sự, như Smalltalk - nó triển khai If / Else như một thư viện ;-)))
Miloslav Raus

5

Đây là một số mã hoạt động trong PowerShell 2.0 để thêm bí danh loại. Nhưng vấn đề là nó không có phạm vi. Với một số công việc bổ sung, bạn có thể "hủy nhập" không gian tên, nhưng điều này sẽ giúp bạn có một khởi đầu tốt.

##############################################################################
#.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, cảm ơn tôi vẫn chưa xem xét việc mở rộng các loại máy gia tốc. Điều này rất thú vị, tôi nghĩ tôi sẽ chơi một chút với nó.
froh42

Nó tiện dụng nhưng hãy sử dụng nó một cách thận trọng. Không gì tệ hơn việc viết một kịch bản không hoạt động trên máy của người khác. Vì lý do đó, tôi không bao giờ đưa những bộ tăng tốc này vào hồ sơ của mình. Nếu có bất cứ điều gì, tôi sẽ đặt chúng ở đầu tập lệnh theo cách đó, nó sẽ không thành công ở Add-TypeAccelerator ngay lập tức.
Josh

5

Nếu bạn chỉ cần tạo một phiên bản thuộc loại của mình, bạn có thể lưu trữ tên của không gian tên dài trong một chuỗi:

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

Nó không mạnh bằng usingchỉ thị trong C #, nhưng ít nhất nó rất dễ sử dụng.


2

Cảm ơn mọi người đã đóng góp ý kiến. Tôi đã đánh dấu đóng góp của Richard Berg như một câu trả lời, bởi vì nó gần giống nhất với những gì tôi đang tìm kiếm.

Tất cả các câu trả lời của bạn đã đưa tôi đi theo hướng có vẻ hứa hẹn nhất: Trong bài đăng trên blog của mình, Keith Dahlby đề xuất một commandlet Get-Type cho phép dễ dàng phân tích các loại cho các phương pháp chung.

Tôi nghĩ rằng không có lý do gì chống lại việc loại bỏ điều này để cũng tìm kiếm thông qua một đường dẫn được xác định trước của các tập hợp cho một kiểu.

Tuyên bố từ chối trách nhiệm: Tôi chưa xây dựng nó - chưa ...

Đây là cách người ta có thể sử dụng nó:

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

Điều này sẽ dẫn đến một Danh sách Thingamabob chung tốt đẹp. Tất nhiên tôi sẽ tóm tắt mọi thứ không có định nghĩa đường dẫn chỉ trong một chức năng tiện ích khác. Kiểu get mở rộng sẽ bao gồm một bước để giải quyết bất kỳ kiểu nào đã cho vẫn giữ nguyên đường dẫn.



Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.