**REGION 00 初期値(フォームに最初から入る値。空なら空欄) # 初期_移動元 が空のときは <ユーザー>\Downloads\PDF-Results の中で一番新しい PAD_Hierarchy_… を自動で入れる # 初期_親フォルダー が空のときは <ユーザー>\Downloads\PDF-Results\振り分け # 初期_表示する子フォルダー : ID 一覧(HTML)で ID の下に並べる子フォルダー名(改行区切り)。移動先の子パスは自動で含む Variables.ConvertJsonToCustomObject Json: $'''{ "初期_移動元": "", "初期_親フォルダー": "", "初期_桁数": "8", "初期_子パス": "保管", "初期_ログも移動": "true", "初期_表示する子フォルダー": "保管\\n作業" }''' CustomObject=> Init **ENDREGION **REGION 01 文章(画面の文言を変えたいときはここ) Variables.ConvertJsonToCustomObject Json: $'''{ "画面_入力タイトル": "PDF振り分け", "画面_入力説明": "移動元直下の PDF を、ファイル名の先頭 N 桁を ID として「親フォルダー\\\\ID\\\\子パス」へ移動します。無いフォルダーは作ります。上書きはしません。", "画面_移動元": "移動元フォルダー(取得したPDFがある場所。初期値は一番新しい取得フォルダー)", "画面_親": "振り分け先の親フォルダー(この下に ID フォルダーを作る。無ければ作成)", "画面_桁数": "ID の桁数(ファイル名の先頭から。例:DEMO-001_… なら 8)", "画面_子パス": "ID フォルダーの中の子パス(任意。例:保管 や 保管\\\\2026年度)", "画面_ログも移動": "ID 別のダウンロード結果ログも一緒に移動する", "画面_開始": "振り分け開始", "画面_キャンセル": "キャンセル", "画面_結果タイトル": "PDF振り分け|結果", "画面_結果ログ欄": "振り分け結果(原本は移動元の 振り分け結果_日時.txt)", "画面_結果案内": "「ID一覧を開く」「親フォルダーを開く」は開くだけで、この画面は残ります。終わるときは「閉じる」。", "画面_ID一覧を開く": "ID一覧を開く(HTML)", "画面_ID一覧HTA": "ID一覧を開く(Explorer ワンクリック版)", "画面_親を開く": "親フォルダーを開く", "画面_再試行": "条件を変えてもう一度", "画面_閉じる": "閉じる", "画面_確認未了": "確認の項目にチェックを入れてください。" }''' CustomObject=> Msg **ENDREGION **REGION 02 入力 System.GetEnvironmentVariable.GetEnvironmentVariable Name: $'''USERPROFILE''' Value=> ProfileFolder SET SrcFolder TO Init['初期_移動元'] SET DstParent TO Init['初期_親フォルダー'] SET IdDigits TO Init['初期_桁数'] SET ChildPath TO Init['初期_子パス'] SET MoveLogs TO Init['初期_ログも移動'] SET ShowKids TO Init['初期_表示する子フォルダー'] IF IsEmpty(DstParent) THEN SET DstParent TO $'''%ProfileFolder%\\Downloads\\PDF-Results\\振り分け''' END IF IsEmpty(SrcFolder) THEN # 一番新しい取得フォルダーを探す Scripting.RunPowershellScript.RunScript Script: $'''$root = [IO.Path]::Combine("%ProfileFolder%", "Downloads", "PDF-Results") if ([IO.Directory]::Exists($root)) { $d = Get-ChildItem -LiteralPath $root -Directory -Filter "PAD_Hierarchy_*" | Sort-Object Name -Descending | Select-Object -First 1; if ($d) { $d.FullName } }''' ScriptOutput=> LatestOut ScriptError=> LatestErr ON ERROR GOTO LatestUnknown END SET SrcFolder TO LatestOut.Trimmed LABEL LatestUnknown END SET Notice TO Msg['画面_入力説明'] LABEL ShowInput Display.ShowCustomDialog CardTemplateJson: '''{ "type": "AdaptiveCard", "version": "1.4", "id": "AdaptiveCard", "body": [ { "type": "TextBlock", "id": "Notice", "text": "${Notice_Text}", "wrap": true }, { "type": "Input.Text", "id": "Src", "label": "${Src_Label}", "value": "${Src_Value}", "isRequired": true, "maxLength": 1024 }, { "type": "Input.Text", "id": "Dst", "label": "${Dst_Label}", "value": "${Dst_Value}", "isRequired": true, "maxLength": 1024 }, { "type": "Input.Text", "id": "Digits", "label": "${Digits_Label}", "value": "${Digits_Value}", "isRequired": true, "maxLength": 3 }, { "type": "Input.Text", "id": "Child", "label": "${Child_Label}", "value": "${Child_Value}", "maxLength": 256 }, { "type": "Input.Toggle", "id": "Logs", "title": "${Logs_Title}", "value": "${Logs_Value}", "valueOn": "true", "valueOff": "false" }, { "type": "Input.Toggle", "id": "ChkSrc", "title": "移動元が今回の取得フォルダーであることを確認した", "value": "false", "valueOn": "true", "valueOff": "false", "isRequired": true, "errorMessage": "チェックが必要です" } ], "actions": [ { "type": "Action.Submit", "id": "OK", "title": "${Start_Title}" }, { "type": "Action.Submit", "id": "Cancel", "title": "${Cancel_Title}", "associatedInputs": "none" } ], "FormTitle": "${Form_Title}" }''' CustomFormData=> InputData ButtonPressed=> InputButton @Notice_Text: Notice @Src_Value: SrcFolder @Dst_Value: DstParent @Digits_Value: IdDigits @Child_Value: ChildPath @Logs_Value: MoveLogs @Src_Label: Msg['画面_移動元'] @Dst_Label: Msg['画面_親'] @Digits_Label: Msg['画面_桁数'] @Child_Label: Msg['画面_子パス'] @Logs_Title: Msg['画面_ログも移動'] @Start_Title: Msg['画面_開始'] @Cancel_Title: Msg['画面_キャンセル'] @Form_Title: Msg['画面_入力タイトル'] ON ERROR GOTO Quit END IF InputButton <> $'''OK''' THEN EXIT Code: 0 END SET SrcFolder TO InputData['Src'] SET DstParent TO InputData['Dst'] SET IdDigits TO InputData['Digits'] SET ChildPath TO InputData['Child'] SET MoveLogs TO InputData['Logs'] IF InputData['ChkSrc'] <> $'''true''' THEN SET Notice TO $'''⚠ %Msg['画面_確認未了']%''' GOTO ShowInput END **ENDREGION **REGION 03 振り分け(PowerShell 1回) Variables.ConvertJsonToCustomObject Json: $'''{}''' CustomObject=> Carry SET Carry['src'] TO SrcFolder SET Carry['dst'] TO DstParent SET Carry['digits'] TO IdDigits SET Carry['child'] TO ChildPath SET Carry['logs'] TO MoveLogs SET Carry['show'] TO ShowKids Variables.ConvertCustomObjectToJson CustomObject: Carry Json=> CarryJson File.GetTempPath TempFile=> CarryFile File.WriteText File: CarryFile TextToWrite: CarryJson AppendNewLine: False IfFileExists: File.IfFileExists.Overwrite Encoding: File.FileEncoding.UTF8 Scripting.RunPowershellScript.RunScript Script: $''' $ErrorActionPreference = "Stop" $carrier = "%CarryFile%" $r = @{ status = "failed"; summary = "振り分け結果を確認できません。"; log = ""; logPath = ""; listHtml = ""; listHta = ""; listCsv = ""; parent = "" } $sep = [IO.Path]::DirectorySeparatorChar $linkCache = @{} function Fail([string]$status, [string]$msg) { $script:r.status = $status; $script:r.summary = $msg; throw "__stop__" } function Test-Name([string]$n) { if ($n.Length -eq 0 -or $n.Length -gt 255 -or $n -eq "." -or $n -eq "..") { return $false } if ($n -match "[\\x00-\\x1f<>:\\x22/\\\\|?*]" -or $n -match "[ .]$") { return $false } if (($n -split "[.]")[0].Trim() -match "^(?i)(CON|PRN|AUX|NUL|COM[1-9]|LPT[1-9])$") { return $false } return $true } function Assert-RealFolder([string]$path) { # シンボリックリンク・ジャンクションの下へは移動しない(OneDrive のクラウド属性は可)。フォルダーごとに1回だけ調べる $full = [IO.Path]::GetFullPath($path) if ($linkCache.ContainsKey($full)) { return } $cur = $full while ($cur) { if ($linkCache.ContainsKey($cur)) { break } $item = Get-Item -LiteralPath $cur -Force if ($item.LinkType) { throw "リンク($($item.LinkType))配下のため対象外:$cur" } $linkCache[$cur] = $true $cur = [IO.Path]::GetDirectoryName($cur) } } function Ensure-Folder([string]$parent, [string]$name) { if (-not (Test-Name $name)) { throw "フォルダー名に使えません:$name" } $p = [IO.Path]::Combine($parent, $name) if ([IO.File]::Exists($p)) { throw "同名のファイルがあります:$p" } if (-not [IO.Directory]::Exists($p)) { [IO.Directory]::CreateDirectory($p) | Out-Null } Assert-RealFolder $p return $p } try { $in = [IO.File]::ReadAllText($carrier, [Text.Encoding]::UTF8) | ConvertFrom-Json $src = [string]$in.src; $dst = [string]$in.dst; $child = ([string]$in.child).Trim().Replace("/", "\\") $includeLogs = ([string]$in.logs) -eq "true" $showKids = @(([string]$in.show) -split "[\\r\\n]+" | ForEach-Object { $_.Trim().Replace("/", "\\") } | Where-Object { $_.Length -gt 0 }) if (-not [IO.Path]::IsPathRooted($src) -or -not [IO.Directory]::Exists($src)) { Fail "invalid" "移動元フォルダーが見つかりません。絶対パスで指定してください。" } if (-not [IO.Path]::IsPathRooted($dst)) { Fail "invalid" "振り分け先の親フォルダーは絶対パスで指定してください。" } if (([string]$in.digits) -notmatch "^[0-9]{1,3}$" -or [int]$in.digits -lt 1 -or [int]$in.digits -gt 200) { Fail "invalid" "ID の桁数は 1~200 の整数で入力してください。" } $digits = [int]$in.digits $childParts = @(); if ($child.Length -gt 0) { $childParts = @($child.Split("\\") | ForEach-Object { $_.Trim() }) foreach ($part in $childParts) { if (-not (Test-Name $part)) { Fail "invalid" "子パスに使えない名前があります:$part" } } } $src = [IO.Path]::GetFullPath($src); $dst = [IO.Path]::GetFullPath($dst) $child = $childParts -join "\\" foreach ($sk in $showKids) { if ([IO.Path]::IsPathRooted($sk)) { Fail "invalid" "表示する子フォルダーは相対パスで指定してください。" } foreach ($part in $sk.Split("\\")) { if (-not (Test-Name $part)) { Fail "invalid" "表示する子フォルダーに使えない名前があります:$part" } } } Assert-RealFolder $src $ancestor = $dst while (-not [IO.Directory]::Exists($ancestor)) { if ([IO.File]::Exists($ancestor)) { Fail "invalid" "移動先の途中に同名ファイルがあります。" } $ancestor = [IO.Path]::GetDirectoryName($ancestor) if (-not $ancestor) { Fail "invalid" "移動先のドライブを確認してください。" } } Assert-RealFolder $ancestor if (-not [IO.Directory]::Exists($dst)) { [IO.Directory]::CreateDirectory($dst) | Out-Null } Assert-RealFolder $dst $logRegex = "_ダウンロード結果_[0-9]{8}_[0-9]{6}_[0-9]{3}[.]txt$" $targets = @(Get-ChildItem -LiteralPath $src -File -Force | Where-Object { $_.Extension -ieq ".pdf" -or ($includeLogs -and $_.Name -match $logRegex) } | Sort-Object Name) $stamp = Get-Date -Format "yyyyMMdd_HHmmss" $uniq = [IO.Path]::GetFileNameWithoutExtension([IO.Path]::GetRandomFileName()) $finalLog = [IO.Path]::Combine($src, "振り分け結果_" + $stamp + "_" + $uniq + ".txt") $tempLog = $finalLog + ".処理中.txt" if ([IO.File]::Exists($finalLog)) { Fail "failed" "同名の振り分け結果ログがあるため中止しました。移動していません。" } $w = [IO.StreamWriter]::new($tempLog, $false, [Text.UTF8Encoding]::new($true)) $lines = [Collections.Generic.List[string]]::new() function Put([string]$t) { $script:w.WriteLine($t); $script:lines.Add($t) } Put "[処理中・未確定] 完了ログではありません。" Put "" $header = @("[移動処理ログファイル]", $finalLog, "", "[移動条件]", "移動元フォルダ : $src", "移動先フォルダ(親): $dst", "移動先フォルダ(子): 各ファイル先頭 $digits 桁", ("移動先フォルダ(孫): " + $(if ($child) { $child } else { "(なし)" })), "ID別ログも振り分け: $includeLogs", "", "[ファイル別結果]") foreach ($h in $header) { Put $h }; $w.Flush() $ok = 0; $ng = 0; $idFolders = [ordered]@{} foreach ($f in $targets) { $name = $f.Name; $base = [IO.Path]::GetFileNameWithoutExtension($name); $id = ""; $to = ""; $why = "" try { if ($base.Length -lt $digits) { throw "ファイル名が ID の桁数より短い" } $id = $name.Substring(0, $digits) if (-not (Test-Name $id)) { throw "先頭 $digits 桁がフォルダー名として使えない($id)" } if (-not $idFolders.Contains($id)) { $planned = [IO.Path]::Combine($dst,$id) foreach ($part in $childParts) { $planned = [IO.Path]::Combine($planned,$part) } $idFolders[$id] = @{ path=$planned; ok=0; ng=0 } } $cur = Get-Item -LiteralPath $f.FullName -Force if ($cur.LinkType) { throw "元ファイルがリンク($($cur.LinkType))のため対象外" } if (($cur.Attributes -band 0x1000) -or ($cur.Attributes -band 0x400000)) { throw "オンラインのみのファイル(ローカルに取得してから再実行)" } if ($cur.Length -ne $f.Length) { throw "一覧確定後にサイズが変わった" } if (-not $idFolders[$id].ready) { $folder = Ensure-Folder $dst $id foreach ($part in $childParts) { $folder = Ensure-Folder $folder $part } $idFolders[$id].path = $folder; $idFolders[$id].ready = $true } $folder = $idFolders[$id].path $to = [IO.Path]::Combine($folder, $name) if ([IO.File]::Exists($to) -or [IO.Directory]::Exists($to)) { throw "移動先に同名があるため上書きしない" } [IO.File]::Move($f.FullName, $to) if ([IO.File]::Exists($f.FullName) -or -not [IO.File]::Exists($to)) { throw "移動後の所在を確認できない" } if ((Get-Item -LiteralPath $to).Length -ne $f.Length) { throw "移動後のサイズが一致しない(移動先を確認)" } $ok++; $idFolders[$id].ok++; $entry = @("【〇 成功】$id | $name") } catch { $ng++; $why = $_.Exception.Message if ($id -and $idFolders.Contains($id)) { $idFolders[$id].ng++ } $now = if ([IO.File]::Exists($f.FullName)) { $f.FullName } elseif ($to -and [IO.File]::Exists($to)) { $to } else { "不明" } $entry = @(("【X 失敗】" + $(if ($id) { $id } else { "ID抽出不能" }) + " | " + $name), " 理由=$why", " 現在=$now", (" 移動先=" + $(if ($to) { "予定:$to" } else { "未特定" }))) } try { foreach ($e in $entry) { Put $e }; $w.Flush() } catch { Fail "failed" ("ログ追記に失敗したため以後の移動を中止しました(" + $_.Exception.Message + ")。移動元・移動先と処理中ログを確認してください。") } } $summary = "対象" + $targets.Count + "件/成功" + $ok + "件/失敗" + $ng + "件" $w.Close(); $w = $null # 確定ログ:冒頭に件数を 1 回だけ。処理中ログの先頭 2 行(未確定の注記)は外す $final = @("[処理結果まとめ]", $summary, "") + @($lines | Select-Object -Skip 2) + @("", "[終了]", "") [IO.File]::WriteAllLines($finalLog, $final, [Text.UTF8Encoding]::new($true)) $r.logPath = $finalLog; $r.log = ($final -join "`r`n"); $r.parent = $dst [IO.File]::Delete($tempLog) $listCsv = [IO.Path]::Combine($dst, "ID一覧_" + $stamp + ".csv"); $listHtml = [IO.Path]::Combine($dst, "ID一覧_" + $stamp + ".html"); $listHta = [IO.Path]::Combine($dst, "ID一覧_" + $stamp + ".hta") function Enc([string]$t) { return [Net.WebUtility]::HtmlEncode($t) } function Kind([string]$ext) { if ($ext -ieq ".pdf") { return "pdf" } elseif ($ext -ieq ".txt" -or $ext -ieq ".csv" -or $ext -ieq ".md" -or $ext -ieq ".log") { return "txt" } else { return "other" } } # 1行:記号+名前+ボタン。data-p にパス。ボタンの中身は html/hta で差し替える function Row([string]$label, [string]$path, [string]$cls, [string]$note, [bool]$isDir) { $btn = $(if ($isDir) { "__DIRBTN__" } else { "__FILEBTN__" }) return "
" + (Enc $label) + "" + $note + "" + $btn + "
" } $displayFiles = @{} function Display-Files([string]$path) { if (-not $displayFiles.ContainsKey($path)) { $displayFiles[$path] = @(Get-ChildItem -LiteralPath $path -File -ErrorAction SilentlyContinue | Sort-Object Name) } return $displayFiles[$path] } $q = [string][char]34; $csv = @("ID,フォルダー,成功,失敗,PDF件数") $tree = "" foreach ($k in $idFolders.Keys) { $f = $idFolders[$k]; $leaf = $f.path $leafFiles = @(Display-Files $leaf) $cnt = @($leafFiles | Where-Object { $_.Extension -ieq ".pdf" }).Count $csv += ($q + $k + $q + "," + $q + $leaf + $q + "," + $f.ok + "," + $f.ng + "," + $cnt) $idPath = [IO.Path]::Combine($dst, $k) $targetTop = $(if ($childParts.Count -gt 0) { $childParts[0] } else { "" }) $kids = [ordered]@{} foreach ($sk in $showKids) { $kids[$sk] = $false } if ($targetTop) { $kids[$targetTop] = $true } foreach ($d in @(Get-ChildItem -LiteralPath $idPath -Directory -ErrorAction SilentlyContinue)) { if (-not $kids.Contains($d.Name)) { $kids[$d.Name] = $false } } $filesHtml = "" foreach ($fi in $leafFiles) { $filesHtml += "
  • " + (Row $fi.Name $fi.FullName (Kind $fi.Extension) "" $false) + "
  • " } $inner = "" foreach ($kn in $kids.Keys) { $kp = [IO.Path]::Combine($idPath, $kn) if ($kids[$kn]) { $sub = ""; $cur = $kp; $depth = 0 foreach ($part in ($childParts | Select-Object -Skip 1)) { $cur = [IO.Path]::Combine($cur, $part); $sub += "
  • " + (Row $part $cur "dir" "" $true) + "
  • " } $note = "★ 今回ここに " + $f.ok + " 件" + $(if ($f.ng -gt 0) { "(失敗 " + $f.ng + ")" } else { "" }) + "" $inner += "
  • " + (Row $kn $kp "dir tgt" $note $true) + "
  • " } elseif ([IO.Directory]::Exists($kp)) { $n = @(Display-Files $kp).Count $inner += "
  • " + (Row $kn $kp "dir" ("" + $n + " ファイル") $true) + "
  • " } else { $inner += "
  • " + (Enc $kn) + "未作成
  • " } } if ($childParts.Count -eq 0) { $inner = $filesHtml + $inner } $tree += "
  • " + (Row $k $idPath "dir id" ("今回 " + $f.ok + " 件/PDF " + $cnt + " 件") $true) + "
  • " } [IO.File]::WriteAllLines($listCsv, $csv, [Text.UTF8Encoding]::new($true)) $css = "body{font:14px/1.4 Segoe UI,Meiryo,system-ui;margin:24px 28px;color:#222;background:#fff}h2{font-size:17px;margin:0 0 4px}.lg{font-size:12px;color:#777;margin:0 0 14px}" + "ul{list-style:none;margin:0;padding:0 0 0 44px;position:relative}ul:before{content:" + $q + $q + ";position:absolute;left:18px;top:0;bottom:14px;border-left:1px solid #9a9a9a}" + "li{position:relative;margin:0;padding:3px 0}li:before{content:" + $q + $q + ";position:absolute;left:-26px;top:17px;width:22px;border-top:1px solid #9a9a9a}" + "ul>li:last-child:after{content:" + $q + $q + ";position:absolute;left:-27px;top:18px;bottom:-4px;width:3px;background:#fff}" + ".row{display:flex;align-items:center;gap:8px;padding:4px 8px;border-radius:6px}.row:hover{background:#f4f6f8}.ic{display:inline-block;width:1.2em;text-align:center;font-size:15px}" + ".dir .ic:before{content:" + $q + "▰" + $q + ";color:#d4a017}.pdf .ic:before{content:" + $q + "▤" + $q + ";color:#c0392b}.txt .ic:before{content:" + $q + "≡" + $q + ";color:#6b7b8c}.other .ic:before{content:" + $q + "○" + $q + ";color:#8a8a8a}.none .ic:before{content:" + $q + "▱" + $q + ";color:#ccc}" + ".nm{white-space:nowrap}.id .nm{font-weight:700;font-size:16px}.none .nm{color:#9a9a9a}.sm{color:#777;font-size:12px}.here{color:#1a6b3a;font-weight:600;font-size:13px;background:#e9f7ee;border-radius:4px;padding:1px 8px}" + ".bt{margin-left:6px;display:flex;gap:4px;padding-left:8px;border-left:1px solid #dfe4ea}.bt button{font:12px Segoe UI,Meiryo,system-ui;padding:3px 9px;border:1px solid #9fb3c8;border-radius:5px;background:#fff;color:#1f3b57;cursor:pointer}.bt button:hover{background:#eaf2fb}.bt button:active{background:#d8e6f5}" + "#toast{position:fixed;right:20px;bottom:20px;background:#1f3b57;color:#fff;padding:8px 14px;border-radius:6px;opacity:0;transition:opacity .2s}" $head = "

    振り分け " + $stamp + " " + (Enc $summary) + "

    ▰ フォルダー ▤ PDF ≡ テキスト ○ その他 ▱ 未作成 | 行の右のボタンで開く/パスをコピー(コピーしたパスは Explorer のアドレス欄や Win+R に貼れば開きます)
    " $root = "
    " + (Enc $dst) + "__DIRBTN__
    " $body = $head + $root + "
    " # HTML 版:Edge で見る/コピー $jsHtml = "function P(b){return b.parentNode.parentNode.getAttribute(" + $q + "data-p" + $q + ")}function T(m){var t=document.getElementById(" + $q + "toast" + $q + ");t.textContent=m;t.style.opacity=1;setTimeout(function(){t.style.opacity=0},1200)}" + "function C(b){var p=P(b);if(navigator.clipboard){navigator.clipboard.writeText(p).then(function(){T(" + $q + "コピーしました" + $q + ")},function(){F(p)})}else{F(p)}}function F(p){var a=document.createElement(" + $q + "textarea" + $q + ");a.value=p;document.body.appendChild(a);a.select();document.execCommand(" + $q + "copy" + $q + ");a.remove();T(" + $q + "コピーしました" + $q + ")}" + "function V(b){var p=P(b);window.open(" + $q + "file:///" + $q + "+p.replace(/\\\\/g," + $q + "/" + $q + ")," + $q + "_blank" + $q + ")}" $btnDirHtml = "" $btnFileHtml = "" $html = "ID一覧 " + $stamp + "" + $body.Replace("__DIRBTN__", $btnDirHtml).Replace("__FILEBTN__", $btnFileHtml) + "" [IO.File]::WriteAllText($listHtml, $html, [Text.UTF8Encoding]::new($true)) # HTA 版:Explorer/開く/コピー(mshta が動く PC 用) $jsHta = "function P(b){return b.parentNode.parentNode.getAttribute(" + $q + "data-p" + $q + ")}function T(m){var t=document.getElementById(" + $q + "toast" + $q + ");t.innerText=m;t.style.opacity=1;setTimeout(function(){t.style.opacity=0},1200)}" + "function E(b){var p=P(b);try{new ActiveXObject(" + $q + "WScript.Shell" + $q + ").Run(" + $q + "explorer.exe \\" + $q + "+p+" + $q + "\\" + $q + ")}catch(e){T(" + $q + "開けません:" + $q + "+e.message)}}" + "function O(b){var p=P(b);try{new ActiveXObject(" + $q + "WScript.Shell" + $q + ").Run(" + $q + "msedge.exe \\" + $q + "file:///" + $q + "+p.replace(/\\\\/g," + $q + "/" + $q + ")+" + $q + "\\" + $q + ")}catch(e){T(" + $q + "開けません:" + $q + "+e.message)}}" + "function C(b){var p=P(b);try{window.clipboardData.setData(" + $q + "text" + $q + ",p);T(" + $q + "コピーしました" + $q + ")}catch(e){T(" + $q + "コピーできません" + $q + ")}}" $btnDirHta = "" $btnFileHta = "" $hta = "ID一覧 " + $stamp + "" + $body.Replace("__DIRBTN__", $btnDirHta).Replace("__FILEBTN__", $btnFileHta) + "" [IO.File]::WriteAllText($listHta, $hta, [Text.UTF8Encoding]::new($true)) $r.status = "complete"; $r.summary = "振り分け完了 " + $summary; $r.logPath = $finalLog; $r.listHtml = $listHtml; $r.listHta = $listHta; $r.listCsv = $listCsv; $r.parent = $dst $r.log = ($final -join "`r`n") } catch { if ($_.Exception.Message -ne "__stop__") { $r.status = "failed"; $r.summary = "振り分け中にエラー:" + $_.Exception.Message + " 移動元・移動先と処理中ログを確認してください。" } if ($w) { try { $w.Close() } catch {} } if ($r.logPath -and [IO.File]::Exists($r.logPath)) { $r.summary = "ファイル移動の結果は確定済みです。一覧作成・後処理でエラー:" + $_.Exception.Message + " 振り分けログを確認してください。" } elseif ($lines.Count -gt 0) { $r.log = ($lines -join "`r`n"); $r.logPath = $tempLog; $r.summary = $r.summary + " 処理中ログ:" + $tempLog } } [IO.File]::WriteAllText($carrier, ($r | ConvertTo-Json -Depth 3 -Compress), [Text.UTF8Encoding]::new($false))''' ScriptOutput=> PsOut ScriptError=> PsErr ON ERROR GOTO RunFailed END File.ReadTextFromFile.ReadText File: CarryFile Encoding: File.TextFileEncoding.UTF8 Content=> ResultJson ON ERROR GOTO RunFailed END Variables.ConvertJsonToCustomObject Json: ResultJson CustomObject=> Result ON ERROR GOTO RunFailed END GOTO Cleanup LABEL RunFailed ERROR => RunError Reset: True Variables.ConvertJsonToCustomObject Json: $'''{"status":"failed","summary":"振り分け結果を確認できません。移動元・移動先を確認してください。","log":"","logPath":"","listHtml":"","listHta":"","listCsv":"","parent":""}''' CustomObject=> Result LABEL Cleanup File.Delete Files: CarryFile ON ERROR GOTO CleanupDone END LABEL CleanupDone IF Result['status'] = $'''invalid''' THEN SET Notice TO $'''⚠ %Result['summary']%''' GOTO ShowInput END **ENDREGION **REGION 04 結果(開くボタンでは終わらない。終わるのは「閉じる」だけ) SET SummaryText TO Result['summary'] SET LogText TO Result['log'] LABEL ShowResult Display.ShowCustomDialog CardTemplateJson: '''{ "type": "AdaptiveCard", "version": "1.4", "id": "AdaptiveCard", "body": [ { "type": "TextBlock", "id": "Summary", "text": "${Summary_Text}", "wrap": true, "weight": "Bolder" }, { "type": "TextBlock", "id": "Where", "text": "親:${Parent_Text}", "wrap": true }, { "type": "Input.Text", "id": "Log", "label": "${Log_Label}", "isMultiline": true, "value": "${Log_Value}" }, { "type": "TextBlock", "id": "Guide", "text": "${Guide_Text}", "wrap": true, "size": "Small", "isSubtle": true } ], "actions": [ { "type": "Action.Submit", "id": "OpenList", "title": "${OpenList_Title}", "associatedInputs": "none" }, { "type": "Action.Submit", "id": "OpenHta", "title": "${OpenHta_Title}", "associatedInputs": "none" }, { "type": "Action.Submit", "id": "OpenParent", "title": "${OpenParent_Title}", "associatedInputs": "none" }, { "type": "Action.Submit", "id": "Retry", "title": "${Retry_Title}", "associatedInputs": "none" }, { "type": "Action.Submit", "id": "Close", "title": "${Close_Title}", "associatedInputs": "none" } ], "FormTitle": "${Form_Title}" }''' CustomFormData=> ResultData ButtonPressed=> ResultButton @Summary_Text: SummaryText @Parent_Text: DstParent @Log_Value: LogText @Log_Label: Msg['画面_結果ログ欄'] @Guide_Text: Msg['画面_結果案内'] @OpenList_Title: Msg['画面_ID一覧を開く'] @OpenHta_Title: Msg['画面_ID一覧HTA'] @OpenParent_Title: Msg['画面_親を開く'] @Retry_Title: Msg['画面_再試行'] @Close_Title: Msg['画面_閉じる'] @Form_Title: Msg['画面_結果タイトル'] ON ERROR GOTO Quit END IF ResultButton = $'''OpenList''' THEN IF IsNotEmpty(Result['listHtml']) THEN System.RunApplication.RunApplication WindowStyle: System.ProcessWindowStyle.Normal WorkingDirectory: $'''%DstParent%''' ApplicationPath: $'''%Result['listHtml']%''' CommandLineArguments: $'''''' ProcessId=> OpenPid ON ERROR GOTO Opened END END LABEL Opened GOTO ShowResult END IF ResultButton = $'''OpenHta''' THEN IF IsNotEmpty(Result['listHta']) THEN System.RunApplication.RunApplication WindowStyle: System.ProcessWindowStyle.Normal WorkingDirectory: $'''%DstParent%''' ApplicationPath: $'''mshta.exe''' CommandLineArguments: $'''"%Result['listHta']%"''' ProcessId=> OpenPid ON ERROR GOTO Opened3 END END LABEL Opened3 GOTO ShowResult END IF ResultButton = $'''OpenParent''' THEN System.RunApplication.RunApplication WindowStyle: System.ProcessWindowStyle.Normal WorkingDirectory: $'''%DstParent%''' ApplicationPath: $'''explorer.exe''' CommandLineArguments: $'''"%DstParent%"''' ProcessId=> OpenPid ON ERROR GOTO Opened2 END LABEL Opened2 GOTO ShowResult END IF ResultButton = $'''Retry''' THEN SET Notice TO $'''前回の入力を直して再実行できます。移動元に残っている PDF が対象です。''' GOTO ShowInput END EXIT Code: 0 LABEL Quit EXIT Code: 0 **ENDREGION