Ubuntu Weekly Recipe

第435回PowerShellをUbuntuにインストール

PowerShellはタスクの自動化や構成管理のためのプラットフォームとしてMicrosoftが開発しているスクリプト言語およびそのコマンドラインインターフェースプログラムです。今回紹介するのは、先日FLOSSとして公開されたこのPowerShellをUbuntuで使うです。

PowerShell 「Core」

Windowsの伝統的なCLIシェルと言えばコマンドプロンプト(cmd.exe)が存在します。PowerShellは、単にシェルとしてこのコマンドプロンプトを置き換えるだけでなく、より広範囲のシステム設定へのアクセスや.NET Frameworkを用いた柔軟な拡張性、パイプを用いたオブジェクトの操作、スクリプトの開発環境などなど、その機能の豊富さによってWindowsの管理には欠かせないツールとなっています。実際、PowerShellなしには生きられない体になったシステム管理者の方も多いことでしょう[1]⁠。

先日のUbuntu Weekly Topicsでも紹介しているように、MicrosoftがそのPowerShellをFLOSSとしてGitHub上に公開しました。2016年8月時点ではまだアルファ版という扱いです。しかしながら単に「ソースコードを公開した」だけではなく、ライセンスがMIT Licenseであり、ソースコードの改修も積極的に受け入れるなど、FLOSSとしての条件が整った上での公開です。もちろんLinux上でも動作します。おそらく将来的には、Debianパッケージとして公式リポジトリからインストールできるようになるはずです[2]⁠。

PowerShellは.NET Frameworkベースのソフトウェアです。それに対して今回GitHub上に公開された「PowerShell Core」は、.NET Frameworkをモジュール化したサブセットである.NET Coreを利用したソフトウェアになっています。つまりPowerShellのフルセットではない、ということは注意しておいてください。たとえばグラフィック関連のオブジェクト操作の機能などがありません。このPowerShell Coreは、コンテナでも使うことを想定したコンパクト版のWindows ServerであるNano Serverにも搭載される予定です。またWindows以外では、当然のことながらWMI(Windows Management Instrumentation)関連の操作も行えません。

Debファイルをインストールするだけ

実際にPowerShellをインストールしてみましょう。といってもGitHub上に公開されているDebファイルをインストールするだけです。DebファイルはUbuntu 14.04 LTS用とUbuntu 16.04 LTS用の両方が存在します。本Recipeでは、16.04で使用することを前提に説明します。

まずリリースページを参考に、最新のDebファイルをダウンロードします。

$ wget "https://github.com/PowerShell/PowerShell/releases/download/\
v6.0.0-alpha.9/powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb"

Debファイルをインストールしたら、すぐにインストールせずにまずは中身を確認することにしましょう[3]⁠。dpkg-debコマンドはDebファイルの内容を確認できるツールです。たとえば「--info」オプションを渡すと、⁠apt show」で表示されるようなメタデータが表示されます。特に注意すべきは「Depends」「Recommends」です。これらのフィールドに表示されているパッケージは、このDebファイルにとって必要なパッケージとなります。下記の例だと「libunwind8」「libicu55」に依存しているということです。libunwind8はプログラムのコールチェインを操作するためのライブラリです。デスクトップ版のUbuntuなら最初からインストールされています。libicuはUnicode対応のために使われるライブラリで、こちらはすべてのエディションのUbuntuに最初からインストールされています。

$ dpkg-deb --info powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb
 新形式 debian パッケージ、バージョン 2.0。
 サイズ 40928824 バイト: コントロールアーカイブ = 14690 バイト。
     468 バイト、  13 行      control
   51279 バイト、 463 行      md5sums
 Package: powershell
 Version: 6.0.0-alpha.9-1
 License: MIT License
 Vendor: Microsoft Corporation
 Architecture: amd64
 Maintainer: PowerShell Team <PowerShellTeam@hotmail.com>
 Installed-Size: 123969
 Depends: libunwind8, libicu55
 Section: shells
 Priority: extra
 Homepage: https://microsoft.com/powershell
 Description: PowerShell is an automation and configuration management platform.
  It consists of a cross-platform command-line shell and associated scripting language.

