関数 関数ドライブ

【連載】

PowerShell Core入門 - 基本コマンドの使い方

【第42回】関数 関数ドライブ

[2019/03/15 07:00]後藤大地 ブックマーク ブックマーク

  • サーバ/ストレージ

サーバ/ストレージ

関数ドライブ

前回はPowerShell Coreの関数がどのスコープに所属するかを説明した。関数は関数が作成された場所のスコープに所属するのがデフォルトの動作。ただし、スコープ指定を行って作成をすればグローバルスコープなど、本来のスコープを超えるスコープに登録させることもできる。

もうひとつ、PowerShell Coreの関数は関数ドライブという点からアクセスする方法も用意されている。PowerShell Coreでは作成した関数は関数ドライブに所属するようになる。関数ドライブはC:やD:のようなドライブ表記と同じで、Function:のようにコロンを指定した表記でアクセスできる。たとえば、次のようにGet-ChildItemを実行すると関数ドライブに登録されている関数を表示させることができる。

関数ドライブに登録されている関数を一覧表示

PS /Users/daichi> Get-ChildItem function:

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        cd..                                                          
Function        cd\                                                           
Function        Clear-Host                                                    
Function        help                                                          
Function        oss                                                           
Function        Pause                                                         
Function        prompt                                                        
Function        PSConsoleHostReadLine                              2.0.0      PSReadLine
Function        TabExpansion2                                                 


PS /Users/daichi>

関数ドライブに登録されている関数には「Function:関数名」といった表記でアクセスできる。さらにDefinitionを使えばどのような関数として定義されているのかの内容も確認することができる。さきほど表示された関数のうち、次の関数はシェルでいえばエイリアスに相当するくらい簡単な置き換えになっていることがわかる。

関数: cd..

PS /Users/daichi> (Get-ChildItem function:cd..).Definition
Set-Location ..
PS /Users/daichi>

関数: cd\

PS /Users/daichi> (Get-ChildItem function:cd\).Definition 
Set-Location \
PS /Users/daichi>

関数: Pause

PS /Users/daichi> (Get-ChildItem function:Pause).Definition
$null = Read-Host 'Press Enter to continue...'
PS /Users/daichi>

関数: prompt

PS /Users/daichi> (Get-ChildItem function:prompt).Definition

"PS $($executionContext.SessionState.Path.CurrentLocation)$('>' * ($nestedPromptLevel + 1)) ";
# .Link
# https://go.microsoft.com/fwlink/?LinkID=225750
# .ExternalHelp System.Management.Automation.dll-help.xml

PS /Users/daichi>

関数: PSConsoleHostReadLine

PS /Users/daichi> (Get-ChildItem function:PSConsoleHostReadLine).Definition

    Microsoft.PowerShell.Core\Set-StrictMode -Off
    [Microsoft.PowerShell.PSConsoleReadLine]::ReadLine($host.Runspace, $ExecutionContext)

PS /Users/daichi>

関数: Clear-Host

PS /Users/daichi> (Get-ChildItem function:Clear-Host).Definition

& (Get-Command -CommandType Application clear | Select-Object -First 1).Definition
# .Link
# https://go.microsoft.com/fwlink/?LinkID=225747
# .ExternalHelp System.Management.Automation.dll-help.xml

PS /Users/daichi>

次の関数はそれなりに作り込まれたものになっている。まず関数helpだが、注目すべきはparam()の使い方だ。パラメータが多くなってきた場合にどのようにparam()を記述すればよいのかのよいサンプルになっている。パラメータの書き方、デフォルト値のセットの方法、引数候補の列挙など、知っておきたいものばかりだ。

関数: help

PS /Users/daichi> (Get-ChildItem function:help).Definition      

