Windows Server 2022 タスクスケジューラで「ユーザーがログオンしていなくても実行」時にバッチが動かない原因と対策|Azure File Share コピーを確実に成功させる設定・スクリプト実例

Windows Server 2022 のタスク スケジューラで「ユーザーがログオンしていなくても実行」を選ぶと、バッチが成功と表示されるのにファイルがコピーされない――現場で非常によく出会う落とし穴です。本記事はその再現条件と原因の本質、確実に動かすための設計と運用のベストプラクティス、そしてすぐ使える堅牢なサンプル スクリプトまで一気通貫で解説します。

目次

質問概要

  • 環境: Microsoft Windows Server 2022 Datacenter
  • 目的: バッチ ファイルで Azure File Share 上のフォルダー → サーバー上の別フォルダーへファイルをコピー
  • 状況:
    • 手動実行 & 「ユーザーがログオン中のみ実行」では成功
    • 「ユーザーがログオンしているかどうかに関係なく実行」にすると、タスクは「成功」だが実体はコピーされない
  • 求めているもの: 失敗原因の特定とベストプラクティス

なぜ起きるのか ― 非対話セッションの3つの壁

タスク スケジューラで「ユーザーがログオンしていなくても実行」を選ぶと、処理は 非対話セッション(バックグラウンド ログオン) で走ります。このモードには次の制約があり、コピー失敗の主因になります。

  1. ドライブ レターの不可視:Z: などのネットワーク ドライブは対話セッションに紐づくため、非対話セッションでは見えません。
    → UNC パス(\\server\share)に置き換えるのが定石。
  2. 資格情報・プロファイルが読み込まれない:ユーザー プロファイル依存の資格情報や環境変数が未ロード。
    → タスクの「パスワードを保存しない(このタスクはローカル コンピューターのリソースのみ)」にチェックがあるとネットワークへ出られません。
  3. トークン権限の不足:同じ管理者アカウントでも、昇格トークンなしでは共有資源にアクセスできないケース。
    → 最上位の特権で実行を必ず有効化。

まずはここを直す(即効性のある設定)

項目推奨値理由
パスの指定\\storageaccount.file.core.windows.net\sharename(UNC)非対話セッションでドライブ レターが見えないため
最上位の特権で実行チェック ON昇格トークンで SMB アクセスの失敗を避ける
パスワードを保存しないチェック OFFOFF でないとネットワーク資源に出られない
実行ユーザードメインのサービス アカウントAzure File Share / コピー先 NTFS に明示権限付与しやすい
開始(作業フォルダー)スクリプト配置ディレクトリ(例: D:\Jobs\Scripts)相対パスやログ出力の失敗を防ぐ
ネットワーク条件「ネットワーク接続がある場合のみ開始」ON(任意)起動直後などのネットワーク未確立時の失敗を回避
構成Windows Server 2022トークン/ポリシー差異での挙動違いを防ぐ

権限とアクセス制御の整え方

Azure File Share の認証方式を整理する

方式認証実務ポイント代表コマンド
アカウント キー(従来)ユーザー: Azure\<StorageAccountName>
パスワード: ストレージ アカウント キー
シンプル。機微情報の保管に注意net use \\<account>.file.core.windows.net\<share> /user:Azure\<account> <key>
AD DS/Entra ID ベース(ID ベース)ドメイン アカウント(RBAC/ACL)キーレスで運用可。権限設計が肝通常の net use \\...\(ユーザー/権限は AD 側で管理)
SAS + AzCopy(HTTPS)SAS トークンSMB/445 を避けられる。自動化に強いazcopy copy "https://.../share?...SAS" "D:\Dest" --recursive

共有/NTFS の二段階で付与

  • Azure File Share 側:対象ユーザー(サービス アカウント)に 読み取り/書き込み 権限(ID ベースの場合は適切なロール/ACL)。
  • コピー先ローカル フォルダー:NTFS の 変更 以上(必要なら 作成/削除)。

ローカル セキュリティ ポリシー

  • バッチ ジョブとしてログオン(SeBatchLogonRight):実行アカウントを付与。
  • ネットワーク経由でこのコンピューターへアクセス(SeNetworkLogonRight):必要に応じて確認。
  • 逆に ネットワーク経由でのアクセスを拒否 に入っていないかもチェック。

