Add-VpnConnection で PowerShell から VPN プロファイルをインポートする
Add-VpnConnection は Windows ネイティブのプロファイルしか作成しません。トンネルと認証の組み合わせをゲートウェイに合わせ、スコープを意図的に決めてから、ルートと DNS を検証します。
Import-VpnProfile というコマンドレットは存在せず、最も近い Add-VpnConnection も .ovpn や .conf ファイルを読むことはありません。渡したパラメーターから Windows ネイティブのプロファイルを組み立てるため、ここでの最初の確認点はコマンドラインではなくファイル形式です。ゲートウェイが SSTP、IKEv2、L2TP/IPsec、PPTP のいずれかに対応していれば、Windows がプロファイルを所有でき、リストの残りが当てはまります。OpenVPN や WireGuard のファイルを渡された場合、それらのクライアントは自前のインポーターを持っているので、最初の手順で止めてください。
手順 1: Windows が実際に所有できるプロファイルを確認する
何よりも先に、マシン上で Get-Command -Module VpnClient を実行してください。Windows 10、Windows 11、Server 2016 以降にはこのモジュールが含まれ、欠けている場合、コピーしたスクリプトではこのホストにネイティブプロファイルを受け入れさせられません。重要なコマンドレットは Add-VpnConnection、Get-VpnConnection、Remove-VpnConnection で、Add-VpnConnection のリファレンス のパラメーター一覧は一度全文に目を通す価値があります。
ネイティブとは、Windows の VPN スタックがトンネルを終端するという意味です。これには IKEv2(多くの場合マシン証明書を使用)、内部でユーザー認証または証明書認証を行う TLS である SSTP、事前共有キーを使う L2TP/IPsec が含まれます。.ovpn ファイルは OpenVPN のスクリプトであり Windows の接続ではなく、remote、cipher、tls-auth といった Windows スタックには存在しない概念のディレクティブを含みます。WireGuard の .conf も PrivateKey と AllowedIPs を伴う同じ話で、一方をもう一方に変換するのはパラメーターの選択ではなく別のトンネル実装です。
第三の分岐もあります。管理者から VPNv2 CSP の XML ドキュメントや Intune プロファイルを渡された場合、それは MDM の経路であり、Add-VpnConnection ではなくプロビジョニング スタックが適用します。それらのノード名を PowerShell のパラメーターに翻訳せず、代わりにどの仕組みが XML を適用するのかを尋ねてください。
手順 2: トンネルの種類と認証方法を組み合わせる
-TunnelType と -AuthenticationMethod は別々のパラメーターで、ゲートウェイが見るのは組み合わせだけです。片方が正しく片方が間違っていれば、どこにも接続しないプロファイルか、トンネルが上がったまま停止するプロファイルになります。別のサービス向けに選ばれた既定値に頼らず、両方を明示的に設定してください。
- IKEv2 と MachineCertificate ではクライアントがコンピューター証明書を提示するので、-EncryptionLevel Required も設定します。
- SSTP と Eap ではまず TLS トンネルを張り、その内側で PEAP/MSCHAPv2 または証明書を使います。これには手順 3 の XML が必要です。
- SSTP、L2TP、PPTP と MSChapv2、Chap、Pap の組み合わせは、ユーザー名とパスワードのみで、EAP ブロブは不要です。
- L2TP と MSChapv2、および -Lt2pPsk では、PSK が IPsec 側を、ユーザーが PPP 側を担い、どちらもサーバーと一致する必要があります。
splat を使えば値が一か所にまとまります:
$p = @{
Name = "Corp IKEv2"
ServerAddress = "vpn.example.com"
TunnelType = "Ikev2"
AuthenticationMethod = "MachineCertificate"
EncryptionLevel = "Required"
SplitTunneling = $false
DnsSuffix = "corp.example.com"
}
Add-VpnConnection @p -PassThru-PassThru は Windows が書き込んだオブジェクトをそのまま返すので、二度目の呼び出しなしで確認できます。名前が既に存在するとコマンドレットは実行を拒否し、-Force は上書きしますが、誰かが手作業で設定した内容を黙って捨ててしまうため、実運用のノート PC では誤った反射です。
手順 3: 資格情報の素材を正しく渡す
パスワード、事前共有キー、EAP ブロブは、これらのスクリプトがたいてい壊れる箇所です。-EapConfigXmlStream が求めるのは XmlDocument でありパスではないので、まずファイルを読み込んで変換します。文字列を渡すとスキーマの問題に見える変換エラーになり、決して間違っていなかった XML を書き直す羽目になります。
$eap = [xml](Get-Content -Raw .\peap-mschapv2.xml)
Add-VpnConnection -Name "Corp SSTP" -ServerAddress "sstp.example.com" `
-TunnelType Sstp -AuthenticationMethod Eap `
-EapConfigXmlStream $eap -EncryptionLevel Requiredその XML はブログの断片から作るものではありません。EAP 方式の種類と内部認証を指定し、ゲートウェイはその両方を自社ポリシーと照合します。一致しない内部方式は TLS ハンドシェイク完了後に失敗し、これは誤ったパスワードとまったく同じに見えますが、そうではありません。XML はゲートウェイを運用している人から受け取るか、既に動作しているプロファイルからエクスポートしてください。
IKEv2 では証明書側はストアの検索です。-MachineCertificateIssuerFilter は証明書オブジェクトを受け取り、Windows はそれを使って LocalMachine\My 内の使用可能なクライアント証明書を探します。証明書には秘密キーとサーバーが信頼するチェーンが必要で、どちらかが欠けると認証は有益な情報なしに失敗するため、まずストアを確認します:
Get-ChildItem Cert:\LocalMachine\My |
Where-Object { $_.HasPrivateKey -and $_.NotAfter -gt (Get-Date) } |
Select-Object Subject, Issuer, Thumbprint, NotAfter秘密情報はスクリプト ファイルの外に置きます。コマンドラインで渡した PSK や .ps1 に埋め込んだ PSK は、トランスクリプト、保存されたセッション、共有リポジトリに残り、また -RememberCredential はユーザー資格情報を後日のためにキャッシュして、一度きりのテストを持続的な許可に変えてしまいます。
手順 4: 最初の実行前にスコープを決める
同じコマンドレットが二つの異なる電話帳に書き込みます。-AllUserConnection を付けなければプロファイルは自分のもので、%APPDATA%\Microsoft\Network\Connections\Pbk\rasphone.pbk の下に置かれます。付けた場合、昇格したプロンプトから、プロファイルは %ProgramData%\Microsoft\Network\Connections\Pbk\rasphone.pbk に置かれ、サインイン画面を含むすべてのアカウントから見えます。
スコープは見た目の問題ではありません。全ユーザー プロファイルは、サービス アカウント、スケジュールされたタスク、サインイン前のシナリオが使えるもので、ユーザーごとのプロファイルはその三つすべてから見えません。オブジェクトの読み方も異なり、Get-VpnConnection は現在のユーザーのエントリを、Get-VpnConnection -AllUserConnection はマシン全体のエントリを一覧します。どちらかを今選び、後からの変更は編集ではなく削除と再作成として扱ってください:
# elevated prompt
Remove-VpnConnection -Name "Corp IKEv2" -Force
Add-VpnConnection -Name "Corp IKEv2" -ServerAddress "vpn.example.com" `
-TunnelType Ikev2 -AuthenticationMethod MachineCertificate `
-EncryptionLevel Required -AllUserConnection手順 5: トンネルが実際に提供すべきものを検証する
接続済みのアイコンが証明するのはトンネルが上がったことだけで、それ以上ではありません。まずコマンドラインから接続し、失敗がダイアログではなくテキストで返るようにしてから、Windows が記録した内容を読み返します:
rasdial "Corp IKEv2"
Get-VpnConnection -Name "Corp IKEv2" |
Select-Object Name, ServerAddress, TunnelType, ConnectionStatus, SplitTunneling
Get-NetRoute -DestinationPrefix "0.0.0.0/0"状態がまだ Connected と表示されているのにユーザーが報告する二つの不具合は、DNS とルーティングです。内部名を解決してどのサーバーが応答したかを確認しますが、-DnsSuffix のないプロファイルはトンネル自体は完璧でも、イントラネットの検索はすべて失敗します。次に既定ルートを確認します: スプリット トンネリングが無効なら、メトリックが最小の 0.0.0.0/0 ルートが VPN インターフェイスを指すはずで、有効なら想定したプレフィックスだけが指すはずです。両方とも正しく見えるのに通信が死ぬなら、問題はプロファイルの外、ポリシーかゲートウェイのフィルターにあります。
接続がまったく失敗する場合、コードが戻るべき手順を絞り込みます:
- 691: ゲートウェイが資格情報を拒否しました。トンネルではなく手順 3 に戻ってください。
- 809: IKEv2 のハンドシェイクが完了していません。UDP 500 と 4500、および証明書の信頼を確認してください。
- 789: L2TP/IPsec の事前共有キーが欠けているか誤っています。
- 868: サーバー名が解決できませんでした。プロファイルを編集する前に DNS を直してください。
動作するコマンドは、それが符号化している設定の隣に置いて、次の担当者が UI からプロファイルを逆解析するのではなく再構築できるようにしてください。どうしても再構築するなら、中途半端に構成されたプロファイルにパッチを当てると古いルートと認証状態が残るため、エントリを削除して同じパラメーターで作り直してください。そしてファイルがそもそもネイティブでなかったなら、それを所有するクライアントに戻ってください。IKEv2 プロファイルの装いをした .ovpn はインポートではなく、サポート チケットです。