Microsoft Print to PDF (redirected)でPrintToFile=trueがXPSになる原因と回避策(RDP/.NET PrintDocument)

リモートデスクトップ(RDP)環境で「Microsoft Print to PDF (redirected)」へ PrintToFile=true を指定して自動保存しようとすると、拡張子は .pdf なのにAcrobatで開けず、実はXPSの中身が出力されている――そんな現象に遭遇することがあります。この記事では原因を仕組みから解きほぐし、要件別の現実的な回避策まで具体的に整理します。

目次

現象:.pdf ファイルは作成されるのにPDFとして開けない

ローカルPCで「Microsoft Print to PDF」に対しては、PrintDocument と PrintToFile=true の組み合わせで問題なくPDFが生成できるのに、RDPセッション上で「Microsoft Print to PDF (redirected n)」を対象にすると次のような症状が出ます。

  • .pdf 拡張子のファイルは作成される
  • Acrobat Reader などのPDFビューアで開けない(破損扱い)
  • テキストエディタで先頭を見ると PK で始まっている
  • 拡張子を .xps に変えるとXPSビューアで普通に開ける

まず切り分けとして「そのファイルは本当にPDFか?」を、ファイル先頭(マジックナンバー)で確認すると腹落ちします。

形式先頭付近の典型例意味今回の現象との関係
PDF%PDF-1.4 などPDFはほぼ必ず %PDF- で始まるこの文字列が無いならPDFではない可能性が高い
XPSPK(ZIPのヘッダ)XPSはZIPコンテナ(中にXMLやリソースを格納)PK が見えたら「XPS(またはZIP系)」を疑う

前提:RDPの「Microsoft Print to PDF (redirected)」は“サーバーのPDFプリンタ”ではない

ここが一番の落とし穴です。RDPセッションで見える「Microsoft Print to PDF (redirected n)」は、見た目はPDFプリンタですが、実体は次の意味になります。

  • あなたのローカルPCに存在するプリンタ(この場合「Microsoft Print to PDF」)が、RDPのプリンタリダイレクト機能でサーバー側に“転送されて見えている”状態
  • サーバー側にローカルのプリンタを“それっぽく”見せるために、間にRemote Desktop Easy Print(Easy Print)が入ることが多い

つまり、RDPセッション上の「redirected」は、サーバーが本来持っている「Microsoft Print to PDF」そのものではなく、クライアント側プリンタへ印刷データを運ぶための仕組みが絡んだ“別物”です。

原因:Remote Desktop Easy Print が「中間形式としてXPS」を出力している

結論から言うと、RDPのリダイレクト印刷で Easy Print が使われている場合、サーバー側では「最終的なPDF」を作っていません。サーバー側で生成しているのは、クライアントへ送るための中間フォーマット(XPS)です。

印刷の流れを、実務的に必要な粒度で分解するとこうなります。

  1. サーバー(RDPセッション)上でアプリが印刷を開始 アプリは「Microsoft Print to PDF (redirected n)」に印刷しているつもりでも、実際にはサーバーの印刷スプーラは「リダイレクト用のキュー」として処理します。
  2. Easy Print ドライバが印刷データをXPSへ“整形” Easy Print は「クライアント側にどんなプリンタドライバが入っていても印刷できる」ことを優先するため、サーバー側でいったん印刷ジョブをXPSにします。XPSはZIPベースなので、ファイル先頭が PK になります(.docx/.xlsx と同じ“ZIPコンテナ”の仕組み)。
  3. XPSがクライアント側へ転送され、クライアント側で最終レンダリング 通常のリダイレクト印刷では、このXPSがクライアントへ渡り、クライアント側の実プリンタ(ここではローカルの「Microsoft Print to PDF」)が“最終的な出力(PDF化)”を担当します。

つまり、RDPセッション側の段階では「PDF化」していないのが本質です。

なぜ PrintToFile=true で「XPSが.pdfとして保存」されるのか

ここも重要ポイントです。PrintToFile は「プリンタドライバが出力したデータ(またはスプールデータ)をファイルとして保存する」系の動きになります。

ローカルの「Microsoft Print to PDF」相手なら、ドライバが生成するものがPDFなので、結果としてPDFが保存されます。しかし、RDPリダイレクトで Easy Print が間に入ると、サーバー側でドライバ(Easy Print)が吐いているのはPDFではなくXPSです。

  • ローカル:プリンタドライバの最終出力=PDF → ファイルに保存してもPDF
  • RDP(redirected):Easy Print の出力=XPS → ファイルに保存するとXPS(拡張子だけ.pdf)

結果として「.pdf という名前のXPS」ができ、Acrobatは開けず、拡張子を .xps に変えると開ける、という現象になります。

再現しやすいコード例(PrintDocument)と“静音化”の注意点

質問のような構成は典型的です。加えて、WinForms系では印刷中の進捗ダイアログを出さないために StandardPrintController を指定するケースが多いです(UIを出したくない用途ではほぼ必須になります)。

using System.Drawing.Printing;