ファイアウォール/ネットワーク前提

  • Azure File Share(SMB)は TCP 445 を使用。サーバーから *.file.core.windows.net へのアウトバウンド 445 が許可されていること。
  • SMB 署名/暗号化ポリシーの厳格化により接続拒否されることがあるため、ドメイン/ローカルのセキュリティ ポリシーでの強制設定との整合性を確認。
  • プロキシ配下では SMB は通りません。必要に応じて AzCopy(HTTPS 443)への切り替えを検討。

堅牢なスクリプト例(バッチ / robocopy 版)

成功・失敗をタスク スケジューラが正しく判定できるよう、エラー処理とログをきちんと入れます。UNC で接続し、資格情報はコマンド内で一時マップします。

@echo off
setlocal enabledelayedexpansion

rem ===== 設定 =====
set "SRC=\.file.core.windows.net<sharename>\input"
set "DST=D:\Data\Inbound"
set "LOG=D:\Jobs\Logs\copy-%%DATE:~0,4%%%%DATE:~5,2%%%%DATE:~8,2%%.log"
set "AZUSER=Azure<storageaccount>"
set "AZPASS="

rem ===== ログ開始 =====
echo [START] %DATE% %TIME% >> "%LOG%"

rem ===== 一時接続 =====
net use "%SRC%" "%AZPASS%" /USER:%AZUSER% >nul 2>&1
if errorlevel 1 (
echo [ERROR] NET USE failed (%ERRORLEVEL%) >> "%LOG%"
exit /b 32
)

rem ===== コピー(robocopy)=====
robocopy "%SRC%" "%DST%" *.* /S /FFT /Z /R:3 /W:5 /NFL /NDL /NP /LOG+:"%LOG%"
set "RC=%ERRORLEVEL%"

rem robocopy の戻り値: 0/1/2/3/4/5/6/7 = 成功/警告, 8+ = 失敗
if %RC% GEQ 8 (
echo [ERROR] ROBOCOPY failed (RC=%RC%) >> "%LOG%"
set "RET=64"
) else (
echo [OK] ROBOCOPY success (RC=%RC%) >> "%LOG%"
set "RET=0"
)

rem ===== 切断 =====
net use "%SRC%" /DELETE >nul 2>&1

echo [END] %DATE% %TIME% RET=%RET% >> "%LOG%"
exit /b %RET% 

ポイント:robocopy の戻り値は 8 以上がエラーです。タスクの「結果 0x0」(成功)だけを鵜呑みにせず、スクリプトが適切な終了コードを返すようにします。

PowerShell 版(セキュアな資格情報の分離)

DPAPI で暗号化したパスワードをファイル保存し、タスクは同一ユーザーで復号して利用する方法です(サーバー単位で有効)。

初期化(手動・一度だけ)

# 実行ユーザーのプロファイル配下に保存
$SecurePath = 'C:\ProgramData\Jobs\azfiles.cred'
$Plain = Read-Host -AsSecureString 'Enter storage key or password'
$Plain | ConvertFrom-SecureString | Set-Content -Path $SecurePath -Encoding ascii

スクリプト本体(PowerShell 7 推奨)

param(
  [string]$Src = "\\&lt;account&gt;.file.core.windows.net\&lt;share&gt;\input",
  [string]$Dst = "D:\Data\Inbound",
  [string]$User = "Azure\&lt;account&gt;",
  [string]$CredPath = "C:\ProgramData\Jobs\azfiles.cred",
  [string]$Log = "D:\Jobs\Logs\copy-$((Get-Date).ToString('yyyyMMdd-HHmmss')).log"
)

$ErrorActionPreference = 'Stop'
Start-Transcript -Path $Log -Append

