Статья размещена автором Бетке Сергей Сергеевич

PowerShell: Add-Member, другие поточные фукнции, $_ и замыкания

Зачастую при добавлении ряда статических свойств объекту класса PSObject при вычислении следующих свойств уже хочется использовать значения добавленных ранее. И при этом не хочется, чтобы код выглядел громоздко. В этой заметке как раз и предлагаю решение этой задачи.

Сразу приведу код, который будет работать неправильно:

function Add-Attribute {
get-content `
    -path $csvFile `
| convertFrom-csv `
    -useCulture `
| Add-Member -PassThru -MemberType noteProperty -Name cn -Value ( ( $_.sn, $_.givenName, $_.middleName | ? { $_ } ) -join ' ' ) `
| Add-Member -PassThru -MemberType noteProperty -Name name -Value ( $_.cn ) `
| Add-Member -PassThru -MemberType noteProperty -Name displayName -Value ( $_.cn ) `
;

Причина ошибки в том, что при вызове поточных функций переменная $_ не принимает передаваемого на “вход” поточной функции объекта, и её нельзя использовать при вычислении параметров поточной функции. А как хочется…

А теперь приведу код, который уже будет работать правильно:

function Add-Attribute {
    param (
        [Parameter(
            Mandatory=$true,
            Position=0,
            ValueFromPipeline=$false,
            ValueFromPipelineByPropertyName=$false
        )]
        [string]
        $Name
        , [Parameter(
            Mandatory=$false,
            Position=1,
            ValueFromPipeline=$false,
            ValueFromPipelineByPropertyName=$false
        )]
        [scriptBlock]
        $Value = {$null}
        , [Parameter(
            Mandatory=$true,
            Position=2,
            ValueFromPipeline=$true
        )]
        [PSObject]
        $InputObject
    ) 
    
    Add-Member `
        -PassThru `
        -InputObject $InputObject `
        -MemberType noteProperty `
        -ErrorAction SilentlyContinue `
        -Name $Name `
        -Value ( $InputObject | % { & $Value } ) `
    ;
}

get-content `
    -path $csvFile `
| convertFrom-csv `
    -useCulture `
| ? { $_.sn } `
| % { 
    $_ `
    | Add-Attribute extensionName `
    | Add-Attribute personalTitle `
    | Add-Attribute generationQualifier `
    | Add-Attribute cn { ( $_.sn, $_.givenName, $_.middleName | ? { $_ } ) -join ' ' } `
    | Add-Attribute name { $_.cn } `
    | Add-Attribute displayName { $_.cn } `
    | Add-Attribute initials { ( $_.givenName, $_.middleName | ? { $_ } | % { $_[0] + '.' } ) -join ' ' } `
    ;
} `
;

Как видно в приведённом выше коде, для того, чтобы в конвейере в выражениях, предназначенных для вычисления значения параметров поточной функции, использовать в качестве $_ объект, поданный “на вход” поточной функции, можно использовать вместо непосредственного вычисления выражения передачу в качестве аргумента функционал, который в функции мы вычисляем в нужный момент следующим вызовом:

$InputObject | % { & $Value }

Вся прелесть PowerShell в данном случае в том, что при передаче функционала PowerShell не создаст замыкания, и значение $_ будет вычисляться в момент выполнения кода с учётом областей видимости переменных в точке исполнения кода.

Опубликовать комментарий

XHTML: Вы можете использовать следующие HTML теги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Tags Связь с комментариями статьи:
RSS комментарии
Обратная ссылка