動くコード図鑑技術記事現場の渡り方キャリア論すべての記事About
技術記事

PowerShell で認証情報を安全に扱う — パスワード平文直書きをやめる(SecureString / Export-Clixml)

バイブス父さん
現役の業務SE
2026年9月14日12 min read広告 (PR) を含む場合があります
PowerShell で認証情報を安全に扱う — パスワード平文直書きをやめる(SecureString / Export-Clixml)

みなさんこんにちは!ヒロポンです!!

運用スクリプトのレビューで、こういう行を見たこと、ないですか??

$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-ClixmlSecureString は、既定で 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 を使った AES 暗号化と復号の往復が成功した実行結果

-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 資格情報マネージャー(cmdkeySecretManagement モジュール)に預ける
  • 案C: そもそも専用のサービスアカウント + 最小権限で、パスワードを持ち回らない設計にする

教訓: 無人バッチに対話コマンドを混ぜない。事前準備か、資格情報ストアに寄せる。

5. SecureString を過信する

最後に、これは意識の話。

SecureString にしたから安全、ではないんですよ。

# SecureString も、その気になれば平文に戻せる
$secure = (Get-Credential).Password
$plain = [System.Net.NetworkCredential]::new("", $secure).Password
# → $plain には平文が入る

実行結果(SecureString がしっかり平文に戻る):

SecureString を NetworkCredential 経由で平文に復元した実行結果

復号できる時点で、メモリ上に平文が現れる瞬間はある。SecureString が守ってくれるのは「スクリプトやログに平文をベタ書きしない」ところまで。

教訓: SecureString は気休めではないが万能でもない。最小権限・アクセス制御・定期ローテーションとセットで初めて意味を持つ。

動作確認メモ: -Key を使った AES 暗号化・復号(3番)と、SecureString を平文に戻す(5番)は Linux の PowerShell 7 でも実機で確認済みです。一方、Export-Clixml の DPAPI 暗号化(2番)や Get-CredentialInvoke-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-ClixmlSecureString は既定で 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 で経歴詳細を見る


この記事のコードと手順は ぜんぶ動作検証済み。 安心して現場で試してくれ。
バイブス父さん

現役の業務SE。C# / SQL Server 保守の現場から、コードも人もキャリアも全部書く。 実体験ベース。

運営者について