Еквівалентно ключовому слову C # у використанні в PowerShell?


80

Коли я використовую інший об'єкт у .net-Framework в C #, я можу заощадити багато набору тексту, використовуючи директиву using.

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

...


  var blurb = new Thingamabob();

...

То чи є в Powershell спосіб зробити щось подібне? Я отримую доступ до багатьох об'єктів .net і не радий набирати текст

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

весь час.


1
Я знаю, що це старе питання, але PowerShell 5 представив usingзаяву. Ви можете використовувати це для просторів імен .net або модулів (що є одним із єдиних способів імпорту користувацьких класів). Синтаксис - це using namespace Name.Space.Hereабо using module C:\Path\to\manifest. Єдина вимога полягає в тому, щоб воно
стояло

Відповіді:


43

PowerShell 5.0 (входить до складу WMF5 або Windows 10 і новіших версій) додає using namespaceконструкцію до мови. Ви можете використовувати його у своєму сценарії так:

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

( #RequireВираз у першому рядку використовувати не потрібно using namespace, але це заважатиме сценарію працювати в PS 4.0 і нижче, де using namespaceє синтаксична помилка.)


1
Це твердження #Require - це дуже зручно знати, дякую.
Саймон Тевсі,

Це працює в загальних сценаріях, але завдання Azure DevOps PowerShell із вбудованим сценарієм говорить, що використання - не перший вираз
Андрій

57

Насправді нічого такого на рівні простору імен немає. Я часто призначаю змінні часто використовувані типи, а потім створюю їх за допомогою екземплярів:

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

Можливо, не варто, якщо тип не буде використовуватися неодноразово, але я вважаю, що це найкраще, що ви можете зробити.


Мені іноді потрібно перетворити SecureStrings назад у звичайний текст. Корисно наступне: $ns = [System.Runtime.InteropServices.Marshal]тоді можна $ns::PtrToStringAuto($ns::SecureStringToBSTR($ss)).
petrsnd

1
Примітка для тих, хто шукає найвищу оцінку відповіді: PowerShell 5.0 це виправляє.
Dave Markle

@petrsnd or use([pscredential]::new('+',$ss)).GetNetworkCredential().Password
Ніколас

12

Ознайомтесь із цим дописом у блозі кілька років тому: http://blogs.msdn.com/richardb/archive/2007/02/21/add-types-ps1-poor-man-s-using-for-powershell.aspx

Ось add-types.ps1, уривок із цієї статті:

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

І, щоб використовувати його:

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

В основному те, що я роблю, це сканувати збірку для нетривіальних типів, а потім написати «конструктор», який використовує Add-Member, додаючи їх (структурованим способом) до об’єктів, які мене цікавлять.

Дивіться також цей наступний пост: http://richardberg.net/blog/?p=38


Здається, що потрібно використовувати ім'я збірки (наприклад, mscorlib) замість імені типу (наприклад, System.IO.Path).
Micha Wiedenmann

Якщо у вас немає об’єкта для передачі його функції, ви можете створити його за допомогою New-Object PSObject.
Micha Wiedenmann

7

це просто жарт, жарт ...

$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

Хтось може пояснити подвійне `` 1 у типі, мені важко шукати.
Піт

Це було б еквівалентно оператору C # using, а не директиві using.
Паулу Моргадо

Мені подобається, як це виглядає. Якби ви взяли на себе зобов'язання, це здається мені досить елегантним рішенням. Гнучкість PowerShell при розробці нового синтаксису мене дуже радує.
Програміст Пол

@ProgrammerPaul Якщо вам це забавно, спробуйте функціональну мову - деякі з них реалізовані try..catchяк бібліотека , включаючи Haskell та IIRC Clojure.
jpaugh

@ProgrammerPaul (wrt. Функціональні мови) ха-ха, просто читаючи це, обертаючи F # lib (DSL Parser через FParsec). Я знаю / люблю Haskell, Clojure, Scala, і досі не можу вмістити коментар. Ось воно: Може, спробувати якусь справді об’єктно-орієнтовану мову, як Smalltalk - він реалізує If / Else як бібліотеку ;-)))
Мілослав Раус,

5

Ось деякий код, який працює в PowerShell 2.0 для додавання псевдонімів типу. Але проблема в тому, що він не застосовується. З деякою додатковою роботою ви можете «деімпортувати» простори імен, але це повинно вас добре розпочати.

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

    }

}

Джош, дякую, я ще не дивився на розширення прискорювачів типу. Це дуже цікаво, я думаю, я з ним трохи пограюся.
froh42

Це зручно, але використовуйте його з обережністю. Нічого гіршого, ніж написання сценарію, який не працює на чужій машині. З цієї причини я ніколи не розміщував ці прискорювачі у своєму профілі. Якщо що, я розміщу їх у верхній частині сценарію таким чином, що він відразу ж провалиться в Add-TypeAccelerator.
Джош,

5

Якщо вам просто потрібно створити екземпляр вашого типу, ви можете зберегти ім'я довгого простору імен у рядку:

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

Він не такий потужний, як usingдиректива на C #, але принаймні дуже простий у використанні.


2

Дякуємо усім за ваш внесок. Я зазначив внесок Річарда Берга як відповідь, оскільки він найбільше нагадує те, що я шукаю.

Усі ваші відповіді вивели мене на шлях, який здається найбільш перспективним: У своєму дописі в блозі Кіт Дальбі пропонує командлет Get-Type, який дозволяє легко використовувати типи типів для загальних методів.

Я думаю, що немає жодної причини проти продовжувати це, а також шукати за заздалегідь визначеним шляхом збірок для типу.

Застереження: Я ще не будував цього - поки ...

Ось як можна ним скористатися:

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

Це призведе до гарного загального списку Thingamabob. Звичайно, я б обгорнув все, що є без визначення шляху, просто черговою функцією корисності. Розширений тип get включав би крок для вирішення будь-якого заданого типу проти шляху.



-2

Я розумію, що це стара публікація, але я шукав те саме і натрапив на це: http://weblogs.asp.net/adweigert/powershell-adding-the-using-statement

Редагувати: Я гадаю, мені слід вказати, що це дозволяє використовувати знайомий синтаксис ...

using ($x = $y) { ... }

1
Це було б еквівалентно оператору C # using, а не директиві using.
Паулу Моргадо,
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.