@echo off setlocal :: Check for admin privileges, auto-elevate if needed net session >nul 2>&1 if %ERRORLEVEL% NEQ 0 ( PowerShell -Command "Start-Process -FilePath '%~f0' -Verb RunAs" exit /b ) set "TARGET_DIR=%PROGRAMDATA%\Autodesk\Navisworks Manage 2026\plugins\TransportPlugin" set "BUILD_DIR=%~dp0bin\x64\Release" pwsh -NoProfile -ExecutionPolicy Bypass -Command ^ "$ErrorActionPreference = 'Stop';" ^ "$targetDir = [System.IO.Path]::GetFullPath('%TARGET_DIR%');" ^ "$buildDir = [System.IO.Path]::GetFullPath('%BUILD_DIR%');" ^ "$deployDllNames = @(" ^ " 'TransportPlugin.dll'," ^ " 'geometry4Sharp.dll'," ^ " 'Newtonsoft.Json.dll'," ^ " 'Roy-T.AStar.dll'," ^ " 'SQLite.Interop.dll'," ^ " 'System.Data.SQLite.dll'," ^ " 'Tomlyn.dll'" ^ ");" ^ "$deployRootFiles = @(" ^ " 'TransportRibbon.xaml'," ^ " 'TransportRibbon_16.png'," ^ " 'TransportRibbon_32.png'" ^ ");" ^ "$stalePluginFiles = @(" ^ " 'Autodesk.Navisworks.Api.dll'," ^ " 'NavisworksTransport.UnitTests.dll'," ^ " 'Microsoft.VisualStudio.TestPlatform.TestFramework.dll'," ^ " 'Microsoft.VisualStudio.TestPlatform.TestFramework.Extensions.dll'" ^ ");" ^ "function Test-FileUnlocked([string]$path) {" ^ " if (-not (Test-Path $path)) { return $true }" ^ " try {" ^ " $stream = [System.IO.File]::Open($path, [System.IO.FileMode]::Open, [System.IO.FileAccess]::ReadWrite, [System.IO.FileShare]::None);" ^ " $stream.Close();" ^ " return $true;" ^ " } catch {" ^ " return $false;" ^ " }" ^ "}" ^ "function Wait-FileUnlocked([string]$path, [datetime]$deadline) {" ^ " while (-not (Test-FileUnlocked $path)) {" ^ " if ((Get-Date) -ge $deadline) { throw ('Target file still locked: ' + $path) }" ^ " Start-Sleep -Milliseconds 500;" ^ " }" ^ "}" ^ "" ^ "Get-Process Roamer -ErrorAction SilentlyContinue | Stop-Process -Force -ErrorAction SilentlyContinue;" ^ "$deadline = (Get-Date).AddSeconds(15);" ^ "while (Get-Process Roamer -ErrorAction SilentlyContinue) {" ^ " if ((Get-Date) -ge $deadline) { throw 'Roamer.exe still running after 15 seconds.' }" ^ " Start-Sleep -Milliseconds 500;" ^ "}" ^ "$keyTargetFiles = @(" ^ " (Join-Path $targetDir 'TransportPlugin.dll')," ^ " (Join-Path $targetDir 'geometry4Sharp.dll')," ^ " (Join-Path (Join-Path $targetDir 'resources') 'unit_cube.nwc')," ^ " (Join-Path (Join-Path $targetDir 'resources') 'unit_cylinder.nwc')" ^ ");" ^ "foreach ($keyFile in $keyTargetFiles) { Wait-FileUnlocked $keyFile $deadline }" ^ "" ^ "New-Item -ItemType Directory -Force -Path $targetDir | Out-Null;" ^ "foreach ($staleFileName in $stalePluginFiles) {" ^ " $stalePath = Join-Path $targetDir $staleFileName;" ^ " if (Test-Path $stalePath) { Remove-Item $stalePath -Force }" ^ "}" ^ "foreach ($dllName in $deployDllNames) {" ^ " $sourceDll = Join-Path $buildDir $dllName;" ^ " if (-not (Test-Path $sourceDll)) { throw ('Deployment source file missing: ' + $sourceDll) }" ^ " Copy-Item $sourceDll $targetDir -Force;" ^ "}" ^ "foreach ($rootFileName in $deployRootFiles) {" ^ " $sourceRootFile = Join-Path $buildDir $rootFileName;" ^ " if (Test-Path $sourceRootFile) {" ^ " Copy-Item $sourceRootFile $targetDir -Force;" ^ " foreach ($locale in @('en-US','zh-CN')) {" ^ " $localeDir = Join-Path $targetDir $locale;" ^ " New-Item -ItemType Directory -Force -Path $localeDir | Out-Null;" ^ " Copy-Item $sourceRootFile $localeDir -Force;" ^ " }" ^ " }" ^ "}" ^ "if (Test-Path (Join-Path $buildDir 'resources')) {" ^ " New-Item -ItemType Directory -Force -Path (Join-Path $targetDir 'resources') | Out-Null;" ^ " Copy-Item (Join-Path $buildDir 'resources\\*') (Join-Path $targetDir 'resources') -Recurse -Force;" ^ "}" ^ "" ^ "$sourceFiles = @();" ^ "foreach ($dllName in $deployDllNames) { $sourceFiles += Get-Item (Join-Path $buildDir $dllName) }" ^ "foreach ($rootFileName in $deployRootFiles) {" ^ " $sourceRootFile = Join-Path $buildDir $rootFileName;" ^ " if (Test-Path $sourceRootFile) { $sourceFiles += Get-Item $sourceRootFile }" ^ "}" ^ "if (Test-Path (Join-Path $buildDir 'resources')) {" ^ " $sourceFiles += Get-ChildItem (Join-Path $buildDir 'resources') -File;" ^ "}" ^ "" ^ "foreach ($sourceFile in $sourceFiles) {" ^ " $targetFile = if ($sourceFile.DirectoryName -eq $buildDir) { Join-Path $targetDir $sourceFile.Name } else { Join-Path (Join-Path $targetDir 'resources') $sourceFile.Name };" ^ " if (-not (Test-Path $targetFile)) { throw ('Deployment verification failed: missing target file ' + $targetFile) }" ^ " $targetInfo = Get-Item $targetFile;" ^ " if ($sourceFile.Length -ne $targetInfo.Length -or $sourceFile.LastWriteTime -ne $targetInfo.LastWriteTime) {" ^ " throw ('Deployment verification failed for ' + $sourceFile.Name + ': source=' + $sourceFile.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff') + ' (' + $sourceFile.Length + '), target=' + $targetInfo.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff') + ' (' + $targetInfo.Length + ')');" ^ " }" ^ " Write-Host ('Verified ' + $sourceFile.Name + ': ' + $targetInfo.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff'));" ^ " if ($deployRootFiles -contains $sourceFile.Name) {" ^ " foreach ($locale in @('en-US','zh-CN')) {" ^ " $localeTargetFile = Join-Path (Join-Path $targetDir $locale) $sourceFile.Name;" ^ " if (-not (Test-Path $localeTargetFile)) { throw ('Deployment verification failed: missing locale target file ' + $localeTargetFile) }" ^ " $localeTargetInfo = Get-Item $localeTargetFile;" ^ " if ($sourceFile.Length -ne $localeTargetInfo.Length -or $sourceFile.LastWriteTime -ne $localeTargetInfo.LastWriteTime) {" ^ " throw ('Deployment verification failed for locale copy ' + $localeTargetFile);" ^ " }" ^ " Write-Host ('Verified ' + $locale + '\\' + $sourceFile.Name + ': ' + $localeTargetInfo.LastWriteTime.ToString('yyyy-MM-dd HH:mm:ss.fff'));" ^ " }" ^ " }" ^ "}" ^ "" ^ "Write-Host 'Plugin deployed successfully!';" if errorlevel 1 exit /b 1 exit /b 0