<#
.FORWARDHELPTARGETNAME Get-Help
.FORWARDHELPCATEGORY Cmdlet
#>
[CmdletBinding(DefaultParameterSetName='AllUsersView', HelpUri='https://go.microsoft.com/fwlink/?LinkID=113316')]
param(
    [Parameter(Position=0, ValueFromPipelineByPropertyName=$true)]
    [string]
    ${Name},

    [string]
    ${Path},

    [ValidateSet('Alias','Cmdlet','Provider','General','FAQ','Glossary','HelpFile','ScriptCommand','Function','Filter','ExternalScript','All','DefaultHelp','Workflow','DscResource','Class','Configuration')]
    [string[]]
    ${Category},

    [Parameter(ParameterSetName='DetailedView', Mandatory=$true)]
    [switch]
    ${Detailed},

    [Parameter(ParameterSetName='AllUsersView')]
    [switch]
    ${Full},

    [Parameter(ParameterSetName='Examples', Mandatory=$true)]
    [switch]
    ${Examples},

    [Parameter(ParameterSetName='Parameters', Mandatory=$true)]
    [string]
    ${Parameter},

    [string[]]
    ${Component},

    [string[]]
    ${Functionality},

    [string[]]
    ${Role},

    [Parameter(ParameterSetName='Online', Mandatory=$true)]
    [switch]
    ${Online},

    [Parameter(ParameterSetName='ShowWindow', Mandatory=$true)]
    [switch]
    ${ShowWindow})

    # Display the full help topic by default but only for the AllUsersView parameter set.
    if (($psCmdlet.ParameterSetName -eq 'AllUsersView') -and !$Full) {
        $PSBoundParameters['Full'] = $true
    }

    # Nano needs to use Unicode, but Windows and Linux need the default
    $OutputEncoding = if ([System.Management.Automation.Platform]::IsNanoServer -or [System.Management.Automation.Platform]::IsIoT) {
        [System.Text.Encoding]::Unicode
    } else {
        [System.Console]::OutputEncoding
    }

    $help = Get-Help @PSBoundParameters

    # If a list of help is returned, don't pipe to more
    if (($help | Select-Object -First 1).PSTypeNames -Contains 'HelpInfoShort')
    {
        $help
    }
    else
    {
        # Respect PAGER, use more on Windows, and use less on Linux
        $moreCommand,$moreArgs = $env:PAGER -split '\s+'
        if ($moreCommand) {
            $help | & $moreCommand $moreArgs
        } elseif ($IsWindows) {
            $help | more.com
        } else {
            $help | less
        }
    }

PS /Users/daichi>

ossは頻用される機能だが、この機能が関数で実装されていることもこれでわかる。内容を見てみるとParam()、Begin{}、Process{}、End{}、try-catchが使われた関数の見本のような内容になっている。どのように関数を記述すればよいのかの見本としても利用できる。

関数: oss

PS /Users/daichi> (Get-ChildItem function:oss).Definition       

[CmdletBinding()]
param(
    [ValidateRange(2, 2147483647)]
    [int]
    ${Width},

    [Parameter(ValueFromPipeline=$true)]
    [psobject]
    ${InputObject})

begin
{
    try {
        $PSBoundParameters['Stream'] = $true
        $wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Out-String',[System.Management.Automation.CommandTypes]::Cmdlet)
        $scriptCmd = {& $wrappedCmd @PSBoundParameters }
        $steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
        $steppablePipeline.Begin($PSCmdlet)
    } catch {
        throw
    }
}

process
{
    try {
        $steppablePipeline.Process($_)
    } catch {
        throw
    }
}

end
{
    try {
        $steppablePipeline.End()
    } catch {
        throw
    }
}
<#
.ForwardHelpTargetName Out-String
.ForwardHelpCategory Cmdlet
#>

PS /Users/daichi>

最後は関数TabExpansion2だ。この関数はBegin{}とProcess{}を使わず、End{}だけを使う場合の関数として興味深い。

関数: TabExpansions2

PS /Users/daichi> (Get-ChildItem function:TabExpansion2).Definition        

