みなさんこんにちは!ヒロポンです!!
運用スクリプトのレビューで、こういう行を見たこと、ないですか??
$password = "P@ssw0rd!"
パスワードの平文直書き。
動くには動きます。ただセキュリティ監査で一発で刺されるやつです。しかも Git のコミット履歴に残るから、後から消しても手遅れ。
今日は PowerShell で認証情報を安全に扱うために、実務でよく踏む落とし穴を5つ、実コードでまとめていきます。Get-Credential / SecureString / Export-Clixml の使いどころと、「別マシンで読めない」みたいな業務でハマる制約まで。
💡 この記事は「1人で運用の自動化を回す」シリーズの1本です。CSV から AD ユーザーを一括作成 や イベントログ監視をメール通知 と同じ、無人で回すスクリプトの前提として読んでもらえるはず。
はじめに: なぜこの5つか
認証情報まわりは「暗号化すれば安全」で終わらないのが厄介なところ。
暗号化した瞬間に、「どこで復号できるか」「鍵をどこに置くか」という別の問題が生えてくる。
ここで挙げる5つは、平文をやめた 次に 詰まるやつを順に並べています。特に2番目(別マシンで読めない)と4番目(無人バッチ)は、1人で夜間バッチを回してる現場だと確実に踏む。そこだけでも押さえてください。
⏱ 対処の目安サマリ
| # | 落とし穴 | 対処の目安 |
|---|---|---|
| 1 | パスワードを平文で直書き | 10分(Get-Credential に置換) |
| 2 | Export-Clixml が別マシンで復号できない | 30分(-Key 方式へ設計変更) |
| 3 | -Key の鍵の置き場所が新たな平文問題に | 設計判断(シークレットストア検討) |
| 4 | 無人バッチで Get-Credential が止まる | 1時間(事前 Export or 資格情報マネージャー) |
| 5 | SecureString を過信する | 意識の問題(最小権限とセット) |
1. パスワードを平文でスクリプトに直書きしている
一番多いやつ。動くけど、スクリプトを見た人全員にパスワードが漏れます。
# NG: 平文直書き。コミット履歴にも残る
$password = "P@ssw0rd!"
$secure = ConvertTo-SecureString $password -AsPlainText -Force
# OK: 対話で都度もらう。スクリプトに秘密を残さない
$cred = Get-Credential -UserName "svc_batch" -Message "バッチ実行アカウント"
Get-Credential は、ユーザー名とパスワードを PSCredential オブジェクトで受け取ります。パスワードは中で SecureString として保持されるので、画面にもスクリプトにも平文が出ない。こんな感じで、秘密を手元にベタ書きせずに済みます。
教訓: 平文の文字列は、書いた時点でもう漏れてる。
2. Export-Clixml で保存したら別マシンで復号できない
無人で回したいから、Get-Credential の結果をファイルに保存する。ここまでは正しい。
# 実行アカウントで一度だけ暗号化保存
$cred = Get-Credential
$cred | Export-Clixml -Path "C:\secure\batch-cred.xml"
# 以降のバッチはこれを読むだけ
$cred = Import-Clixml -Path "C:\secure\batch-cred.xml"
問題はここから。
Export-Clixml の SecureString は、既定で Windows の DPAPI で暗号化されます。この暗号化は「保存したユーザー × 保存したマシン」に紐づく。
つまり、この XML を別のサーバーにコピーしても、別のアカウントで実行しても、復号できずに落ちる。
俺も昔、開発機で作った cred.xml を本番サーバーにそのままコピーして、「なんで動かないんだ」と小一時間ハマりました。原因に辿り着くまでずっと復号エラーを睨んでたやつです。「開発機では通るのに本番で落ちる」の正体は、だいたいこれ。
教訓: Export-Clixml の暗号化は、作った本人・そのマシン専用。持ち出せない。
3. -Key で移植できるが、鍵の置き場所が新たな問題になる
マシンを跨ぎたいなら、DPAPI に頼らず AES キーを自分で指定します。
# 32バイトの AES キーを生成
$key = New-Object byte[] 32
[System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($key)
$secure = ConvertTo-SecureString "P@ssw0rd!" -AsPlainText -Force
$encrypted = ConvertFrom-SecureString -SecureString $secure -Key $key
# $key さえあれば、別マシンでも復号できる
$restored = ConvertTo-SecureString -String $encrypted -Key $key
実行結果(同じ $key で暗号化 → 復号して元のパスワードに一致):

-Key を渡すと DPAPI ではなく AES で暗号化されるので、$key を持っていけばどのマシンでも復号できる。いい感じに移植性は出ます。
ただ、ここで一回冷静になってほしいんですよね。じゃあ その $key はどこに置くのか??
スクリプトの隣に鍵ファイルを平文で置いたら、鍵を持ってる人=復号できる人。1番の「平文直書き」に逆戻りです。
教訓: -Key は「パスワードの平文問題」を「鍵の平文問題」にすり替えるだけ。鍵は別レイヤー(資格情報マネージャー等)で守る。
4. 無人バッチで Get-Credential は使えない
タスクスケジューラやサービスで無人実行するスクリプトに Get-Credential を書くと、対話プロンプトを出せずにその場で固まります。
誰も応答できないので、バッチが永遠に待つ。これ、地味に本番で刺さるやつです!!
現実的な落としどころは、だいたいこの3つ。
# 案A: 実行アカウント本人が事前に Export-Clixml しておき、バッチは読むだけ
$cred = Import-Clixml -Path "C:\secure\batch-cred.xml"
Invoke-Command -ComputerName "SRV01" -Credential $cred -ScriptBlock { hostname }
- 案A: 実行アカウントで一度だけ
Export-Clixml(2番の DPAPI 制約は「同じアカウント・同じマシン」で回すなら逆に好都合) - 案B: Windows 資格情報マネージャー(
cmdkeyやSecretManagementモジュール)に預ける - 案C: そもそも専用のサービスアカウント + 最小権限で、パスワードを持ち回らない設計にする
教訓: 無人バッチに対話コマンドを混ぜない。事前準備か、資格情報ストアに寄せる。
5. SecureString を過信する
最後に、これは意識の話。
SecureString にしたから安全、ではないんですよ。
# SecureString も、その気になれば平文に戻せる
$secure = (Get-Credential).Password
$plain = [System.Net.NetworkCredential]::new("", $secure).Password
# → $plain には平文が入る
実行結果(SecureString がしっかり平文に戻る):

復号できる時点で、メモリ上に平文が現れる瞬間はある。SecureString が守ってくれるのは「スクリプトやログに平文をベタ書きしない」ところまで。
教訓: SecureString は気休めではないが万能でもない。最小権限・アクセス制御・定期ローテーションとセットで初めて意味を持つ。
動作確認メモ:
-Keyを使った AES 暗号化・復号(3番)と、SecureString を平文に戻す(5番)は Linux の PowerShell 7 でも実機で確認済みです。一方、Export-Clixmlの DPAPI 暗号化(2番)やGet-Credential・Invoke-Command(1・4番)は Windows 前提の機能なので、実際の挙動は Windows + PowerShell でお試しください。
まとめ: 認証情報の選び方チートシート
どのやり方を選ぶかは、「対話できるか」「同じマシンか」で大体決まります。こんな感じで、フローに落とすと迷わないです。

- 平文直書きは即やめる(
Get-Credential) - 保存は
Export-Clixml。ただし DPAPI は「本人 × マシン」束縛 - マシン跨ぎは
-Key。でも鍵の管理にすり替わる - 無人バッチは事前 Export か資格情報ストア
SecureStringは最小権限とセットで
ここまで押さえておけば、「認証情報の扱いが甘い」でレビューや監査に刺される回数はぐっと減ります。
よくある質問
Q1. PowerShell でパスワードを平文で書かないにはどうすればいいですか?
対話実行なら Get-Credential で都度入力し、スクリプトに平文を残しません。無人バッチなら、実行アカウント本人が一度 Export-Clixml で暗号化保存し、以降は Import-Clixml で読み込みます。平文の文字列をスクリプトに直書きするのは避けます。
Q2. Export-Clixml で保存した認証情報が別のマシンで読めないのはなぜですか?
Export-Clixml の SecureString は既定で Windows の DPAPI で暗号化され、保存したユーザーとマシンに紐づくためです。別マシンや別アカウントでは復号できません。マシンを跨ぐ場合は ConvertFrom-SecureString の -Key で AES キーを明示します。
Q3. 無人のタスクスケジューラで Get-Credential は使えますか?
使えません。対話プロンプトを表示できない実行文脈では Get-Credential は止まります。実行アカウントで事前に Export-Clixml しておくか、Windows 資格情報マネージャーや SecretManagement モジュール、専用サービスアカウントを検討します。
Q4. -Key を使えば安全ですか?
-Key はマシンを跨いで復号できるようにするための仕組みで、それ自体がセキュリティを保証するわけではありません。鍵ファイルを平文で近くに置けば、鍵を持つ人は誰でも復号できます。鍵は資格情報マネージャーや専用のシークレットストアなど、別のレイヤーで保護します。
Q5. SecureString ならメモリ上も完全に安全ですか?
いいえ。SecureString は復号できる以上、平文がメモリに現れる瞬間があります。守れるのは「スクリプトやログに平文を残さない」ところまでです。最小権限とアクセス制御、定期的なローテーションと組み合わせて使います。
次に読むべき記事




以上!
執筆者
バイブス父さん — 業務 SE 7 年 (SIer 正社員 2 / フリーランス 5)。 現職は SEO 直轄部の AI アドバイザー兼 PL、 副業で中小 SIer の CTO。 SIer の正社員からフリーランスに転じ、 複数のエージェント経由で案件を回してきた経験ベースで「業務 SE 視点」 の技術 + キャリア記事を書いています。
🐦 X: @hiro_progra0524 (日々の現場メモ更新中)
📝 About Me で経歴詳細を見る