public void PrintSilent(string printerName, string outputPath)
{
    using var pd = new PrintDocument();

    // 進捗ダイアログを抑止(WinForms系の「印刷中...」を出さない)
    pd.PrintController = new StandardPrintController();

    pd.PrinterSettings.PrinterName = printerName;
    pd.PrinterSettings.PrintToFile = true;
    pd.PrinterSettings.PrintFileName = outputPath;

    // pd.PrintPage += ... で描画内容を出す(省略)

    pd.Print();
}

ポイント:このコードがローカルでは動くのに、RDPの redirected だとXPSになるのは、コードの誤りというより印刷パイプライン(ドライバ構成)の違いが原因です。

まず確認するべきチェック項目(原因の特定が一気に楽になる)

プリンタ名に「(redirected)」が付いていないか

名前に (redirected) が付いている時点で、基本は「クライアント側プリンタをリダイレクトしている」状態です。サーバー側に“ネイティブなPDFプリンタ”が必要な要件(サーバーのパスへ自動保存)なら、この時点で赤信号だと思ってください。

サーバー側で使われているドライバが「Remote Desktop Easy Print」になっていないか

印刷管理(printmanagement.msc)やプリンタのプロパティで、対象キューのドライバ名を確認します。Easy Print になっているなら、今回の挙動はかなり高確率で説明できます。

PowerShellでざっくり見るなら次のような確認もできます(環境により利用可否はあります)。

Get-Printer | Select-Object Name, DriverName, PortName | Format-Table -Auto

出力の中に対象の Microsoft Print to PDF (redirected ...) があり、DriverName が Easy Print 系になっていれば「XPS中間形式」ルートの可能性が濃厚です。

ファイル先頭が本当にPKか(誤認を潰す)

生成された「.pdf」の先頭数バイトを確認します。PDFなら %PDF が見えるはずで、XPSならZIPヘッダの PK が見えます。

# 先頭4バイトを16進で見る(例)
$bytes = Get-Content -Path "C:\Temp\out.pdf" -Encoding Byte -TotalCount 4
$bytes | ForEach-Object { "{0:X2}" -f $_ }

50 4B ... ならASCIIで PK です。これで「PDFが壊れた」のではなく「別形式を.pdfで保存している」ことが確定します。

対処方針は“要件”で決まる:現場で使える回避策まとめ

この問題は、気合いで直すというより「設計をどう寄せるか」が勝負です。要件別に選びやすいよう、まずは結論を表にまとめます。

回避策できることメリットデメリット / 注意点おすすめ場面
サーバー側に“ネイティブPDFプリンタ”を用意サーバーのパスへPDFを直接保存RDPリダイレクトに依存しない/挙動が安定サーバー構成変更が必要/権限設計が必要業務バッチ・帳票など「自動保存が必須」
アプリ側で直接PDF生成(PDFライブラリ)プリンタ経由なしでPDF出力環境差に最も強い/レイアウト制御しやすい実装工数/印刷前提の既存ロジック改修長期運用・品質重視/帳票を制御したい
PrintToFileを使わず、クライアント側でPDF化クライアントPCにPDFとして保存XPS化問題を回避しやすい保存先の自動指定が難しいことが多い「ユーザーのPCに出ればOK」な運用
XPSとして受け取り、後段でXPS→PDF変換現状の印刷経路を維持してPDF化既存の印刷コードを大きく変えずに済む変換品質・フォント・改ページの検証が必要短期回避/改修余地が小さい案件
Easy Printを使わない設定(ドライバマッピング)中間XPSではないルートを狙う環境によっては改善する可能性印刷トラブルが増えることがある/運用が難しい管理者が印刷基盤を統制できる場合のみ

回避策:サーバー側に「redirectedではない」PDFプリンタを用意する

サーバーの指定パスにサイレントでPDFを吐きたいなら、いちばん筋が良いのはサーバー側で完結するPDFプリンタを使うことです。

  • RDPの「redirected」を使わず、サーバーに存在する「Microsoft Print to PDF」や、サーバーにドライバを入れるタイプのPDFプリンタを使う
  • こうすると Easy Print の中間XPSに巻き込まれにくく、PrintToFile の結果がPDFになりやすい

実務でよく起きるつまずきは次の2点です。

  • 同名プリンタの取り違え:「Microsoft Print to PDF」と「Microsoft Print to PDF (redirected n)」を混同しない(PrinterNameをログ出力して確認)
  • 保存先権限:サービスアカウントや実行ユーザーが PrintFileName のフォルダに書き込めるか(特にUNCパスや共有フォルダ)

PrinterNameを選ぶ段階で「redirected を弾く」だけでも、事故率がかなり下がります。

public static bool IsRedirectedPrinter(string printerName)
{
    return printerName != null
        && printerName.IndexOf("(redirected", StringComparison.OrdinalIgnoreCase) >= 0;
}

回避策:アプリ側でPDFを直接生成する(印刷APIから卒業する)

「自動保存」「パス指定」「無人運用」が要件に入る場合、プリンタ経由はどうしても不安定になりがちです。理由はシンプルで、印刷は本来対話的(ドライバ・UI・スプーラ・セッション依存)に設計されているからです。