「--contents」オプションを使うと、そのパッケージのインストールパスを確認できます。PowerShellの場合は、基本的に「/opt/microsoft/」以下にインストールし、マニュアルやパッケージの変更履歴、実行ファイルへのシンボリックリンクなどを標準的な場所にインストールするようです。ちなみにインストール済みのパッケージであれば「dpkg -L パッケージ名」で同等の情報を取得できます。

$ dpkg-deb --contents powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb
drwx------ 0/0               0 2016-08-16 07:04 ./
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./opt/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./opt/microsoft/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./opt/microsoft/powershell/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./opt/microsoft/powershell/6.0.0-alpha.9/
-rw-r--r-- 0/0           36744 2016-08-12 09:47 ./opt/microsoft/powershell/6.0.0-alpha.9/System.Xml.XPath.XDocument.dll
(中略)
-rw-r--r-- 0/0           74120 2016-06-12 08:14 ./opt/microsoft/powershell/6.0.0-alpha.9/System.Runtime.Extensions.dll
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/bin/
lrwxrwxrwx 0/0               0 2016-08-16 07:04 ./usr/bin/powershell -> /opt/microsoft/powershell/6.0.0-alpha.9/powershell
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/local/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/local/share/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/local/share/man/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/local/share/man/man1/
-rw-r--r-- 0/0            1924 2016-08-16 07:04 ./usr/local/share/man/man1/powershell.1.gz
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/share/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/share/doc/
drwxr-xr-x 0/0               0 2016-08-16 07:04 ./usr/share/doc/powershell/
-rw-r--r-- 0/0             160 2016-08-16 07:04 ./usr/share/doc/powershell/changelog.gz

Debianパッケージは、パッケージが提供するコンテンツとは別に「コントロールファイル」と呼ばれる、パッケージの操作に必要なスクリプト群を「/var/lib/dpkg/info/」以下にインストールします。そのファイルのリストは「--control」で確認できます。PowerShellの場合は、パッケージのメタデータであるcontrolファイルと、コンテンツのハッシュ値が格納されたmd5sumsファイルのみインストールします。パッケージによっては「postinst」「prerm」といった、インストールや削除前後に実行するスクリプトがインストールされることもあります。

$ dpkg-deb --control powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb control
ls control/
control  md5sums

Debファイルの中身に不審な点がなければ、パッケージをインストールしましょう。Ubuntu 16.04 LTSのaptコマンドは、相対パスでDebファイルを渡せば依存パッケージまでインストールしてくれるので便利です。なお「./」を指定しないとパッケージファイル名ではなくパッケージ名として判断してしまうので注意してください。

$ sudo apt install ./powershell_6.0.0-alpha.9-1ubuntu1.16.04.1_amd64.deb

Ubuntu 14.04 LTSなら、dpkgコマンドでインストールしたのちにapt-getコマンドで依存関係を解決すると良いでしょう。

$ sudo dpkg -i powershell_6.0.0-alpha.9-1ubuntu1.14.04.1_amd64.deb
$ sudo apt-get install -f

うまくインストールできたらPowerShellを起動してみましょう。

$ powershell
PowerShell
Copyright (C) 2016 Microsoft Corporation. All rights reserved.

PS /home/ubuntu> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.0.0-alpha
PSEdition                      Core
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   3.0.0.0
GitCommitId                    v6.0.0-alpha.9
CLRVersion
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1


PS /home/ubuntu> lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description:    Ubuntu 16.04.1 LTS
Release:        16.04
Codename:       xenial
PS /home/ubuntu> uname -a
Linux powershell 4.4.0-34-generic #53-Ubuntu SMP Wed Jul 27 16:06:39 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux
PS /home/ubuntu>

とっても簡単でしたね。

PowerShellの基本のキ

