LoginSignup
3
6

More than 5 years have passed since last update.

PowerShell で ANSI escape sequences を表示する

Posted at

背景

PowerShell 上で Packer や Terraform を使うとき、出力に ANSI escape sequences が含まれるがデフォルトコンソールではこれを解釈できません。ツール側で色付けを無効化(例: Packer の PACKER_NO_COLOR=true や Terraform の -no-color)すれば回避できますが、せっかくなら色付きで出力して欲しいです。

方法1 : ansicon を使う

ansicon は元々 cmd.exe 向けの ANSI escape sequences を表示するためのアプリケーションです。コマンドプロンプトから ansicon と入力すると、 ansicon を経由した cmd.exe が立ち上がり、ANSI escape sequences を解釈してくれるようになります。これを PowerShell で使います。

ansicon サンプル

※サンプルの ANSI Prompt Colours.txtこちらの ANSI Prompt Colours (25k) です。

インストール

choco install ansicon

または GitHub からバイナリをダウンロードして適当な場所に置いてください。

使い方

ansicon powershell

で ansicon 経由で powershell が起動できます。

ansicon サンプル on PowerShell

ただし、見ての通り Dark Yellow が白に、 Dark Magenta が背景色になっており、おかしいです。直し方は今のところ分かっていません。

NVIDIA のビデオカードを使用していてエラーが出る場合

NVIDIA のドライバと競合します。回避するためには環境変数に以下を追加します。

ANSICON_EXC=nvd3d9wrap.dll;nvd3d9wrapx.dll

一時的に環境変数に追加した場合は以下の通りです。

$env:ANSICON_EXC = "nvd3d9wrap.dll;nvd3d9wrapx.dll"

これを設定しない場合、例えば posh-git で git.exe を呼び出そうとしたときに git.exe がフリーズします。

方法 2 : コンソールエミュレータを使う

以下のような高機能コンソールエミュレータは ANSI escape sequences を解釈してくれます。他にもいろいろな機能があるので、普通はこっちの方法で解決するのがお勧めだと思います。私はデフォルトのコンソールが使いたいのと、コンソールエミュレータは重いので前述の ansicon を必要に応じて使っています。

  - ConEmu
  - ConsoleZ

なお、Console2 のように ANSI escape sequences に対応していないコンソールエミュレータでも、前述の ansicon と組み合わせれば対応可能です(参考)。

方法 3 : PowerShell スクリプトでなんとかする

原始的な方法ですが PowerShell スクリプトで正規表現などを用いて ANSI escape sequences を PowerShell での色表現に置き換えれば外部アプリケーションを用いずに対応できるはずです。実際にやっている人がいました

ちょっとだけ手直ししたコードを以下に記載します。

Write-ColoredHost.ps1
function global:Write-ColoredHost
{
    Param(
        [switch]$noNewLine,
        [String]$separator=" ",
        [System.ConsoleColor]$foregroundColor = $Host.UI.RawUI.ForegroundColor,
        [System.ConsoleColor]$backgroundColor = $Host.UI.RawUI.BackgroundColor
    )
    BEGIN {
        $fgc, $bgc = $foregroundColor, $backgroundColor
    }
    PROCESS {
        $token, $coloredTokens = $_ -split "\e\["
        Write-Host $token `
                   -noNewLine -separator $separator `
                   -foregroundColor $fgc `
                   -backgroundColor $bgc
        foreach ($coloredToken in $coloredTokens) {
            $colorCodes, $token = $coloredToken -split "m", 2
                $colorCodes -split ";" | foreach-object {
                    switch -regex ($_) {
                        "^0{1,2}$" { $fgc, $bgc = $foregroundColor, $backgroundColor }
                        "^30$"     { $fgc       = "Black"                            }
                        "^31$"     { $fgc       = "Red"                              }
                        "^32$"     { $fgc       = "Green"                            }
                        "^33$"     { $fgc       = "Yellow"                           }
                        "^34$"     { $fgc       = "Blue"                             }
                        "^35$"     { $fgc       = "Magenta"                          }
                        "^36$"     { $fgc       = "Cyan"                             }
                        "^37$"     { $fgc       = "White"                            }
                        "^39$"     { $fgc       = $foregroundColor                   }
                        "^40$"     {       $bgc =                   "Black"          }
                        "^41$"     {       $bgc =                   "Red"            }
                        "^42$"     {       $bgc =                   "Green"          }
                        "^43$"     {       $bgc =                   "Yellow"         }
                        "^44$"     {       $bgc =                   "Blue"           }
                        "^45$"     {       $bgc =                   "Magenta"        }
                        "^46$"     {       $bgc =                   "Cyan"           }
                        "^47$"     {       $bgc =                   "White"          }
                        "^49$"     {       $bgc =                   $backgroundColor }
                    }
                }
            Write-Host $token `
                       -noNewLine -separator $separator `
                       -foregroundColor $fgc `
                       -backgroundColor $bgc
        }
        if (!$noNewLine) { Write-Host }
    }
}

これを適当なフォルダに置いて

.\Write-ColoredHost.ps1
Get-Content '.\ANSI Prompt Colours.txt' | Write-ColoredHost

のようにすると色付きで表示されます。ただし、一部の ANSI escape sequences にしか対応していないため「とりあえず近い色が付く」程度のものになっています。

Write-ColoredHost サンプル

PowerShell にこの関数を組み込みたい場合はこのあたりを参考にしてください。

3
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
6