[Code Runner]UTF-8 BOM付きのPowerShellスクリプトを実行する設定
概要
Markdownファイル内のコード内容だけで正常動作するか検証したく、VS Codeに拡張機能のCode Runnerを導入しました。
実際に複数行のPowerShellコードを範囲選択して動かしてみると、文字化けしてエラーが発生してしまいました。
今回、この問題を解決する方法が見つかったので紹介します。
この記事のターゲット
- VS Codeユーザーの方
- Code Runnerについて知りたい方
- Code RunnerでPowerShell実行時に文字化けしてエラーが発生する問題を解決したい方
環境
Windows & PowerShell
PowerShell Coreをインストール済み。
PS C:\Users\XXXX> $PSVersionTable
Name Value
---- -----
PSVersion 7.3.8
PSEdition Core
GitCommitId 7.3.8
OS Microsoft Windows 10.0.19045
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0…}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
PS C:\Users\XXXX>
- PowerShell OS別のダウンロードリンク・インストール方法のリスト
https://github.com/PowerShell/PowerShell#get-powershell
VS Code
code -v
PS C:\Users\XXXX> code -v
1.83.1
f1b07bd25dfad64b0167beb15359ae573aecd2cc
x64
PS C:\Users\XXXX>
Code Runner
code --list-extensions --show-versions
PS C:\Users\XXXX> code --list-extensions --show-versions
formulahendry.code-runner@0.12.1
~ 省略 ~
PS C:\Users\XXXX>
なぜCode Runnerを導入したのか
冒頭でも記載していますが、Markdown内で書いたコードの動作検証を簡略化したくなり導入しました。
この記事を投稿しているプラットフォームZenn.devではMarkdown記法を使用しています。
Markdownファイル内にプログラムコードを書いた後、そのコードが正常に動くか検証する為、
対応する言語ファイル(たとえばPowerShellスクリプトの場合、*.ps1
)を個別に書き出した後、実行していました。
一度で動作検証が終われば良いですが試行錯誤すると、どうしても何度も繰り返して作業する事になり、
個別に書き出して実行する事が面倒に感じていました。
ネットで探してみると、VS Codeの拡張機能であるCode Runnerを使用する事で、
マウス・キーボードで範囲選択したコードだけの実行する事ができるとの事で導入しました。
- Code Runner
Code Runner | Visual Studio Marketplace
VS Code 拡張機能 - 識別子:formulahendry.code-runner
実際に動かしてみるとエラーが発生
Code Runnerを使い動かしてみた結果、範囲選択したコードの実行でエラーが発生しました。
エラー内容をみると文字化けしている事がわかります。
画像:範囲選択したコードの実行でエラー
[Running] powershell -ExecutionPolicy ByPass -File "C:\Users\ADMINI~1\AppData\Local\Temp\tempCodeRunnerFile.ps1"
�����ꏊ C:\Users\Administrator\AppData\Local\Temp\tempCodeRunnerFile.ps1:21 ����:39
+ [System.String]$prompt_message = '参�Eするフォルダーを�E力してください、E
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
���܂��̓X�e�[�g�����g�̃g�[�N�� '参�Eするフォルダーを�E力してください、E' ���g�p�ł��܂���B
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
[Done] exited with code=1 in 3.738 seconds
-
範囲選択したコード実行(Select Language To Run)
ショートカットキー [Ctrl + Alt + J
]
実行したい部分を範囲選択してショートカットキーを入力。表示された言語のリストの中から“powershell”を選択すると実行できた。
画像:Code Runnerの範囲選択したコードを実行するモードで表示される言語リスト
詳細情報:範囲選択で実行したコード < クリックで折りたたみが開く >
#################################################################################
# 処理名 |InputForm
# 機能 |対象フォルダーを指定する入力フォーム
#--------------------------------------------------------------------------------
# 戻り値 |Boolean(True: OKボタン、False: OKボタン以外)
# 引数 |target_folder: 対象フォルダー
#################################################################################
Function InputForm {
Param (
[System.String]$target_folder
)
# アセンブリ読み込み(フォーム用)
Add-Type -AssemblyName System.Windows.Forms
Add-Type -AssemblyName System.Drawing
[System.String[]]$input_parameters = @()
# フォームの作成
[System.String]$prompt_title = 'タイトル:対象フォルダーを入力'
[System.String]$prompt_message = '参照するフォルダーを入力してください。'
[System.Windows.Forms.Form]$form = New-Object System.Windows.Forms.Form
$form.Text = $prompt_title
[System.UInt32[]]$form_size = @(550, 300)
$form.Size = New-Object System.Drawing.Size($form_size[0],$form_size[1])
$form.StartPosition = 'CenterScreen'
$form.MaximizeBox = $false
$form.MinimizeBox = $false
[System.String]$font_family = 'MS ゴシック'
[System.Int32]$font_size = 12
# ラベル作成
[System.Windows.Forms.Label]$label = New-Object System.Windows.Forms.Label
$label.Location = New-Object System.Drawing.Point(20, 20)
$label.Size = New-Object System.Drawing.Size(350, 50)
$label.Text = $prompt_message
[System.Drawing.Font]$font = New-Object System.Drawing.Font($font_family, $font_size)
$label.Font = New-Object System.Drawing.Font($font_family, $font_size)
# テキストボックスの作成
[System.Windows.Forms.TextBox]$textbox = New-Object System.Windows.Forms.TextBox
$textbox.Location = New-Object System.Drawing.Point(40, 80)
# 100の場合
$textbox.Size = New-Object System.Drawing.Size(350, 100)
$textbox.Text = $target_folder
$textbox.Font = New-Object System.Drawing.Font($font_family, $font_size)
# 参照ボタンの作成
[System.Windows.Forms.Button]$btnRefer = New-Object System.Windows.Forms.Button
$btnRefer.Location = New-Object System.Drawing.Point(420, 80)
$btnRefer.Size = New-Object System.Drawing.Size(75,25)
$btnRefer.Text = '参照'
# OKボタンの作成
[System.Windows.Forms.Button]$btnOkay = New-Object System.Windows.Forms.Button
$btnOkay.Location = New-Object System.Drawing.Point(355, 210)
$btnOkay.Size = New-Object System.Drawing.Size(75,30)
$btnOkay.Text = 'OK'
$btnOkay.DialogResult = [System.Windows.Forms.DialogResult]::OK
# Cancelボタンの作成
[System.Windows.Forms.Button]$btnCancel = New-Object System.Windows.Forms.Button
$btnCancel.Location = New-Object System.Drawing.Point(440,210)
$btnCancel.Size = New-Object System.Drawing.Size(75,30)
$btnCancel.Text = 'キャンセル'
$btnCancel.DialogResult = [System.Windows.Forms.DialogResult]::Cancel
# ボタンの紐づけ
$form.AcceptButton = $btnOkay
$form.CancelButton = $btnCancel
# フォームに紐づけ
$form.Controls.Add($label)
$form.Controls.Add($textbox)
$form.Controls.Add($btnRefer)
$form.Controls.Add($btnOkay)
$form.Controls.Add($btnCancel)
# フォーム表示
[System.Boolean]$is_Selected = ($form.ShowDialog() -eq [System.Windows.Forms.DialogResult]::OK)
$form = $null
return $is_Selected
}
# 実行
InputForm 'D:\Downloads'
- Code Runnerを導入し始めたMarkdownファイルの記事
こちらの記事の内容にあるコードで実際に動作するプログラムなのかCode Runnerで確認しました。
https://zenn.dev/haretokidoki/articles/a95255bdb31ad3
補足情報:Code Runnerでアクティブファイルを実行するモードあり
ちなみにCode Runnerでは範囲選択したコードの実行だけでなく、アクティブファイルを実行できるモードもあります。
試しに実行していみるとアクティブファイルがMarkdownファイル(拡張子は*.md
)だった為、、Code language not supported or defined.
というメッセージが出ました。
Markdownファイルはプログラム実行用の形式ではないので想定通り実行できませんでした。
-
コードの実行(Run Code)
ショートカットキー [Ctrl + Alt + N
] -
実行結果
画像:メッセージ“Code language not supported or defined.”
Code Runnerでは初期設定されている主流の言語以外にも個別に追加する事が可能です。
- Code Runnerで動作させる言語を個別に追加する方法
https://qiita.com/take_me/items/6a1d2d417889837219d1#私の言語が対応していませんが
範囲選択の実行で発生した文字化け表示とエラーの対応
Code Runnerの出力先をターミナルに設定(必須作業)
調べた結果、こちらで紹介されているCode Runnerの出力先をターミナルに変更する事で、
文字化けが解消されたという記事が見つかりました。
以下が詳しい設定方法です。
- VS Codeの設定画面を開く
ショートカットキー操作 :Ctrl + ,(カンマ)
画面操作 :ファイル(F)
→ユーザー設定(P)
→設定(S)
を選択 - 設定で検索欄で
code-runner run in terminal
と入力 - 設定項目「
Code-runner: Run In Terminal
」をチェックする
画像:Code Runnerの設定で「Code-runner: Run In Terminal」にチェックを入れた状態
設定変更後、文字化けの度合いは少なくなったように見えるが、状況は変わらず文字化けとエラーが発生。
画像:出力からターミナルに変更して選択範囲のコードを実行するも文字化けとエラーが発生
PS C:\Users\Administrator> powershell -ExecutionPolicy ByPass -File "c:\Users\Administrator\Downloads\tempCodeRunnerFile.ps1"
発生場所 C:\Users\Administrator\Downloads\tempCodeRunnerFile.ps1:21 文字:39
+ [System.String]$prompt_message = '蜿ら・縺吶k繝輔か繝ォ繝繝シ繧貞・蜉帙@縺ヲ縺上□縺輔>縲・
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
式またはステートメントのトークン '蜿ら・縺吶k繝輔か繝ォ繝繝シ繧貞・蜉帙@縺ヲ縺上□縺輔>縲・' を使用できません。
+ CategoryInfo : ParserError: (:) [], ParentContainsErrorRecordException
+ FullyQualifiedErrorId : UnexpectedToken
PS C:\Users\Administrator>
- 参考情報:Code Runnerの出力先をターミナルに設定する方法
https://beiyan-tool.info/?p=962
変わらず文字化けとエラーが発生しましたが最終的な結果、ここでの「 出力先をターミナルに設定 」 と 後述する「 Code RunnerでPowerShellの個別設定を追加 」 の2件あわせて対応した事により解決しました。
その為、ここで対応した「 出力先をターミナルに設定 」はそのままの状態で次項の作業に移ってください。
調査方法(私の環境で通常とは異なる点を洗い出し)
ネットの情報を元に一般的な環境と私の環境で異なる部分をあらためて洗い出した結果、
一般的な環境と違う点は、PowerShellスクリプトファイルをUTF-8 BOM付きで保存しているという点でした。
-
一般的な環境
通常PowerShellスクリプトは文字コードがUTF-8の環境で動作する -
私の環境の場合
マルチバイト(日本語)を含む文字列を取り扱う為、PowerShellスクリプトファイル(*.ps1)をUTF-8 BOM付きで保存している。補足情報:なぜUTF-8 BOMで保存した方がよいのか < クリックで折りたたみが開く >
今回、作成したPowerShellスクリプトは、ASCII文字以外(つまり日本語)が含まれている。
PowerShellでは、ASCII文字以外の文字列が含まれていると自動的にANSI(日本語版Windows OSであれば、Shift-JISの事を指す)として処理され文字化けする。メッセージ内容の文字化けぐらいであれば動作に問題はないが、文字化けの度合いによっては動作しない場合もある。
上記の回避策として日本語を含むPowerShellスクリプトは、文字コードを“UTF-8 BOM付き”で保存する事により、
文字コードのデータがファイルに付与され文字化けやエラーがなく動作する。- 参考情報:なぜUTF-8 BOMで保存した方がよいのか
- Visual Studio CodeでPowerShellスクリプトが文字化けする時の対処法
https://ygkb.jp/17519 - Microsoft公式:バイトオーダーマーク BOM について(日本語)
https://learn.microsoft.com/ja-jp/powershell/module/microsoft.powershell.core/about/about_character_encoding?view=powershell-7.3#the-byte-order-mark - Microsoft公式:バイトオーダーマーク BOM について(英語)
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_character_encoding?view=powershell-7.3#the-byte-order-mark
- Visual Studio CodeでPowerShellスクリプトが文字化けする時の対処法
- 参考情報:なぜUTF-8 BOMで保存した方がよいのか
この事をふまえてCode Runnerで実行される一時ファイル「tempCodeRunnerFile.ps1
」を確認すると文字コードが「UTF-8」である事が判明。
原因
PowerShellの仕様動作から見ると、マルチバイト(日本語)がないPowerShellはUTF-8で正常動作する。
しかし、今回のコードではコメント行やフォームの設定値などで日本語があった。
通常はマルチバイトを含むPowerShellスクリプトはUTF-8 BOM付きで保存し実行する事で正常動作するが、
今回のCodeRunner経由での実行では、拡張機能が実行する為の一時ファイルの文字コードがUTF-8(BOMなし)だった。
CodeRunnerで実行した際、BOM情報がなくPowerShell側で文字コードが判別できなかった事と、
マルチバイトの文字(日本語)が含まれていた事でPowerShellが自動でShift-JISとして実行されてしまった為、文字化けが発生。
最終的にエラーが発生してしまったという事がわかった。
文字だけだとわかりにくいと思うので箇条書きにすると下記の流れでエラーが発生していた事がわかる。
- Markdownファイル内のコードを範囲選択してCode Runnerで実行
範囲選択したコードには、日本語が含まれた状態 - (Code Runnerで自動)で範囲選択部分を抜き出し UTF-8 のps1ファイルを生成
- (Code Runnerで自動)生成したps1ファイルをPowerShellで実行
- (PowerShellで自動)BOM付きでないので文字コードが判別できないが日本語を含むps1ファイルである為 Shift-JIS で実行
-
<< エラーが発生 >>
文字コード UTF-8のps1ファイルをShift-JISとして実行してしまった為 、日本語が文字化けしエラーが発生
Code RunnerでPowerShellの個別設定を追加(必須作業)
Code Runnerの設定でPowerShellを実行する際に個別の処理を追加する。
具体的に追加する内容は下記の通り。
- Code Runner実行時にターミナルで動作するよう変更
前述に記載した必須作業が実施済みである事。 - 実行時、一時的に作成されるファイルをUTF-8 BOM付きに変換
一時的に作成されるUTF-8のファイル「tempCodeRunnerFile.ps1
」
上記をUTF8 BOMに変換したファイル 「tempCodeRunnerFile_utf8bom.ps1
」
なお、変換したファイルの保存先は一時フォルダー「$Env:TEMP
(C:\Users\ユーザー名\AppData\Local\Temp
) 」に保存する。 - 変換後、Code Runnerで一時的に作成されたUTF-8のファイルを削除
- UTF-8 BOMに変換したファイルをPowerShellで実行
settings.jsonにおける実際の設定作業
-
VS Codeの設定画面を開く
ショートカットキー操作 :Ctrl + ,(カンマ)
画面操作 :ファイル(F)
→ユーザー設定
→設定 Ctrl + ,
を選択 -
設定で検索欄で
code-runner executor map
と入力 -
設定項目
Code-runner: Executor Map
にあるリンク「settings.jsonで編集
」をクリックCode-runner: Executor Map の「 settings.jsonで編集 」による変化点 < クリックで折りたたみが開く >
Code-runner{ "python.linting.flake8Enabled": true, "editor.fontFamily": "'BIZ UDゴシック', Consolas, 'Courier New', monospace", "extensions.ignoreRecommendations": true, "[python]": { "editor.formatOnType": true }, "code-runner.runInTerminal": true + "code-runner.executorMap": { + + "javascript": "node", + "java": "cd $dir && javac $fileName && java $fileNameWithoutExt", + "c": "cd $dir && gcc $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", + "zig": "zig run", + "cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", + "objective-c": "cd $dir && gcc -framework Cocoa $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", + "php": "php", + "python": "python -u", + "perl": "perl", + "perl6": "perl6", + "ruby": "ruby", + "go": "go run", + "lua": "lua", + "groovy": "groovy", + "powershell": "powershell -ExecutionPolicy ByPass -File", + "bat": "cmd /c", + "shellscript": "bash", + "fsharp": "fsi", + "csharp": "scriptcs", + "vbscript": "cscript //Nologo", + "typescript": "ts-node", + "coffeescript": "coffee", + "scala": "scala", + "swift": "swift", + "julia": "julia", + "crystal": "crystal", + "ocaml": "ocaml", + "r": "Rscript", + "applescript": "osascript", + "clojure": "lein exec", + "haxe": "haxe --cwd $dirWithoutTrailingSlash --run $fileNameWithoutExt", + "rust": "cd $dir && rustc $fileName && $dir$fileNameWithoutExt", + "racket": "racket", + "scheme": "csi -script", + "ahk": "autohotkey", + "autoit": "autoit3", + "dart": "dart", + "pascal": "cd $dir && fpc $fileName && $dir$fileNameWithoutExt", + "d": "cd $dir && dmd $fileName && $dir$fileNameWithoutExt", + "haskell": "runghc", + "nim": "nim compile --verbosity:0 --hints:off --run", + "lisp": "sbcl --script", + "kit": "kitc --run", + "v": "v run", + "sass": "sass --style expanded", + "scss": "scss --style expanded", + "less": "cd $dir && lessc $fileName $fileNameWithoutExt.css", + "FortranFreeForm": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", + "fortran-modern": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", + "fortran_fixed-form": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", + "fortran": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", + "sml": "cd $dir && sml $fileName", + "mojo": "mojo run" + } }
-
settings.jsonでpowershellの欄を個別に変更する
UTF-8 BOMの変換処理を追加したsettings.json{ // ~ 省略 ~ // "code-runner.runInTerminal": true, "code-runner.executorMap": { "javascript": "node", "java": "cd $dir && javac $fileName && java $fileNameWithoutExt", "c": "cd $dir && gcc $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "zig": "zig run", "cpp": "cd $dir && g++ $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "objective-c": "cd $dir && gcc -framework Cocoa $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "php": "php", "python": "python -u", "perl": "perl", "perl6": "perl6", "ruby": "ruby", "go": "go run", "lua": "lua", "groovy": "groovy", - "powershell": "powershell -ExecutionPolicy ByPass -File", // Windows標準のPowerShell 5.1.x の場合 + "powershell": "cd $dir && Get-Content -Encoding utf8BOM .\\$fileName | Out-File -Encoding utf8BOM $Env:TEMP\\tempCodeRunnerFile_utf88BOM.ps1 && Remove-Item .\\$fileName -Force && powershell -ExecutionPolicy ByPass -File $Env:TEMP\\tempCodeRunnerFile_utf88BOM.ps1", // PowerShell Core の場合(私の場合、7.3.8) + "powershell": "cd $dir && Get-Content -Encoding utf8BOM .\\$fileName | Out-File -Encoding utf8BOM $Env:TEMP\\tempCodeRunnerFile_utf88BOM.ps1 && Remove-Item .\\$fileName -Force && pwsh -ExecutionPolicy ByPass -File $Env:TEMP\\tempCodeRunnerFile_utf88BOM.ps1", "bat": "cmd /c", "shellscript": "bash", "fsharp": "fsi", "csharp": "scriptcs", "vbscript": "cscript //Nologo", "typescript": "ts-node", "coffeescript": "coffee", "scala": "scala", "swift": "swift", "julia": "julia", "crystal": "crystal", "ocaml": "ocaml", "r": "Rscript", "applescript": "osascript", "clojure": "lein exec", "haxe": "haxe --cwd $dirWithoutTrailingSlash --run $fileNameWithoutExt", "rust": "cd $dir && rustc $fileName && $dir$fileNameWithoutExt", "racket": "racket", "scheme": "csi -script", "ahk": "autohotkey", "autoit": "autoit3", "dart": "dart", "pascal": "cd $dir && fpc $fileName && $dir$fileNameWithoutExt", "d": "cd $dir && dmd $fileName && $dir$fileNameWithoutExt", "haskell": "runghc", "nim": "nim compile --verbosity:0 --hints:off --run", "lisp": "sbcl --script", "kit": "kitc --run", "v": "v run", "sass": "sass --style expanded", "scss": "scss --style expanded", "less": "cd $dir && lessc $fileName $fileNameWithoutExt.css", "FortranFreeForm": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "fortran-modern": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "fortran_fixed-form": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "fortran": "cd $dir && gfortran $fileName -o $fileNameWithoutExt && $dir$fileNameWithoutExt", "sml": "cd $dir && sml $fileName", "mojo": "mojo run" } // ~ 省略 ~ // }
設定変更後に範囲選択で実行した結果
「 出力先をターミナルに設定 」と 「 Code RunnerでPowerShellの個別設定を追加 」
画像:Code Runnerの個別実行が正常動作してWindowsフォームが表示
参考情報
- Code Runner 全体的な説明
https://qiita.com/take_me/items/6a1d2d417889837219d1 - Code Runner 実行すると文字化けしてエラーが表示される場合
https://beiyan-tool.info/?p=962 - Code Runner 拡張子ごとの個別設定で参考
https://dianxnao.com/visual-studio-codeでc言語プログラミングを始める(windows編)/#toc8 - PowerShell Get-Contentコマンドでエンコード
https://www.ipentec.com/document/powershell-get-content-specify-encoding - PowerShell Out-Fileコマンド
https://hardsofttalk.seesaa.net/article/202106article_1.html - PowerShell 一時フォルダーの場所を取得
https://www.tekizai.net/entry/powershell_TemporaryFile
まとめ
- Code Runner を導入する事で選択範囲のコードのみ実行する事が可能
- Code Runner では拡張子(言語)毎に実行コマンドを変更する事が可能
- 今回検証したPowerShellスクリプトでは日本語が含まれていた事によりPowerShellで自動的にShift-JISとして処理され文字化けとエラーが発生していた
- Code Runner で実行時に生成される一時ファイルをUTF-8 BOMに変換する事で正常動作した
関連記事
Discussion