PowerShellは単体で動かすと、ごく普通のCLIシェルプログラムです。プロンプトが表示され、コマンドを入力し、ディレクトリの移動やファイルの操作、各種プログラムの呼び出しを行います。PowerShellに組み込まれた一定の命名規則に従った命令を「コマンドレット」と呼びます。単なる組み込みコマンドというわけではなく、ユーザーがコマンドレットを追加することも可能です。またシェルなのでコマンドレットだけでなく、システムに存在する実行ファイルをコマンドとして実行できます。たとえばPowerShell上でBashを実行することももちろん可能なのです。

コマンドレットは「動詞-名詞」という命名規則をもっています。必ずしもすべてが命名規則に従っているわけではありませんし、コマンドレット以外も同じような名前が付いている場合もあります。現在のセッションで利用できるコマンドレット一覧は、⁠Get-Command」で取得できます。また、ワイルドカードも使えます。なおすべて小文字でも問題ありません。

PS /home/ubuntu> Get-Command

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Function        Add-NodeKeys                                       0.0        PSDesiredStateConfiguration
Function        AddDscResourceProperty                             0.0        PSDesiredStateConfiguration
Function        AddDscResourcePropertyFromMetadata                 0.0        PSDesiredStateConfiguration
(中略)
Cmdlet          Write-Output                                       3.1.0.0    Microsoft.PowerShell.Utility
Cmdlet          Write-Progress                                     3.1.0.0    Microsoft.PowerShell.Utility
Cmdlet          Write-Verbose                                      3.1.0.0    Microsoft.PowerShell.Utility
Cmdlet          Write-Warning                                      3.1.0.0    Microsoft.PowerShell.Utility

PS /home/ubuntu> Get-Command *-Location

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Cmdlet          Get-Location                                       3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Pop-Location                                       3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Push-Location                                      3.1.0.0    Microsoft.PowerShell.Management
Cmdlet          Set-Location                                       3.1.0.0    Microsoft.PowerShell.Management

タブ補完もサポートしているので、とりあえず「Get」を入力してタブを押せば、何らかのオブジェクトを取得できるコマンドの一覧をリストアップできるというわけです。

特定のコマンドのヘルプは「Get-Help」で確認できます[4]⁠。

PS /home/ubuntu> Get-Help Set-Location

NAME
    Set-Location

SYNOPSIS
    Sets the current working location to a specified location.

(後略)

PowerShellにもエイリアス機能があります。たとえばディレクトリを移動する「Set-Location」には「sl」というエイリアスがついています。つまり、PowerShell環境では残念ながらslコマンドを実行しても、カレントディレクトリがホームディレクトリになるでSLは走ってくれません。どうしてもSLを走らせたい場合は、⁠/usr/games/sl」とフルパスで実行してください[5]⁠。

エイリアスの一覧は「Get-Alias」で取得できます。また「Set-Alias」でエイリアスを作成・変更できます。組み込みエイリアスは比較的使用頻度の高いコマンドの一覧でもあるため、一度ながめておくとPowerShellのコマンドレットの雰囲気がわかることでしょう。

PS /home/ubuntu> Get-Alias

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           ? -> Where-Object
Alias           % -> ForEach-Object
Alias           cd -> Set-Location
Alias           chdir -> Set-Location
Alias           clc -> Clear-Content
Alias           clear -> Clear-Host
Alias           clhy -> Clear-History
(後略)

変数や制御構造、リダイレクト、パイプといった機能は他のシェルスクリプトと同じように利用できます。しかしながらPowerShellでは、すべてをオブジェクトとして扱います。パイプもオブジェクトを次のコマンドレットに渡すのです。雰囲気としてはBashよりも、Pythonなどのオブジェクト指向言語に近いでしょう。たとえばpsコマンドを使ってプロセスツリーを表示することは、Bashと同じです。

(bashの中でpowershellを実行し、その中でさらにbashとpowsershellを実行した場合)
PS /home/ubuntu> ps -ejH
(中略)
  433   399   399 ?        00:00:03       sshd
  434   434   434 pts/0    00:00:00         bash
  682   682   434 pts/0    00:00:39           powershell
 2009  2009   434 pts/0    00:00:00             bash
 2019  2019   434 pts/0    00:00:19               powershell
 2060  2019   434 pts/0    00:00:00                 ps
(後略)

