534 lines
20 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 家具导出插件 - 安装包生成脚本
# 生成一个“解压后双击 安装.bat 即可安装”的简化安装包。
#
# 关键设计:
# - 设计师侧仍然只接触 .bat(双击即可),但核心逻辑用 PowerShell 执行。
# - 原因:部分机器的 AutoCAD Profile 名称可能包含 << >>,在 cmd/bat 的 for /f 子命令里
# 很容易触发重定向解析,导致 TRUSTEDPATHS 写入失败 -> 插件无法自启动(每次都要 NETLOAD)。
$ErrorActionPreference = "Stop"
function Write-TextFileUtf8NoBom {
param(
[Parameter(Mandatory = $true)][string]$Path,
[Parameter(Mandatory = $true)][string]$Content
)
# Windows 下的脚本/文本统一 CRLF,避免 cmd/某些编辑器对 LF-only 解析异常
$normalized = $Content.Replace("`r`n", "`n").Replace("`n", "`r`n")
$utf8NoBom = New-Object System.Text.UTF8Encoding($false)
[System.IO.File]::WriteAllText($Path, $normalized, $utf8NoBom)
}
function Write-TextFileUtf8Bom {
param(
[Parameter(Mandatory = $true)][string]$Path,
[Parameter(Mandatory = $true)][string]$Content
)
# Windows PowerShell 5.1 对“UTF-8 无 BOM”的脚本兼容性很差(常见表现:中文乱码甚至解析报错)。
# 设计师侧会通过 powershell.exe 执行 install.ps1 / uninstall.ps1,因此这里强制写入 UTF-8 BOM。
$normalized = $Content.Replace("`r`n", "`n").Replace("`n", "`r`n")
$utf8Bom = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText($Path, $normalized, $utf8Bom)
}
function Write-TextFileGbk {
param(
[Parameter(Mandatory = $true)][string]$Path,
[Parameter(Mandatory = $true)][string]$Content
)
# cmd 解析 bat 对编码/换行很敏感:使用 GBK + CRLF 兼容中文环境
$normalized = $Content.Replace("`r`n", "`n").Replace("`n", "`r`n")
$gbk = [System.Text.Encoding]::GetEncoding(936)
[System.IO.File]::WriteAllText($Path, $normalized, $gbk)
}
Write-Host "========================================" -ForegroundColor Cyan
Write-Host " 家具导出插件 - 安装包生成器" -ForegroundColor Cyan
Write-Host "========================================" -ForegroundColor Cyan
Write-Host ""
# 路径设置
$PluginName = "FurnitureExporter"
$Version = "2.6.0"
$SourceDir = Join-Path $PSScriptRoot "FurnitureExporter"
$InstallerDir = Join-Path $PSScriptRoot "installer"
$OutputDir = Join-Path $PSScriptRoot "dist"
$OutputName = "家具导出插件-v${Version}-一键安装版"
$DllSourcePath = Join-Path $SourceDir "bin\\Release\\net48\\FurnitureExporter.dll"
$PdbSourcePath = Join-Path $SourceDir "bin\\Release\\net48\\FurnitureExporter.pdb"
if (-not (Test-Path $DllSourcePath)) {
Write-Host "❌ 未找到编译好的 DLL:$DllSourcePath" -ForegroundColor Red
Write-Host "请先运行 build.ps1(或 dotnet build -c Release)编译插件" -ForegroundColor Yellow
exit 1
}
# 清理并创建安装目录
if (Test-Path $InstallerDir) {
Remove-Item -Path $InstallerDir -Recurse -Force
}
New-Item -ItemType Directory -Path $InstallerDir -Force | Out-Null
Write-Host "📦 正在准备安装包文件..." -ForegroundColor Yellow
# 1) 创建 Bundle 目录结构
$BundleDir = Join-Path $InstallerDir "${PluginName}.bundle"
$ContentsDir = Join-Path $BundleDir "Contents"
New-Item -ItemType Directory -Path $ContentsDir -Force | Out-Null
# 2) 复制 DLL / PDB
Copy-Item -Path $DllSourcePath -Destination $ContentsDir -Force
if (Test-Path $PdbSourcePath) {
Copy-Item -Path $PdbSourcePath -Destination $ContentsDir -Force
}
# 3) PackageContents.xml
$PackageXml = @"
<?xml version="1.0" encoding="utf-8"?>
<ApplicationPackage
SchemaVersion="1.0"
AutodeskProduct="AutoCAD"
Name="$PluginName"
Description="家具导出插件 v$Version - 默认资产中心单资产导出,保留整套兼容导出"
Author="Furniture 3D System"
AppVersion="$Version"
FriendlyVersion="$Version"
ProductType="Application"
Version="$Version"
ProductCode="{A1B2C3D4-E5F6-7890-ABCD-EF1234567890}">
<CompanyDetails
Name="Furniture 3D System"
Email="support@example.com" />
<RuntimeRequirements
OS="Win64"
Platform="AutoCAD*"
SeriesMin="R24.0"
SeriesMax="R24.3" />
<Components Description="AutoCAD 2024">
<RuntimeRequirements
OS="Win64"
Platform="AutoCAD*"
SeriesMin="R24.0"
SeriesMax="R24.3" />
<ComponentEntry
AppName="$PluginName"
Version="$Version"
ModuleName="./Contents/$PluginName.dll"
AppDescription="家具导出插件 - 默认资产中心单资产导出,保留整套兼容导出"
LoadOnAutoCADStartup="True"
AppType="Net" />
</Components>
</ApplicationPackage>
"@
Write-TextFileUtf8NoBom -Path (Join-Path $BundleDir "PackageContents.xml") -Content $PackageXml
# 4) 安装/卸载 PowerShell 脚本(核心逻辑)
$InstallPs1 = @'
# 家具导出插件 - 一键安装脚本(PowerShell)
# 目标:
# 1) 复制 bundle 到当前用户:%AppData%\Autodesk\ApplicationPlugins
# 2) 写入 AutoCAD 2024 自启动注册表(避免每次 NETLOAD)
# 3) 追加可信路径 TRUSTEDPATHS(SECURELOAD=1 时必须,否则不自动加载)
$ErrorActionPreference = "Stop"
function Write-Step {
param([string]$Text)
Write-Host $Text -ForegroundColor Cyan
}
function Test-IsAdmin {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
$principal = New-Object Security.Principal.WindowsPrincipal($identity)
return $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
}
function Add-TrustedPath {
param(
[AllowNull()][string]$Existing,
[Parameter(Mandatory = $true)][string]$PathToAdd
)
$normalizedAdd = $PathToAdd.Trim().TrimEnd('\')
$items = @()
if ($Existing) {
$items = $Existing.Split(';') | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }
}
if (-not $items -or $items.Count -eq 0) {
# 保留 AutoCAD 常见默认值,避免误删用户原本设置
$items = @("APP_PATH")
}
$exists = $false
foreach ($it in $items) {
if ($it.Trim().TrimEnd('\').Equals($normalizedAdd, [StringComparison]::OrdinalIgnoreCase)) {
$exists = $true
break
}
}
if (-not $exists) {
$items += $PathToAdd
}
# 去重(忽略大小写 + 末尾反斜杠)
$seen = New-Object "System.Collections.Generic.HashSet[string]" ([StringComparer]::OrdinalIgnoreCase)
$dedup = New-Object System.Collections.Generic.List[string]
foreach ($it in $items) {
$k = $it.Trim().TrimEnd('\')
if ($seen.Add($k)) {
$dedup.Add($it.Trim())
}
}
return ($dedup -join ";")
}
Write-Step "[0/3] 环境检查..."
if (Get-Process acad -ErrorAction SilentlyContinue) {
Write-Host ""
Write-Host "注意:检测到 AutoCAD 正在运行 (acad.exe)。" -ForegroundColor Yellow
Write-Host "为避免 DLL 被占用导致复制/删除失败,建议先完全关闭 AutoCAD 再安装。" -ForegroundColor Yellow
Write-Host ""
}
if (Test-IsAdmin) {
Write-Host ""
Write-Host "注意:你正在以管理员身份运行。" -ForegroundColor Yellow
Write-Host "本插件按“当前 Windows 用户”安装(%AppData% + HKCU 注册表)。" -ForegroundColor Yellow
Write-Host "如果不是在设计师账号下运行,安装后可能在设计师账号下不生效。" -ForegroundColor Yellow
Write-Host ""
}
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
$bundleSrc = Join-Path $scriptDir "FurnitureExporter.bundle"
# 兼容“解压覆盖旧目录”导致的套娃结构:FurnitureExporter.bundle\FurnitureExporter.bundle\...
if (-not (Test-Path (Join-Path $bundleSrc "PackageContents.xml"))) {
$nested = Join-Path $bundleSrc "FurnitureExporter.bundle"
if (Test-Path (Join-Path $nested "PackageContents.xml")) {
$bundleSrc = $nested
}
}
if (-not (Test-Path (Join-Path $bundleSrc "PackageContents.xml"))) {
Write-Host "未找到 FurnitureExporter.bundle(请先解压安装包,再运行 安装.bat)。" -ForegroundColor Red
exit 1
}
$appPlugins = Join-Path $env:APPDATA "Autodesk\ApplicationPlugins"
$bundleDst = Join-Path $appPlugins "FurnitureExporter.bundle"
$dllPath = Join-Path $bundleDst "Contents\FurnitureExporter.dll"
$trustedDir = Join-Path $bundleDst "Contents"
Write-Step "[1/3] 复制插件..."
New-Item -ItemType Directory -Path $appPlugins -Force | Out-Null
if (Test-Path $bundleDst) {
try {
Remove-Item -Path $bundleDst -Recurse -Force
}
catch {
Write-Host ""
Write-Host "删除旧版本失败:$bundleDst" -ForegroundColor Red
Write-Host "常见原因:AutoCAD 未完全关闭/文件被占用/安全软件拦截。" -ForegroundColor Yellow
Write-Host "请关闭 AutoCAD 后重试,或手动删除上述目录。" -ForegroundColor Yellow
Write-Host ""
throw
}
}
Copy-Item -Path $bundleSrc -Destination $bundleDst -Recurse -Force
if (-not (Test-Path $dllPath)) {
Write-Host "安装失败:未找到 DLL:$dllPath" -ForegroundColor Red
exit 1
}
Write-Step "[2/3] 注册自启动/可信路径..."
$acadRoot = "HKCU:\Software\Autodesk\AutoCAD\R24.3"
$curVerObj = Get-ItemProperty -Path $acadRoot -Name CurVer -ErrorAction SilentlyContinue
$acadCur = $curVerObj.CurVer
if (-not $acadCur) {
Write-Host "未检测到 AutoCAD 2024 注册表信息:$acadRoot\CurVer" -ForegroundColor Yellow
Write-Host "已完成文件复制,但未写入自启动注册。请确认已至少启动过 AutoCAD 2024 一次。" -ForegroundColor Yellow
}
else {
$acadBase = Join-Path $acadRoot $acadCur
# 1) Applications 自启动(.NET 插件标准方式)
$appKey = Join-Path $acadBase "Applications\FurnitureExporter"
New-Item -Path $appKey -Force | Out-Null
New-ItemProperty -Path $appKey -Name "DESCRIPTION" -PropertyType String -Value "家具导出插件 v$Version" -Force | Out-Null
New-ItemProperty -Path $appKey -Name "LOADCTRLS" -PropertyType DWord -Value 2 -Force | Out-Null
New-ItemProperty -Path $appKey -Name "MANAGED" -PropertyType DWord -Value 1 -Force | Out-Null
New-ItemProperty -Path $appKey -Name "LOADER" -PropertyType String -Value $dllPath -Force | Out-Null
# 2) 可信路径:只加入本插件 Contents,避免把整个 ApplicationPlugins 目录设为可信
$profilesRoot = Join-Path $acadBase "Profiles"
$profiles = Get-ChildItem -Path $profilesRoot -ErrorAction SilentlyContinue
foreach ($p in $profiles) {
$varsKey = Join-Path $p.PSPath "Variables"
if (-not (Test-Path $varsKey)) { continue }
$vars = Get-ItemProperty -Path $varsKey -ErrorAction SilentlyContinue
$existingTrusted = $null
if ($vars.PSObject.Properties.Name -contains "TRUSTEDPATHS") {
$existingTrusted = [string]$vars.TRUSTEDPATHS
}
$newTrusted = Add-TrustedPath -Existing $existingTrusted -PathToAdd $trustedDir
if ($existingTrusted -ne $newTrusted) {
New-ItemProperty -Path $varsKey -Name "TRUSTEDPATHS" -PropertyType String -Value $newTrusted -Force | Out-Null
}
# 如果 SECURELOAD=2,会导致即使加入可信路径也不加载(尽量只从 2 降到 1)
if ($vars.PSObject.Properties.Name -contains "SECURELOAD") {
if ([string]$vars.SECURELOAD -eq "2") {
New-ItemProperty -Path $varsKey -Name "SECURELOAD" -PropertyType String -Value "1" -Force | Out-Null
}
}
}
}
Write-Step "[3/3] 完成"
Write-Host ""
Write-Host "安装完成。请完全关闭 AutoCAD 后重新启动。" -ForegroundColor Green
Write-Host "启动后命令行输入:FEXPORT(单资产)或 FEXPORTPRODUCT(整套兼容)" -ForegroundColor Green
Write-Host ""
'@
Write-TextFileUtf8Bom -Path (Join-Path $InstallerDir "install.ps1") -Content $InstallPs1
$UninstallPs1 = @'
# 家具导出插件 - 一键卸载脚本(PowerShell)
# 目标:删除当前用户 ApplicationPlugins 下的 bundle,并清理自启动注册/可信路径。
$ErrorActionPreference = "Stop"
function Write-Step {
param([string]$Text)
Write-Host $Text -ForegroundColor Cyan
}
function Remove-TrustedPath {
param(
[AllowNull()][string]$Existing,
[Parameter(Mandatory = $true)][string]$PathToRemove
)
if (-not $Existing) { return $Existing }
$normalizedRemove = $PathToRemove.Trim().TrimEnd('\')
$items = $Existing.Split(';') | ForEach-Object { $_.Trim() } | Where-Object { $_ -ne "" }
$kept = New-Object System.Collections.Generic.List[string]
foreach ($it in $items) {
$k = $it.Trim().TrimEnd('\')
if (-not $k.Equals($normalizedRemove, [StringComparison]::OrdinalIgnoreCase)) {
$kept.Add($it.Trim())
}
}
return ($kept -join ";")
}
Write-Step "[0/3] 环境检查..."
if (Get-Process acad -ErrorAction SilentlyContinue) {
Write-Host ""
Write-Host "注意:检测到 AutoCAD 正在运行 (acad.exe)。" -ForegroundColor Yellow
Write-Host "如卸载失败,请先完全关闭 AutoCAD 后再重试。" -ForegroundColor Yellow
Write-Host ""
}
$appPlugins = Join-Path $env:APPDATA "Autodesk\ApplicationPlugins"
$bundleDst = Join-Path $appPlugins "FurnitureExporter.bundle"
$trustedDir = Join-Path $bundleDst "Contents"
Write-Step "[1/3] 删除插件文件..."
if (Test-Path $bundleDst) {
try {
Remove-Item -Path $bundleDst -Recurse -Force
}
catch {
Write-Host ""
Write-Host "删除失败:$bundleDst" -ForegroundColor Red
Write-Host "常见原因:AutoCAD 未完全关闭/文件被占用/安全软件拦截。" -ForegroundColor Yellow
Write-Host "你也可以手动删除该目录后,再运行 卸载.bat 清理注册表。" -ForegroundColor Yellow
Write-Host ""
throw
}
}
Write-Step "[2/3] 清理注册表..."
$acadRoot = "HKCU:\Software\Autodesk\AutoCAD\R24.3"
$curVerObj = Get-ItemProperty -Path $acadRoot -Name CurVer -ErrorAction SilentlyContinue
$acadCur = $curVerObj.CurVer
if ($acadCur) {
$acadBase = Join-Path $acadRoot $acadCur
# Applications 自启动项
$appKey = Join-Path $acadBase "Applications\FurnitureExporter"
if (Test-Path $appKey) {
Remove-Item -Path $appKey -Recurse -Force -ErrorAction SilentlyContinue
}
# TRUSTEDPATHS 移除插件 Contents(只移除我们加的这一项,避免影响其他插件)
$profilesRoot = Join-Path $acadBase "Profiles"
$profiles = Get-ChildItem -Path $profilesRoot -ErrorAction SilentlyContinue
foreach ($p in $profiles) {
$varsKey = Join-Path $p.PSPath "Variables"
if (-not (Test-Path $varsKey)) { continue }
$vars = Get-ItemProperty -Path $varsKey -ErrorAction SilentlyContinue
if (-not ($vars.PSObject.Properties.Name -contains "TRUSTEDPATHS")) { continue }
$existingTrusted = [string]$vars.TRUSTEDPATHS
$newTrusted = Remove-TrustedPath -Existing $existingTrusted -PathToRemove $trustedDir
if ($existingTrusted -ne $newTrusted) {
if ([string]::IsNullOrWhiteSpace($newTrusted)) {
Remove-ItemProperty -Path $varsKey -Name "TRUSTEDPATHS" -ErrorAction SilentlyContinue
}
else {
New-ItemProperty -Path $varsKey -Name "TRUSTEDPATHS" -PropertyType String -Value $newTrusted -Force | Out-Null
}
}
}
}
else {
Write-Host "未检测到 AutoCAD 2024 注册表信息,跳过注册表清理。" -ForegroundColor Yellow
}
Write-Step "[3/3] 完成"
Write-Host ""
Write-Host "卸载完成。请完全关闭 AutoCAD 后重新启动。" -ForegroundColor Green
Write-Host ""
'@
Write-TextFileUtf8Bom -Path (Join-Path $InstallerDir "uninstall.ps1") -Content $UninstallPs1
# 5) bat 入口(只负责启动 PowerShell 脚本)
$InstallBat = @'
@echo off
setlocal EnableExtensions
title 家具导出插件 安装程序
set "SCRIPT_DIR=%~dp0"
if not exist "%SCRIPT_DIR%install.ps1" (
echo 未找到 install.ps1
echo 请先解压安装包到当前目录后再运行。
echo.
pause
exit /b 1
)
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%install.ps1"
echo.
pause
endlocal
'@
Write-TextFileGbk -Path (Join-Path $InstallerDir "安装.bat") -Content $InstallBat
$UninstallBat = @'
@echo off
setlocal EnableExtensions
title 家具导出插件 卸载程序
set "SCRIPT_DIR=%~dp0"
if not exist "%SCRIPT_DIR%uninstall.ps1" (
echo 未找到 uninstall.ps1
echo 请先解压安装包到当前目录后再运行。
echo.
pause
exit /b 1
)
powershell.exe -NoProfile -ExecutionPolicy Bypass -File "%SCRIPT_DIR%uninstall.ps1"
echo.
pause
endlocal
'@
Write-TextFileGbk -Path (Join-Path $InstallerDir "卸载.bat") -Content $UninstallBat
# 6) 使用说明
$Readme = @"
═══════════════════════════════════════════════════════════════════════
家具导出插件 v$Version - 安装指南
═══════════════════════════════════════════════════════════════════════
安装步骤(只需30秒)
───────────────────────────────────────────────────────────────────────
1) 解压安装包
2) 双击运行:安装.bat
3) 完全关闭 AutoCAD 2024 后重新启动
卸载步骤(只需10秒)
───────────────────────────────────────────────────────────────────────
1) 双击运行:卸载.bat
2) 完全关闭 AutoCAD 2024 后重新启动
使用方法
───────────────────────────────────────────────────────────────────────
打开 AutoCAD 后,命令行输入:
FEXPORT -> 单资产导出到资产中心(板材 / 组件 / 五金)
FEXPORTASSET -> 单资产导出别名
FEXPORTPRODUCT -> 整套家具兼容导出
FEXPORTBUNDLE -> 整套家具兼容导出别名
FINFO -> 查看实体信息
安装脚本做了什么(便于 IT/排查)
───────────────────────────────────────────────────────────────────────
1) 复制到:
%AppData%\Autodesk\ApplicationPlugins\FurnitureExporter.bundle
2) 注册自启动(HKCU):
HKCU\Software\Autodesk\AutoCAD\R24.3\<CurVer>\Applications\FurnitureExporter
3) 追加可信路径(HKCU / 每个 Profile):
TRUSTEDPATHS += ...\FurnitureExporter.bundle\Contents
常见问题
───────────────────────────────────────────────────────────────────────
Q: 提示“未知命令 FEXPORT / FEXPORTPRODUCT”
A: 1) 确认已重启 AutoCAD(关闭再打开)
2) 确认插件目录存在:
%AppData%\Autodesk\ApplicationPlugins\FurnitureExporter.bundle\Contents\FurnitureExporter.dll
3) 如果 SECURELOAD=2,脚本会将其降到 1;如仍无效请截图安装日志给开发排查
版本: v$Version
"@
Write-TextFileUtf8NoBom -Path (Join-Path $InstallerDir "使用说明.txt") -Content $Readme
# 7) 打包为 ZIP(并同时输出一个可直接双击测试的目录)
Write-Host "📦 正在生成安装包..." -ForegroundColor Yellow
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
$ZipPath = Join-Path $OutputDir "$OutputName.zip"
Compress-Archive -Path (Join-Path $InstallerDir "*") -DestinationPath $ZipPath -Force
$StagingDir = Join-Path $OutputDir $OutputName
if (Test-Path $StagingDir) {
Remove-Item -Path $StagingDir -Recurse -Force
}
New-Item -ItemType Directory -Path $StagingDir -Force | Out-Null
Copy-Item -Path (Join-Path $InstallerDir "*") -Destination $StagingDir -Recurse -Force
Write-Host ""
Write-Host "========================================" -ForegroundColor Green
Write-Host " ✅ 安装包生成成功!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host ""
Write-Host "输出文件:" -ForegroundColor Cyan
Write-Host " - $ZipPath"
Write-Host " - $StagingDir"
Write-Host ""