<# Options include:
     RelativeFilePaths - [bool]
         Always resolve file paths using Resolve-Path -Relative.
         The default is to use some heuristics to guess if relative or absolute is better.

   To customize your own custom options, pass a hashtable to CompleteInput, e.g.
         return [System.Management.Automation.CommandCompletion]::CompleteInput($inputScript, $cursorColumn,
             @{ RelativeFilePaths=$false }
#>

[CmdletBinding(DefaultParameterSetName = 'ScriptInputSet')]
Param(
    [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 0)]
    [string] $inputScript,

    [Parameter(ParameterSetName = 'ScriptInputSet', Mandatory = $true, Position = 1)]
    [int] $cursorColumn,

    [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 0)]
    [System.Management.Automation.Language.Ast] $ast,

    [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 1)]
    [System.Management.Automation.Language.Token[]] $tokens,

    [Parameter(ParameterSetName = 'AstInputSet', Mandatory = $true, Position = 2)]
    [System.Management.Automation.Language.IScriptPosition] $positionOfCursor,

    [Parameter(ParameterSetName = 'ScriptInputSet', Position = 2)]
    [Parameter(ParameterSetName = 'AstInputSet', Position = 3)]
    [Hashtable] $options = $null
)

End
{
    if ($psCmdlet.ParameterSetName -eq 'ScriptInputSet')
    {
        return [System.Management.Automation.CommandCompletion]::CompleteInput(
            <#inputScript#>  $inputScript,
            <#cursorColumn#> $cursorColumn,
            <#options#>      $options)
    }
    else
    {
        return [System.Management.Automation.CommandCompletion]::CompleteInput(
            <#ast#>              $ast,
            <#tokens#>           $tokens,
            <#positionOfCursor#> $positionOfCursor,
            <#options#>          $options)
    }
}

PS /Users/daichi>

このように、PowerShell Coreでは関数が関数ドライブに登録されるという仕組みだ。PowrShell Coreのエイリアスはシェルのエイリアスと比較すると名前だけの置き換えになっており、パラメータまで含めたエイリアスということになってくると、PowerShellにおいては関数がその役割も担っていることがわかる。

関数は作成しても基本的にPowerShell Coreが終了すると同時に消えてしまう。PowerShell Coreを起動するごとに関数を定義したい場合には、プロファイルに定義を書いておけばよい。起動するごとに定義した関数を利用できるようになる。

参考資料

※ 本記事は掲載時点の情報であり、最新のものとは異なる場合がございます。予めご了承ください。

一覧はこちら

連載目次

もっと知りたい!こちらもオススメ

【連載】RPA入門 - ツールで学ぶ活用シーン

【連載】RPA入門 - ツールで学ぶ活用シーン

AIには、ルールベース、機械学習、深層学習(ディープラーニング)の3つのレベルがあり、レベルが上がるに連れてより高度な人工知能を実現しますが、AIのスピンオフという位置付けで、Digital Labor(仮想知的労働者)によるホワイトカラー業務の自動化を実現するRPAが注目されています。

関連リンク

この記事に興味を持ったら"いいね!"を Click
Facebook で IT Search+ の人気記事をお届けします

会員登録(無料)

注目の特集/連載
[解説動画] Googleアナリティクス分析&活用講座 - Webサイト改善の正しい考え方
[解説動画] 個人の業務効率化術 - 短時間集中はこうして作る
知りたい! カナコさん 皆で話そうAIのコト
教えてカナコさん! これならわかるAI入門
対話システムをつくろう! Python超入門
Kubernetes入門
AWSで作るクラウドネイティブアプリケーションの基本
PowerShell Core入門
徹底研究! ハイブリッドクラウド
マイナビニュース スペシャルセミナー 講演レポート/当日講演資料 まとめ
セキュリティアワード特設ページ

一覧はこちら

今注目のIT用語の意味を事典でチェック!

一覧はこちら

ページの先頭に戻る