try {
$secure = Get-Content -Path $CredPath -Encoding ascii | ConvertTo-SecureString
$cred   = New-Object System.Management.Automation.PSCredential($User, $secure)

# 一時接続(UNC 推奨。ドライブ レターは使わない)

$null = cmd /c "net use `"$Src`" `"$($cred.GetNetworkCredential().Password)`" /USER:$User"

# コピー(robocopy を使うと大容量でも堅牢)

$robolog = $Log
$robocmd = "robocopy `"$Src`" `"$Dst`" *.* /S /FFT /Z /R:3 /W:5 /NFL /NDL /NP /LOG+:`"$robolog`""
$proc = Start-Process -FilePath "cmd.exe" -ArgumentList "/c $robocmd" -PassThru -Wait
$rc = $proc.ExitCode

if ($rc -ge 8) { throw "ROBOCOPY failed. RC=$rc" }

Write-Host "Copy completed. RC=$rc"
exit 0
}
catch {
Write-Error $_
exit 64
}
finally {
cmd /c "net use `"$Src`" /DELETE" | Out-Null
Stop-Transcript
} </code></pre>

<h3>タスク設定例(PowerShell を直接起動)</h3>
<ul>
  <li><strong>プログラム/スクリプト</strong>:<code>C:\Program Files\PowerShell\7\pwsh.exe</code></li>
  <li><strong>引数の追加</strong>:<code>-NoLogo -NoProfile -ExecutionPolicy Bypass -File "D:\Jobs\Scripts\Copy-AzFiles.ps1"</code></li>
  <li><strong>開始(作業フォルダー)</strong>:<code>D:\Jobs\Scripts</code></li>
</ul>

<h2>資格情報の安全な扱い(バッチに直書きしない)</h2>
<ul>
  <li><strong>Credential Manager + cmdkey</strong>:マシン/ユーザー コンテキストに保存し、タスクから利用。
    <pre><code>cmdkey /add:&lt;account&gt;.file.core.windows.net /user:Azure\&lt;account&gt; /pass:&lt;key&gt;
net use \\&lt;account&gt;.file.core.windows.net\&lt;share&gt; /persistent:no
タスクは同一ユーザーで実行すること。

gMSA(グループ管理サービス アカウント):パスワードの自動ローテーションが効く運用に強い選択。タスクの「ユーザーまたはグループ」に DOMAIN\svc-xxx$ を指定できる。
Azure ID ベース SMB:ストレージ側を ID 連携し、Storage File Data SMB Share Contributor 等のロールや ACL を付与。キーレスでの監査性が高い。

「成功なのにコピーされない」を見抜くトラブルシューティング

症状観点具体的な確認
タスク結果 0x0 だがファイル無し戻り値の取りこぼしスクリプトが適切に exit /b/exit <code> しているか。robocopy の RC 判定を実装
ログに「指定されたネットワーク名は利用できません」UNC/445UNC を使っているか、TCP 445 のアウトバウンドが通るか
「アクセスが拒否されました」権限/トークン最上位の特権を ON、共有/NTFS の権限を明示付与、パスワードを保存しない は OFF
手動では通るがタスクで失敗プロファイル依存資格情報は DPAPI/Credential Manager/gMSA に寄せる。相対パスや環境変数に依存しない
起動時のみ失敗ネットワーク成立前トリガーに「遅延タスク(例: 2 分)」や「ネットワーク接続がある場合のみ開始」を設定

ログの取り方

  • Task Scheduler > すべてのタスク履歴を有効化:Microsoft-Windows-TaskScheduler/Operational を確認。
  • PowerShell:Start-Transcript を使用し、実行コマンド/例外を残す。
  • イベント ログ出力:独自ソースを作り、致命エラーで Write-EventLog。

チェックリスト(そのまま現場で使える)

  • UNC パスで記述している(Z: 等を使っていない)。
  • タスク「最上位の特権で実行」ON、「パスワードを保存しない」は OFF。
  • 実行アカウントはサービス アカウント。Azure 側と NTFS 側に 変更 以上の権限あり。
  • プログラム/引数/開始フォルダーを適切に指定(相対パス無し)。
  • 戻り値を厳密に判定(robocopy: 8 以上で失敗)。
  • TCP 445 のアウトバウンド許可。プロキシを経由しない経路を用意。
  • 初回のみ手動実行でログを確認し、次いで「ユーザーがログオンしていなくても実行」で再検証。

セキュリティ設計の勘所

  • 最小権限:コピー元は読み取りのみ、コピー先は作成/変更/削除の必要最小限。
  • 秘密情報の回避:可能なら ID ベース SMB へ移行。キーベース運用時はキーを Key Vault 等で管理(運用手順でローテーション前提)。
  • 監査:アクセス失敗/成功をイベント ログ・ストレージ監査で収集。タスク失敗時にメール/Teams 通知を組み合わせると復旧が速い。

代替策:AzCopy(HTTPS)で SMB の制約を回避

ネットワーク ポリシーや ISP の都合で TCP 445 を開けられない場合、AzCopy が有効です。HTTPS(443) で動作し、タスク スケジューラとも相性が良好です。

azcopy copy `
  "https://&lt;account&gt;.file.core.windows.net/&lt;share&gt;/input?&lt;SAS&gt;" `
  "D:\Data\Inbound" `
  --recursive=true --check-length=true --overwrite=ifSourceNewer `
  --log-level=INFO --output-type=text

AzCopy 自体の戻り値をタスクが受け取れるように、cmd /c 経由ではなく直接実行し、作業フォルダーをログ出力先にしておくと管理が楽です。

複数台運用の安定化テクニック

  • GPO のスタートアップ スクリプト:複数サーバーで同一処理を走らせるなら、GPO にスクリプト(UNC パスで記述)を配布して統一。
  • タスク XML を雛形化:検証済みのタスクを エクスポート → XML を雛形にして schtasks /create /XML で一括展開。
  • ログ規約:サーバー名/ジョブ名/日付 でローテーション。D:\Jobs\Logs\{Job}\yyyyMMdd.log 等。

よくある落とし穴(再確認)

  1. 「パスワードを保存しない」にチェック:これがあると非対話セッションでネットワークに出られません。必ず OFF。
  2. ドライブ レター依存:Z:\ は使わない。常に \\server\share で。
  3. 相対パス/カレント ディレクトリ依存:開始(作業フォルダー)を明示。
  4. 戻り値未実装:成功と見えて失敗している典型。exit /b と robocopy の判定を実装。
  5. 実行アカウントの権限不足:共有/NTFS の両面、ローカル ポリシーのユーザー権利割り当ても必ず確認。

ワンライナーでの健全性チェック

:: 資格情報を明示して UNC へ到達できるか
cmd /c "net use \\&lt;account&gt;.file.core.windows.net\&lt;share&gt; &lt;key&gt; /user:Azure\&lt;account&gt; &amp; dir \\&lt;account&gt;.file.core.windows.net\&lt;share&gt; &amp; net use \\&lt;account&gt;.file.core.windows.net\&lt;share&gt; /delete"
# PowerShell: UNC の到達性
Test-Path "\\&lt;account&gt;.file.core.windows.net\&lt;share&gt;" -ErrorAction SilentlyContinue

まとめ

今回の事象は、非対話セッション(Run whether user is logged on or not)で失われる前提――ドライブ レター、資格情報、昇格トークン――が主因です。対策はシンプルで、UNC で書く/最上位の特権で実行/パスワードを保存しないを OFF/権限を二段で明示。これに堅牢なエラー処理とログ、ネットワーク前提の確認を加えれば、タスクは確実に動きます。さらに AzCopy を組み合わせれば、TCP 445 の制約も回避できます。記事のスクリプトとチェックリストをそのまま適用し、「成功なのに動いていない」状態から脱却しましょう。


付録:設定の具体例(スクリーンで確認する項目)

タブ項目設定
全般ユーザーまたはグループドメインのサービス アカウント(または gMSA)
全般ユーザーがログオンしているかどうかに関係なく実行ON(本件の要件)
全般最上位の特権で実行するON
全般パスワードを保存しない(このタスクはローカル コンピューターのリソースのみ)OFF
トリガースケジュール/ログオン/スタートアップ要件に合わせて設定(遅延開始を推奨)
操作プログラム/スクリプトpwsh.exe または cmd.exe
操作引数PowerShell の場合:-NoLogo -NoProfile -ExecutionPolicy Bypass -File ...
操作開始(作業フォルダー)スクリプトの配置フォルダー
条件ネットワークネットワーク接続がある場合のみ開始(任意)
設定期限切れ後、可能な場合はタスクをできるだけ早く実行するON(実行機会の取りこぼしを防止)

付録:エラーコード早見表

対象コード意味対応
タスク スケジューラ0x0タスクとしては成功実際の処理結果はスクリプトの終了コードで判定
robocopy0–7成功/一部差分/警告ログを確認(8 以上のみ失敗扱い)
robocopy8 以上失敗終了コードでエラーとして返す
net use1219 etc.異なる資格情報で既に接続済み一旦 net use \\... /delete して再接続

付録:簡易バッチ(最小構成)

@echo off
set "SRC=\\&lt;account&gt;.file.core.windows.net\&lt;share&gt;"
set "DST=D:\Dest"
net use "%SRC%" "&lt;key&gt;" /USER:Azure\&lt;account&gt; &gt;nul 2&gt;&amp;1 || exit /b 10
xcopy "%SRC%\*" "%DST%\" /S /Y /I &gt;nul 2&gt;&amp;1 || exit /b 20
net use "%SRC%" /DELETE &gt;nul 2&gt;&amp;1
exit /b 0

上記の設計・手順・スクリプトを順に適用すれば、Windows Server 2022 のタスク スケジューラで「ユーザーがログオンしていなくても実行」でも確実に Azure File Share からのコピーが動作するようになります。

この記事を書いた人

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

コメント

コメントする

目次