しかしながら「Get-Process」を使うと特定のプロセスのProcessオブジェクトを取得した上で、さらにそのプロセスの詳細をメソッドを用いて出力できます。

PS /home/ubuntu> $pro = Get-Process -Name powershell
PS /home/ubuntu> $pro.GetType()

IsPublic IsSerial Name                                     BaseType
-------- -------- ----                                     --------
True     False    Process                                  System.Object


PS /home/ubuntu> $pro.Id
682
PS /home/ubuntu> $pro.Modules

   Size(K) ModuleName                                         FileName
   ------- ----------                                         --------
       100 powershell                                         /opt/microsoft/powershell/6.0.0-alpha.9/powershell
        44 libnss_nis-2.23.so                                 /lib/x86_64-linux-gnu/libnss_nis-2.23.so
        88 libnsl-2.23.so                                     /lib/x86_64-linux-gnu/libnsl-2.23.so
        32 libnss_compat-2.23.so                              /lib/x86_64-linux-gnu/libnss_compat-2.23.so
        92 libresolv-2.23.so                                  /lib/x86_64-linux-gnu/libresolv-2.23.so
        20 libnss_dns-2.23.so                                 /lib/x86_64-linux-gnu/libnss_dns-2.23.so
         8 libnss_mdns4_minimal.so.2                          /lib/x86_64-linux-gnu/libnss_mdns4_minimal.so.2
        44 libnss_files-2.23.so                               /lib/x86_64-linux-gnu/libnss_files-2.23.so
(後略)

さらに「New-Object」などを使うことで.NETのクラスを使用したインスタンスを生成できます。とりあえず「PowerShellはその名の通りかなり強力な言語」ということだけ覚えておいて、詳しいことはPowerShellのドキュメントや各種解説サイトを参照してください。

PowerShellをビルドする

ソースコードが公開されているので、もちろんリポジトリの最新のコードをビルドして試すことも可能です。Ubuntu 14.04 LTSとUbuntu 16.04 LTSのどちらでもビルドできます。PowerShellのビルドには.NET CoreのCLIツールが必要です。こちらもUbuntu用のバイナリが存在します。またビルドシステムはCMakeを使っています。パッケージを作る場合は、Ruby gemのfpmを使用しているようです。

まずはPowerShellのソースコードをクローンします。⁠--recursive」オプションを指定するとsubmoduleも一緒にクローンしてくれるので便利です。ちなみにsubmoduleとして使用しているのは、Google製のC++テストフレームワークであるGoogle TestとPowerShell用のテストフレームワークであるPesterクロスプラットフォーム向けに一時的にフォークしたものの2つです。

$ git clone --recursive https://github.com/PowerShell/PowerShell
$ cd PowerShell/

まずはビルドに必要なパッケージやツールをインストールします。といってもPowerShellのソースコードにはそれを実行するためのPowerShellスクリプトモジュールが存在します。つまりPowerShellをビルドするなら、まずはじめにPowerShellをインストールしておいた方が楽です。もちろんスクリプトモジュールと同じ内容のコマンドを実行すれば、あらかじめPowerShellをインストールする必要はありません。もし、未インストールなら次のスクリプトを実行しましょう。OSに応じて処理が変わるようになっていますが、内容的には本Recipeの前半で説明したことと同じです。

$ ./tools/download.sh

以降はPowerShellを用いたビルド方法を説明します。PowerShellを起動した上で、ソースディレクトリの中で次のコマンドを実行します。

PS /home/ubuntu/src/PowerShell> Import-Module ./build.psm1
PS /home/ubuntu/src/PowerShell> Start-PSBootstrap
Installing PowerShell build dependencies
Submodule path '../src/libpsl-native/test/googletest': checked out 'c99458533a9b4c743ed51537e25989ea55944908'
(後略)

もしくはpowershellコマンドから直接スクリプトモジュールを読み込んで実行する方法でもかまいません。

powershell -noprofile -c "Import-Module ./build.psm1; Start-PSBootstrap"