帳票やレポートをコントロールできるなら、PDF生成ライブラリを使ってアプリが直接PDFを作る方式は長期的に強いです。

  • RDPの有無・プリンタドライバ・リダイレクト設定の影響をほぼ受けない
  • PDF/A、フォント埋め込み、透かし、電子署名など要件拡張に対応しやすい
  • 「印刷結果が人によって変わる」問題(用紙サイズ、余白、スケール)を抑えやすい

一方で、既存の「紙への印刷」を前提とした描画ロジックがある場合は改修コストが上がるため、短期の火消しではなく中長期の改善策として検討するのが現実的です。

回避策:PrintToFileを使わず、クライアント側でPDF化(RDPの本来の流れに戻す)

もし要件が「サーバーに保存」ではなく「ユーザーが自分のPCにPDFを出力できれば良い」なら、最も単純なのは PrintToFile=true をやめることです。

リダイレクト印刷は本来、サーバー側で中間形式(XPS)を作ってクライアントに渡し、クライアント側のプリンタで最終出力を行います。ここにファイル出力を挟み込むとねじれが生まれます。

  • サーバー側:通常印刷(PrintToFileなし)で redirected へ出す
  • クライアント側:Microsoft Print to PDF のUIや設定で保存

ただしこの方式は、完全なサイレントや保存パスの完全自動指定が難しいことが多い(ユーザー操作が必要、または環境依存の回避が必要)ため、無人運用には向きません。

回避策:出力はXPSとして受け取り、後段でXPS→PDFへ変換する

既存コードを大きく変えられず、かつRDP環境の「redirected」しか使えない場合は、割り切って二段構えにする手があります。

  1. まず PrintToFile の出力を「PDF」ではなくXPSとして扱う(保存拡張子を最初から .xps にする、またはPK判定したら拡張子を付け替える)
  2. 次に別プロセスで XPS→PDF 変換を行う(変換ツール/ライブラリ/サーバー機能を利用)

この方法の注意点は、変換品質です。特に次の観点は事前検証してください。

  • フォントの置換・文字化け(埋め込みの有無)
  • 改ページ位置や余白の再現性
  • 画像の解像度や透明効果
  • 大量印刷時の処理時間(バッチで詰まる)

短期的には救われますが、「印刷→中間形式→変換」という経路は部品が増えるほど運用リスクも上がるため、長期運用ならサーバー側PDFプリンタや直接PDF生成への移行も並行検討するのがおすすめです。

回避策:Easy Printを使わない構成に寄せる(ただし慎重に)

管理者権限があり、印刷基盤を統制できる環境なら「Easy Printを使わず、サーバー側ドライバを使う」方向に振る選択肢もあります。

ただしこれは、環境によっては印刷トラブル(ドライバ差異・プリンタごとの癖・64bit/32bit・署名問題など)が増えることがあるため、全社影響が出る可能性があります。次のような条件が揃っている場合に限定して検討してください。

  • RDS(RD Session Host)側のプリンタドライバをきちんと運用できる
  • クライアント端末の種類が限定されている
  • 「印刷が止まる」ことが業務影響として許容されない(つまり事前検証に時間がかけられる)

「サーバーの指定パスにPDFを自動保存したい」という要件だけを見ると、ここに寄せるより、サーバー側PDFプリンタ/PDF直接生成の方がトータルで安全になるケースが多いです。

実務でハマりやすいポイント(チェックリスト)

ポイント症状確認方法対処の方向
プリンタ名の取り違えredirectedを指定してしまうPrinterNameをログ出力/(redirected) 文字列を確認サーバー側のネイティブPDFプリンタを指定
Easy Print 経由出力がXPSになるドライバ名がEasy PrintになっていないかEasy Printを避ける構成/別方式へ切替
保存先権限0バイト/作成失敗/例外実行ユーザーの書き込み権限、パス存在確認権限付与/ローカル一時フォルダ経由
印刷の“完了”タイミング印刷直後にファイルを掴むと不完全リトライ/ファイルサイズが安定するまで待機後段処理は堅牢に(監視・再試行)
Windows更新・環境差特定環境だけ挙動が違うOS/ドライバ/ポリシー差を記録「印刷依存」を減らす設計へ

まとめ:本質は「Easy Print の中間XPSをそのまま保存している」

  • RDPの「Microsoft Print to PDF (redirected)」は、サーバーにあるPDFプリンタそのものではなく、リダイレクト印刷の仕組みの上に見えているキュー
  • Easy Print が介在すると、サーバー側ではPDFではなくXPS(ZIPコンテナ)を生成してクライアントへ送る
  • PrintToFile=true は、その“サーバー側の出力物”をファイル化するため、結果として「.pdf拡張子のXPS」ができる
  • 対処は、要件に合わせて「サーバー側で完結させる(ネイティブPDFプリンタ/PDF直接生成)」か、「クライアント側に寄せる(PrintToFileを使わない)」かを選ぶのが現実的

「拡張子はPDFなのに中身がXPS」という違和感は、印刷の途中段階を“ファイル保存”してしまったことによるズレです。仕組みが分かると、対処方針も選びやすくなるはずです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次