「サーバー移行のタイミングで、20年もののバッチファイルが山ほど出てきた。これ、全部PowerShellに書き直すべきでしょうか」── レガシー資産の相談で、この質問は定番です。コピーとバックアップ、アプリ起動のラッパー、夜間の連携ジョブ。cmdのバッチ(bat)は今もWindows運用の現場を静かに支えています。
結論を先に言えば、全部書き直す必要はありません。batが今すぐ動かなくなる予定はなく、動いているものを書き換えること自体が障害リスクだからです。一方で、「そのまま」が危ないbatも確実に存在します。VBScriptを呼んでいるもの、エラーを握り潰しているもの、これから変更が入るもの。この見極めをせずに「全部残す」も「全部移行」も、どちらも事故のもとです。
この記事では、中小企業の情シスや運用担当者を対象に、bat資産の棚卸しと移行判断の基準、bat特有の落とし穴、移行期にbatとPowerShellを共存させる書き方、書き換えの対応表までを整理します。
1. まず結論
- cmd.exeとbatに廃止予定はありませんが、MicrosoftはWindowsの自動化にPowerShellの使用を推奨すると明言しています。新規に書くならPowerShell、が公式の方向性です。1
- VBScriptは2023年10月に非推奨が正式発表され、要求時インストール(Feature on Demand)化を経てOSから削除される段階的計画が公開されています。batから
cscript/wscriptでVBScriptを呼んでいる資産は、移行必須度が最も高いグループです。23 代替としてはPowerShellが公式に案内されています。4 - 移行判断は「全部」ではなく仕分けです。安定稼働中で変更予定なし→残す。変更が入る・エラー処理が必要・ログが必要→移行。VBScript依存→優先的に移行。第4章の判断表で整理します。
- batの構造的な弱点は、エラーで止まらないこと、
%ERRORLEVEL%の罠、文字コードです。if errorlevel 1は「1以上」の判定であり5、%errorlevel%は同名の環境変数を定義すると壊れます。5 - PowerShellに移行して得られるのは、オブジェクトパイプライン、try/catchによるエラー処理6、-WhatIfによる予行演習7、Pesterによるテストです。「失敗に気づける・安全に試せる・自動でテストできる」が移行の本質的な価値です。
- 混在期は、batからpowershell.exe / pwshを
-Fileで呼ぶのが現実解です。スクリプトのexitが返す終了コードはbat側の%ERRORLEVEL%にそのまま渡るため、既存のジョブ管理を保ったまま中身を置き換えられます。89 - robocopyのような優秀な外部コマンドは書き換えず、PowerShellからそのまま呼びます。終了コードは0〜8以上で、8以上が失敗という独特の体系なので、
$LASTEXITCODEでの判定だけ正しく書きます。1011 - 配布時は実行ポリシーを設計に含めます。既定はWindows PowerShell 5.1のクライアントOSではRestricted(スクリプト実行不可)、Windows ServerとPowerShell 7ではRemoteSignedです。RemoteSignedでもネット由来マークの付いた未署名スクリプトはブロックされます。12
2. なぜ今考えるのか ── cmdは残る、VBScriptは消える
まず前提の事実関係を整理します。Windowsのコマンドラインシェルにはcmd(コマンドシェル)とPowerShellの2系統があり、Microsoftの公式ドキュメントは「最も堅牢で最新のWindows自動化には、WindowsコマンドやWindows Script HostではなくPowerShellの使用を推奨する」と明記しています。1 ただし推奨はあくまで推奨で、cmd自体はWindowsの非推奨機能一覧に載っていません。既存のbatが動かなくなる予定は、現時点でありません。
対照的なのがVBScriptです。2023年10月、VBScriptの非推奨(deprecation)が正式に発表されました。今後のWindowsリリースでは要求時インストールの機能(Feature on Demand)として提供され、その後OSから削除される計画が公開されています。2 当初はプリインストールされた状態で提供されるため今日明日に止まるわけではありませんが3、方向は「削除」で確定しています。Windows Server 2025でも同様にFoD化されており、代替としてPowerShellへの移行が公式に案内されています。4
ここで重要なのは、bat資産の中にVBScriptが隠れていることです。batから cscript //nologo convert.vbs のようにVBScriptを呼び出す構成は、2000年代の定番パターンでした。この構成のbatは「batだから安全」ではなく「VBScriptと運命共同体」です。棚卸しでは、batファイルそのものに加えて、batが呼んでいる先を必ず確認してください(第7章にスキャン用スクリプトを載せます)。社内のVBScript・VBA資産全体の点検は「VBScript廃止に備えるVBA・社内ツール点検ガイド」で詳述しています。
3. batの落とし穴と、PowerShellで得られるもの
移行判断の材料として、batの構造的な弱点を具体的に見ます。次のバッチは、バックアップ処理としてよく見る形です。
@echo off
rem 夜間バックアップ(ありがちな危ういバッチ)
xcopy C:\data \\backup01\share\data /E /Y
echo バックアップ完了 >> C:\logs\backup.log
このバッチには、気づきにくい問題が3つ埋まっています。
- エラーでも止まりません。xcopyが共有先に届かず失敗しても、cmdは既定で次の行へ進み、ログには「バックアップ完了」と記録されます。失敗の検知には毎回
if errorlevelの判定を自分で書く必要があります。 %ERRORLEVEL%には罠があります。if errorlevel 1は「終了コードが1と等しい」ではなく「1以上」の判定です。5 また%errorlevel%という書き方は「ERRORLEVELという環境変数が定義されていなければ現在の終了コードに展開される」仕様なので、誰かがset ERRORLEVEL=0と書いた瞬間、以後の判定はすべて壊れます。5exit /b 数値で終了コードを返す仕様13と合わせて、正しく書くには相応の知識が要ります。- 文字コードの事故。日本語環境のcmdは伝統的にShift_JIS系の世界で、UTF-8で保存し直したbatが化ける・記号入りパスで誤動作する、という事故は今も起きます。この問題の全体像は「Windowsの文字コードと改行コード - 文字化けとCRLF/LFの基本」を参照してください。
同じ処理をPowerShellで書くと、失敗の扱いが構造的に変わります。
# 夜間バックアップ(PowerShell版の骨格)
$ErrorActionPreference = 'Stop' # エラーを「止まる」側に倒す
try {
# コピー元は「フォルダーの中身」を指す C:\data\* にする。'C:\data' を渡すと、
# コピー先フォルダーが既に存在する2回目以降は data\data と入れ子になってしまう
Copy-Item -Path 'C:\data\*' -Destination '\\backup01\share\data' -Recurse -Force
Add-Content -Path 'C:\logs\backup.log' -Value "$(Get-Date -Format o) バックアップ完了"
exit 0
}
catch {
# 何が・どこで失敗したかを構造化された情報のまま記録できる
Add-Content -Path 'C:\logs\backup.log' -Value "$(Get-Date -Format o) 失敗: $($_.Exception.Message)"
exit 1
}
try/catch は文を終了させるエラーを捕捉し、後始末は finally に書けます。6 さらにPowerShellには、破壊的な操作を実行せず「何が起きるはずだったか」だけを表示する -WhatIf が共通の仕組みとして用意されており7、書き換えたスクリプトを本番相手に安全に予行演習できます。加えてPesterでテストを書けば、「動くはず」を自動で確認し続けられます(「PesterによるPowerShellのテスト整備 ── 運用スクリプトを壊しにくくする実務の型」参照)。エラー処理と再実行の設計自体は、同時公開の「PowerShellのエラー処理と再実行設計」で深掘りしています。
つまり移行で得られるのは構文の新しさではなく、失敗に気づける・安全に試せる・テストで守れるという運用品質です。逆に言えば、失敗してもすぐ分かる単純な起動ラッパーのようなbatには、この価値はあまり効きません。だから仕分けが必要になります。
4. 全部移行しない ── 仕分けの判断表
| 論点 | 選択肢 | 判断の目安 |
|---|---|---|
| 安定稼働中・変更予定なし・単純 | そのまま残す / 移行 | アプリ起動ラッパーや数行のコピーは残してよい。書き換え自体が新規リスク |
| VBScript(cscript/wscript)を呼んでいる | 残す / 優先的に移行 | VBScriptは非推奨→FoD→削除の計画が公式発表済み。放置の先に廃止日が来る2 |
| これから仕様変更・機能追加が入る | batのまま改修 / 移行してから改修 | 変更のタイミングが移行の好機。改修とテスト整備を同時にやる |
| 失敗検知・ログ・リトライが必要 | batに判定を足す / 移行 | if errorlevelの網羅は保守困難。try/catchと構造化ログが効く領域6 |
| 夜間ジョブ(タスクスケジューラ起動) | 現状維持 / 移行を検討 | 無人実行こそ失敗の扱いが命。実行アカウントや0x1問題も合わせて見直す |
| robocopy等の外部コマンドが主役 | コマンドレットで再実装 / 外部コマンドは残して呼ぶ | 実績あるコマンドの再実装は損。呼び出しと判定だけPowerShellにする10 |
| 書いた本人が退職済み・仕様不明 | 触らない / 挙動を記録してから判断 | まず現状の入出力とスケジュールを文書化。不明なまま書き換えない |
迷ったときの原則は2つです。第一に、移行は「価値が出る順」であり「古い順」ではないこと。第二に、触るなら読み取り(棚卸しと記録)から始めることです。
5. 混在期の現実解 ── batからPowerShellを呼び、終了コードを受け渡す
仕分けの結果、多くの現場は「一部はbatのまま、一部はPowerShell」という混在期に入ります。このとき便利なのが、batを入口(ジョブ管理との接点)として残し、中身だけPowerShellにする構成です。ジョブスケジューラや運用手順書はbatのパスを見続けるので、周辺を壊さずに中身を近代化できます。
@echo off
rem 入口bat: 同じフォルダのjob.ps1を呼び出し、終了コードを引き継ぐ
rem %~dp0はこのbat自身のあるフォルダ(公式ドキュメントにも載っている定石)
rem 誰かがset ERRORLEVEL=...した環境変数が残っていると%ERRORLEVEL%が
rem 本物の終了コードを隠すため、呼び出し前に消して動的な値に戻しておく
rem 実行ポリシーはここで上書きしない。-ExecutionPolicy指定は優先度の高い
rem Processスコープになり、管理者が構成したAllSigned等を黙って弱めてしまう
set "ERRORLEVEL="
powershell.exe -NoProfile -File "%~dp0job.ps1"
exit /b %ERRORLEVEL%
カレントディレクトリに依存せず %~dp0 でスクリプトの場所を解決する書き方は、公式ドキュメントがbatからの呼び出し例として示しているものです。9 PowerShell 7で動かすなら powershell.exe を pwsh に変えるだけです(5.1と7は別々にインストールされ共存できます。使い分けは同時公開の「Windows PowerShell 5.1とPowerShell 7の違いと移行」参照)。
終了コードの受け渡しは次のとおり整理できます。
- スクリプトが
exit 4で終わると、プロセスの終了コードが4になり、bat側の%ERRORLEVEL%で受け取れます。この連携は公式ドキュメントに実例つきで記載されています。8 -Fileで呼んだ場合、スクリプトが未処理の例外で死ぬと終了コードは1、正常終了なら0です。「失敗したのに0」を避けるため、スクリプト側では成否を判定して明示的にexitするのが安全です。914- PowerShellから外部コマンドを呼んだ結果は、自動変数
$LASTEXITCODEに入ります。11
robocopyを主役にしたbatは、この形の好例です。robocopyはリトライ(既定でなんと100万回・待機30秒)やミラーリング、ログ機能を持つ実績あるコマンドで10、Copy-Itemで再実装する理由はありません。ただし終了コードの体系が独特で、0は「コピー対象なし」、1が「正常にコピー」、8以上が失敗です。10 「0以外は異常」という一般則で判定すると、正常なコピーを異常と誤判定します。
# robocopyはそのまま使い、判定だけPowerShellで正しく行う
# /r:2 /w:5 ── 既定のリトライ100万回は無人ジョブでは事実上のハングになるため必ず絞る
robocopy 'C:\data' '\\backup01\share\data' /MIR /R:2 /W:5 /NP /LOG+:'C:\logs\robocopy.log'
if ($LASTEXITCODE -ge 8) {
Write-Error "robocopyが失敗しました(終了コード: $LASTEXITCODE)"
exit 1
}
Write-Host "同期完了(終了コード: $LASTEXITCODE)" # 0〜7は成功系
exit 0
6. 書き換え対応表 ── batの語彙をPowerShellへ
実際に書き換えるときの対応表です。機械的な置換ではなく「同じ意図をどう表現するか」の対照表として使ってください。
| batの書き方 | PowerShellでの定石 | 補足 |
|---|---|---|
copy / move / del / md |
Copy-Item / Move-Item / Remove-Item / New-Item |
破壊的操作はまず -WhatIf を付けて予行演習7 |
xcopy / robocopy |
robocopyをそのまま呼ぶ | 再実装しない。$LASTEXITCODE で8以上を失敗と判定1011 |
for %%f in (*.csv) do ... |
Get-ChildItem *.csv \| ForEach-Object { ... } |
ファイル名の文字列ではなくオブジェクトが流れる |
if errorlevel 1 goto :error |
try/catch + $ErrorActionPreference = 'Stop' |
外部コマンドは従来どおり終了コード判定6 |
set VAR=value |
$var = 'value'(環境変数は $env:VAR) |
プロセス環境変数と変数を区別できる |
call :sub / goto |
function |
引数に型と検証を付けられる |
findstr |
Select-String |
一致行がオブジェクトで返り、後段で加工できる |
>> log.txt |
Start-Transcript / Add-Content |
実行記録の丸ごと採取はTranscriptが手軽 |
rem |
# |
─ |
PowerShell側の基本語彙(コマンドレットの探し方、パイプライン、確認の作法)は「PowerShellコマンドの基本 ── まず覚える操作と安全な使い方」にまとめています。
7. 段階的移行の手順 ── 棚卸し→分類→パイロット→並行稼働
最後に、進め方を4段階に整理します。
(1) 棚卸し。まず読み取り専用の調査から始めます。batの所在と、VBScript依存の有無を機械的に洗い出します。
# bat資産の棚卸し: 所在一覧と、VBScript呼び出しの検出(読み取りのみの安全な調査)
# 列挙できなかった場所は棚卸しの穴になるため、-ErrorVariableで記録して後で開示する
$targets = Get-ChildItem -Path 'C:\', 'D:\jobs', '\\fileserver\scripts' -Recurse `
-Include '*.bat', '*.cmd' -File -ErrorAction SilentlyContinue -ErrorVariable enumErrors
$readErrors = @()
$report = foreach ($file in $targets) {
# cscript/wscript/.vbsの呼び出しがあれば「VBScript依存」として要注意フラグ
# 列挙済みのパスは-LiteralPathで渡す([2026]job.batのような角かっこ入りの
# ファイル名を-Pathに渡すとワイルドカード解釈されて別ファイルを見てしまう)
# ロック中などで中身を読めなかったファイルも$readErrorsに記録する
$vbs = Select-String -LiteralPath $file.FullName -Pattern 'cscript|wscript|\.vbs' -Quiet `
-ErrorAction SilentlyContinue -ErrorVariable +readErrors
[pscustomobject]@{
Path = $file.FullName
LastWriteTime = $file.LastWriteTime
UsesVBScript = $vbs
}
}
$report | Sort-Object UsesVBScript -Descending | Export-Csv 'C:\audit\bat-inventory.csv' -NoTypeInformation -Encoding UTF8
# 調べられなかった場所を一覧に残す(空でなければ棚卸しは不完全)
# 列挙に失敗した場所と、列挙できたが中身を読めなかったファイルの両方を含める
@($enumErrors) + @($readErrors) | ForEach-Object { $_.TargetObject } |
Set-Content -Path 'C:\audit\bat-uninspected.txt'
(2) リスク分類。棚卸し結果を第4章の判断表に当てはめ、「残す」「移行」「優先移行(VBScript依存)」に仕分けます。あわせて、各batの起動元(タスクスケジューラ、ジョブ管理ツール、人手)と失敗時の影響範囲を記録します。夜間ジョブの実行アカウントや「0x1で終わる」問題は「タスクスケジューラのタスクが実行されない・0x1で終わる ── 原因の切り分けと安全な運用設計」を参照してください。
(3) パイロット。影響の小さい1本を選び、第5章の入口bat方式で書き換えます。このとき実行ポリシーを設計に含めます。Windowsの既定はRemoteSignedで、ローカル作成のスクリプトは動きますが、インターネット由来のマークが付いた未署名スクリプトはブロックされます。12 共有フォルダ配布で引っかかる場合の切り分けと、署名運用まで含めた本筋の設計は、同時公開の「PowerShellの実行ポリシーとスクリプト署名」にまとめています。
(4) 並行稼働。旧batと新スクリプトを一定期間並走させます。書き込み先を分けて出力を突き合わせる、新側は最初 -WhatIf やログのみで走らせる、切り戻しはジョブの向き先をbatに戻すだけにしておく ── ここまで仕込んでから旧batを退役させれば、移行そのものが事故になることはまずありません。
8. まとめ
- cmdとbatに廃止予定はありませんが、公式の推奨はPowerShellです。一方VBScriptは非推奨→FoD→削除の計画が発表済みで、batから呼ばれているVBScriptが最優先の移行対象です。
- 移行は「全部」ではなく仕分けです。安定稼働・変更なしのbatは残し、変更が入るもの・エラー処理とログが必要なもの・VBScript依存のものから移行します。
- batはエラーで止まらず、
if errorlevel 1は1以上判定、%errorlevel%は同名環境変数で壊れます。PowerShellはtry/catch・-WhatIf・Pesterで「気づける・試せる・守れる」を提供します。 - 混在期は入口batから
powershell.exe -File(またはpwsh -File)を呼び、exitと%ERRORLEVEL%で終了コードを受け渡すのが現実解です。 - robocopyのような優秀な外部コマンドは書き換えず、
$LASTEXITCODEの判定(8以上が失敗)だけ正しく書きます。 - 手順は棚卸し(読み取りから)→リスク分類→パイロット→並行稼働。実行ポリシーと配布の設計も忘れずに。
関連記事
- VBScript廃止に備えるVBA・社内ツール点検ガイド
- PowerShellコマンドの基本 ── まず覚える操作と安全な使い方
- タスクスケジューラのタスクが実行されない・0x1で終わる ── 原因の切り分けと安全な運用設計
- Windowsの文字コードと改行コード - 文字化けとCRLF/LFの基本
- PowerShellの実行ポリシーとスクリプト署名
- PowerShellのエラー処理と再実行設計
関連する相談領域
合同会社小村ソフトでは、bat・VBScript・PowerShellが混在したレガシー資産の棚卸しと移行計画の策定、夜間ジョブのPowerShell化と運用設計、移行に伴う不具合の調査を扱っています。「書いた人がもういない」バッチの解読からでもご相談いただけます。
参考リンク
-
Microsoft Learn, Windows Commands. Windowsにコマンドシェル(cmd)とPowerShellの2つのシェルがあること、最も堅牢で最新のWindows自動化にはWindowsコマンドやWindows Script HostではなくPowerShellの使用を推奨するという公式記述について。 ↩ ↩2
-
Microsoft Learn, Deprecated features for Windows client. VBScriptの非推奨が2023年10月に発表されたこと、今後のWindowsリリースでFeature on Demandとして提供された後にOSから削除される計画であることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, Resources for deprecated features. VBScriptのFeature on Demandが当初はプリインストールされ、退役準備の間は中断なく使用できることについて。 ↩ ↩2
-
Microsoft Learn, Features removed or no longer developed in Windows Server. Windows Server 2025でVBScriptがFoDとして提供され後のリリースで削除されること、タスク自動化やスクリプトの代替としてPowerShellの使用が案内されていることについて。 ↩ ↩2
-
Microsoft Learn, if. if errorlevel
が「直前のプログラムの終了コードがnumber以上のときに真」という以上判定であること、%errorlevel%がERRORLEVELという環境変数が存在しない前提の展開であり、同名の環境変数が定義されているとその値が返ることについて。 ↩ ↩2 ↩3 ↩4 -
Microsoft Learn, about_Try_Catch_Finally. try/catch/finallyブロックが文終了エラーとスクリプト終了エラーを処理すること、catchで例外型を指定できること、finallyがエラーの有無にかかわらず実行され後始末に使えることについて。 ↩ ↩2 ↩3 ↩4
-
Microsoft Learn, about_CommonParameters. システムやデータに変更を加えるコマンドレットが提供するリスク軽減パラメーター(-WhatIf/-Confirm)、-WhatIfがコマンドを実行せず影響の説明だけを表示することについて。 ↩ ↩2 ↩3
-
Microsoft Learn, about_Language_Keywords. exitキーワードが$LASTEXITCODEを設定し、cmd.exe側では%ERRORLEVEL%に対応すること、pwsh -Fileで実行したスクリプトのexit 4が呼び出し元の%ERRORLEVEL%で4として観測される実例、exit文が無い場合は正常終了で0・未処理例外で1になることについて。 ↩ ↩2
-
Microsoft Learn, about_Pwsh. pwshの-Fileパラメーターの使い方、バッチスクリプトから呼ぶ際に%~dp0で実行ディレクトリを表す公式の例、-Fileでスクリプト終了エラーが起きた場合に終了コードが1になること、exitコマンドで終了した場合はその数値が終了コードになることについて。 ↩ ↩2 ↩3
-
Microsoft Learn, robocopy. robocopyの終了コード体系(0=コピー対象なし、1=全ファイルを正常コピー、8以上=1件以上の失敗)、リトライ既定値が/r:1000000(100万回)・待機既定値が/w:30秒であること、ミラーリングやログなどのオプションについて。 ↩ ↩2 ↩3 ↩4 ↩5
-
Microsoft Learn, about_Automatic_Variables. 自動変数$LASTEXITCODEにネイティブプログラムやスクリプトの終了コードが格納されること、-Fileでのスクリプト実行時の値の決まり方(例外で1、exit指定値、正常終了で0)について。 ↩ ↩2 ↩3
-
Microsoft Learn, about_Execution_Policies. Windowsの既定の実行ポリシーがRemoteSignedであること、RemoteSignedがインターネット由来のスクリプトに信頼された発行元の署名を要求し、ローカルで作成したスクリプトには署名を要求しないこと、各ポリシー(Restricted/AllSigned/Bypass等)の意味について。 ↩ ↩2
-
Microsoft Learn, exit. exit /b
がバッチスクリプトを終了しERRORLEVEL環境変数に指定値を設定すること、cmd自体を終了する場合はプロセス終了コードに設定されることについて。 ↩ -
Microsoft Learn, about_PowerShell_exe. Windows PowerShell 5.1のpowershell.exeにおける-Fileパラメーターの仕様、cmd.exeから環境変数を渡す場合の%windir%構文、終了コードの扱いについて。 ↩
関連する記事
同じタグを共有する最新の記事です。さらに近い話題で知識を深められます。
PowerShellスクリプトの引数設計とモジュール化 ── 「動くスクリプト」から「人に渡せるスクリプト」へ
PowerShellスクリプトを他人に渡せる品質に引き上げる実務手順を整理します。paramブロックと[CmdletBinding()]による高度な関数化、型指定とMandatory、ValidateSetなどの入力検証、パイプライン入力、コメントベースヘルプ、-WhatI...
Windows PowerShell 5.1とPowerShell 7の違い ── 社内スクリプト移行の実務ガイド
Windows PowerShell 5.1とPowerShell 7の関係(共存・powershell.exeとpwsh.exe)、5.1は新機能追加なしという公式方針、既定エンコーディング差による文字化け、互換機能の制約、#Requiresでの防御、タスクスケジューラ更...
PowerShellからCOMと.NETを呼ぶ実践 ── スクリプトの届く範囲を一気に広げる
PowerShellから.NETクラスを直接呼ぶ方法([型]::メソッド、New-Object、[型]::new())、Add-TypeによるC#コードとWin32 API(P/Invoke)の組み込み、New-Object -ComObjectでのCOM操作、Excel....
PowerShellでの資格情報の安全な扱い ── 平文パスワードをスクリプトから追放する
PowerShellスクリプトに埋め込まれた平文パスワードを安全な保管へ移行する実務手順を整理します。Get-CredentialとPSCredential、SecureStringの実像と限界、Export-ClixmlによるDPAPI保存が同一ユーザー・同一マシン限定で...
PowerShellでファイルサーバーを棚卸しする ── 容量調査とアクセス権(ACL)監査
PowerShellでファイルサーバーを棚卸しする実務手順。容量調査とアクセス拒否の記録、古いファイル一覧と重複候補のハッシュ抽出、Get-Aclによる権限監査と継承切れの検出、CSVレポート化、icaclsとの使い分け、Set-Aclの安全な変更手順まで整理します。
関連トピック
このテーマと近いトピックページです。記事を起点に、関連するサービスや他の記事へ進めます。
Windows技術トピック
Windows 開発、不具合調査、既存資産活用の技術トピックをまとめた入口です。
このテーマがつながるサービス
この記事は次のサービスページにつながります。近い入口からご覧ください。
Windowsアプリ開発
業務アプリ、装置連携、通信ツールなどの Windows ソフト開発を支援します。
既存資産活用・移行支援
COM / ActiveX / OCX、32bit / 64bit 制約を抱える既存資産の活用と移行を支援します。
よくある質問
この記事のテーマについて、相談時によくある質問をまとめています。
- 社内のバッチファイルはすべてPowerShellに移行すべきですか?
- 全部移行は推奨しません。何年も安定稼働していて変更予定のないバッチは、書き換え自体が新しい障害リスクになります。移行の優先度が高いのは、これから変更が入るもの、エラー処理やログが必要なもの、そしてVBScript(cscript/wscript)を呼んでいるものです。判断表で仕分けて、価値のあるものから段階的に移行するのが実務の定石です。
- cmd.exeやバッチファイルは廃止されるのですか?
- cmd.exeはWindowsの非推奨機能一覧に載っておらず、廃止のアナウンスはありません。ただしMicrosoftはWindowsの自動化にはコマンドやWSHではなくPowerShellの使用を推奨すると明言しています。一方VBScriptは2023年10月に非推奨が正式発表され、今後のWindowsでは要求時インストールの機能(Feature on Demand)になった後、OSから削除される段階的な計画が公開されています。batそのものは動き続けますが、batから呼んでいるVBScriptは確実に動かなくなる日が来ます。
- batファイルからPowerShellスクリプトを呼ぶにはどう書けばよいですか?
- powershell.exe(またはPowerShell 7のpwsh.exe)に-Fileパラメーターでスクリプトを渡します。batと同じフォルダのスクリプトなら「powershell.exe -NoProfile -File "%~dp0job.ps1"」のように%~dp0で場所を解決するのが公式ドキュメントにも載っている書き方です。なお-ExecutionPolicy指定は優先度の高いProcessスコープになり、管理者が構成したポリシーを弱めてしまうため、bat側では付けず環境側の実行ポリシー設計に従わせます。スクリプト側でexit 数値を返せば、bat側の%ERRORLEVEL%にそのまま渡るため、既存のジョブ管理の仕組みを保ったまま中身だけPowerShell化できます。
- batの%ERRORLEVEL%にはどんな罠がありますか?
- 代表的なのは「if errorlevel 1」が『終了コードが1以上なら真』という以上判定である点です(等値判定ではありません)。また%errorlevel%は環境変数ERRORLEVELが定義されていない前提の動的展開なので、set ERRORLEVEL=0のように自分で定義してしまうと以後は常にその値が返ります。さらにbatはコマンドが失敗しても既定では次の行へ進むため、判定を書き忘れた失敗は静かに握り潰されます。この種の罠の少なさが、エラー処理を持つPowerShellへ移行する動機になります。
- robocopyを使っているバッチはPowerShellでどう書き換えますか?
- 書き換えないのが定石です。robocopyはリトライ・ミラーリング・ログなど実績のある機能を持つ優秀な外部コマンドで、PowerShellからそのまま呼べます。Copy-Itemで再実装するのは手間の割に信頼性が下がります。注意点は終了コードの解釈で、robocopyは0〜8以上の値を返し、8以上が失敗、1は正常なコピー完了です。PowerShell側では$LASTEXITCODEを見て「8以上なら異常」と判定します。
- PowerShellスクリプトの配布で実行ポリシーに引っかかりました。どうすべきですか?
- 実行ポリシーの既定(RemoteSigned)は、インターネット由来のマーク付きスクリプトに署名を要求します。共有フォルダ経由の配布でブロックされる場合、まず原因を確認し、恒久策としては署名運用か、グループポリシーでの統一が本筋です。バッチからの呼び出しで-ExecutionPolicy Bypassを付ける方法は手軽ですが、組織のポリシー設計として意図した状態か確認した上で使ってください。
著者プロフィール
記事の著者プロフィールページです。
小村 豪
合同会社小村ソフト 代表
Windows ソフト開発、技術相談、不具合調査を中心に、既存資産が残る案件や原因が見えにくい障害調査に強みがあります。
公開リンク