PowerShellのスクリプトファイルは、拡張子に「.ps1」を指定することが一般的です。それに対して「.psm1」は、他のPowerShellスクリプトから再利用可能なスクリプトや関数の集合体で、⁠Import-Module」で取り込んでからモジュール内の関数を実行します。

「Start-PSBootstrap」関数では、主に以下のような作業を行います。

内部的に「sudo」コマンドを使っているため、必要に応じてパスワード入力が発生します。また、.NET CLI関連は「~/.dotnet/」以下にインストールされます。

$ ls ~/.dotnet/
LICENSE.txt  ThirdPartyNotices.txt  dotnet  host  sdk  shared
$ ~/.dotnet/dotnet --version
1.0.0-preview3-003223

さて、ようやく実際のビルド作業に入ります。こちらもPowerShellスクリプトを実行するだけです。

PS /home/ubuntu/src/PowerShell> Import-Module ./build.psm1
PS /home/ubuntu/src/PowerShell> Start-PSBuild
WARNING: Could not find 'dotnet', appending /home/ubuntu/.dotnet to PATH.
VERBOSE: Using configuration 'Linux'
VERBOSE: Top project directory is /home/ubuntu/src/PowerShell/src/powershell-unix
VERBOSE: Using framework 'netcoreapp1.0'
VERBOSE: Using runtime 'ubuntu.16.04-x64'
Run dotnet restore
(後略)

もしくはpowershellコマンドから直接スクリプトモジュールを読み込んで実行する方法でもかまいません。

powershell -noprofile -c "Import-Module ./build.psm1; Start-PSBuild"

ちなみにPowerShellのソースコードに含まれる、build.shも上記と同じことを実施していますので、何度もビルドを繰り返すならこちらを使うと良いでしょう。

しばらく待てばビルドが完了します。ビルドされたPowerShell本体は以下のパスに存在しますので、実際に起動してみましょう。

$ ./src/powershell-unix/bin/Linux/netcoreapp1.0/ubuntu.16.04-x64/powershell
PS /home/ubuntu/src/PowerShell> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      6.0.0-alpha
PSEdition                      Core
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   3.0.0.0
GitCommitId                    v6.0.0-alpha.9-146-gd57530812e437a5fb265179c89783565d55a2004
CLRVersion
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

パッケージを作りたい場合は、パッケージフラグを有効化した上でStart-PSBootstrapを実行します。これでRubyなどがインストールされます。ただしgemのインストール時にエラーとなってしまうようです。

PS /home/ubuntu/src/PowerShell> Import-Module ./build.psm1
PS /home/ubuntu/src/PowerShell> Start-PSBootstrap -Package
(中略)
ERROR:  While executing gem ... (Gem::FilePermissionError)
    You don't have write permissions for the /var/lib/gems/2.3.0 directory.
(中略)

そこで別途手動でgemをインストールします。ここではsudoを使って/var/lib/gems/以下にインストールしていますが、PowerShellから見える場所であればどこでもかまいません。

$ sudo gem install fpm ronn

gemをインストールできたら、Publishフラグを有効化して再ビルドした上で、Start-PSPackageでパッケージを作成します。なお、再ビルド時に前回ビルドしたpowershell上、つまり「./src/powershell-unix」以下のpowershellで実行しようとするとファイルが使用中のため再ビルドできないので注意してください。

PS /home/ubuntu/src/PowerShell> Start-PSBuild -Publish
PS /home/ubuntu/src/PowerShell> Start-PSPackage
WARNING: Please ensure you have previously run Start-PSBuild -Clean -CrossGen!
WARNING: -Types was not specified, continuing with deb!
WARNING: Building for Ubuntu 16.04!
WARNING: Suffix not given, building primary PowerShell package!
     roff: /home/ubuntu/src/PowerShell/assets/powershell.1


    Directory: /home/ubuntu/src/PowerShell


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
------       2016/08/28      2:35       31632896 powershell_6.0.0-alpha.9-146-gd575308-1ubuntu1.16.04.1_amd64.deb

あとはカレントディレクトリに作られたパッケージファイルを本Recipeの最初に説明した方法でインストールすれば、システムのpowershellが最新版になります。

おすすめ記事

記事・ニュース一覧