提交 4a80cb90 authored 作者: 陈泽健's avatar 陈泽健

docs(service-self-inspection): 添加服务自检脚本执行时的问题处理文档以及修复展厅巡检预定系统相关定位元素改变的问题

- 添加_PRD_MQTT工具包路径获取异常_问题处理文档
- 添加_PRD_MQTT工具执行异常_问题处理文档
- 更新中间件检测执行异常问题处理文档,增加FastDFS脚本执行错误问题
- 添加_PRD_日志导出失败_问题处理文档
- 更新模块加载异常问题处理文档,增加ConfigIPCheck模块编码问题
- 完善各问题处理文档的错误信息记录和解决方案说明
上级 70f1feed
......@@ -106,7 +106,11 @@
"Bash(more)",
"Bash(timeout 3)",
"Bash(Out-File -FilePath 'C:\\\\PycharmData\\\\ubains-module-test\\\\AuxiliaryTool\\\\ScriptTool\\\\RemoteUpdate\\\\test_projects.ps1' -Encoding UTF8)",
"Bash(Select-Object -First 5)"
"Bash(Select-Object -First 5)",
"Bash(del:*)",
"Bash(git --no-pager show HEAD:AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules/ConfigIPCheck.psm1)",
"Bash(python:*)",
"Bash(git checkout:*)"
]
}
}
<changelist name="在进行更新之前于_2026_2_5_14_00_取消提交了更改_[更改]" date="1770271259492" recycled="true" deleted="true">
<option name="PATH" value="$PROJECT_DIR$/.idea/shelf/在进行更新之前于_2026_2_5_14_00_取消提交了更改_[更改]/shelved.patch" />
<option name="DESCRIPTION" value="在进行更新之前于 2026/2/5 14:00 取消提交了更改 [更改]" />
</changelist>
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -304,6 +304,7 @@ $ModulesToImport = @(
"ConfigIPCheck.psm1",
"MiddlewareCheck.psm1",
"AndroidCheck.psm1",
"LogExport.psm1",
"Report.psm1"
)
......@@ -349,6 +350,7 @@ $ExpectedFunctions = @(
"Test-TraditionalPlatformIPs",
"Test-NTPService",
"Test-AndroidDeviceHealth",
"Export-ServiceLogs",
"Show-HealthReport"
)
......
# Debug module loading issue
$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
$ModulePath = Join-Path $SCRIPT_DIR "modules"
# Load modules in same order as main script
$ModulesToImport = @(
"ServiceCheck.psm1",
"DNSCheck.psm1",
"ServerResourceAnalysis.psm1",
"NTPCheck.psm1",
"ContainerCheck.psm1",
"ConfigIPCheck.psm1",
"MiddlewareCheck.psm1"
)
# First load Common
$CommonModulePath = Join-Path $ModulePath "Common.psm1"
Import-Module $CommonModulePath -Force -Global -ErrorAction Stop
Write-Host "Common loaded" -ForegroundColor Green
# Then load each module
foreach ($Module in $ModulesToImport) {
$ModuleFilePath = Join-Path $ModulePath $Module
if (Test-Path $ModuleFilePath) {
try {
Import-Module $ModuleFilePath -Force -Global -ErrorAction Stop
Write-Host "Loaded: $Module" -ForegroundColor Green
# Check what functions this module exported
$modName = $Module.Replace(".psm1", "")
$mod = Get-Module $modName
if ($mod) {
Write-Host " Exported: $($mod.ExportedFunctions.Count) functions"
$mod.ExportedFunctions.Keys | ForEach-Object { Write-Host " - $_" }
}
}
catch {
Write-Host "Failed: $Module - $($_.Exception.Message)" -ForegroundColor Red
}
}
}
# Check for ContainerCheck functions
Write-Host "`n=== Final check ===" -ForegroundColor Cyan
$funcs = @("Get-ContainerDetails", "Test-ContainerInformation")
foreach ($f in $funcs) {
$c = Get-Command $f -ErrorAction SilentlyContinue
if ($c) {
Write-Host "[OK] $f from $($c.Source)" -ForegroundColor Green
} else {
Write-Host "[FAIL] $f not found" -ForegroundColor Red
}
}
# Debug - check loaded modules after all imports
$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
$ModulePath = Join-Path $SCRIPT_DIR "modules"
# Load modules in same order as main script
$ModulesToImport = @(
"ServiceCheck.psm1",
"DNSCheck.psm1",
"ServerResourceAnalysis.psm1",
"NTPCheck.psm1",
"ContainerCheck.psm1",
"ConfigIPCheck.psm1",
"MiddlewareCheck.psm1"
)
# First load Common
$CommonModulePath = Join-Path $ModulePath "Common.psm1"
Import-Module $CommonModulePath -Force -Global -ErrorAction Stop
# Then load each module
foreach ($Module in $ModulesToImport) {
$ModuleFilePath = Join-Path $ModulePath $Module
if (Test-Path $ModuleFilePath) {
Import-Module $ModuleFilePath -Force -Global -ErrorAction SilentlyContinue
}
}
# List ALL loaded modules
Write-Host "=== All loaded modules ===" -ForegroundColor Cyan
Get-Module | Where-Object { $_.Name -like "*Check*" } | ForEach-Object {
Write-Host "$($_.Name): $($_.ExportedFunctions.Count) exported functions"
}
# Try using the module directly
Write-Host "`n=== Direct module access ===" -ForegroundColor Cyan
$cc = Get-Module ContainerCheck
if ($cc) {
Write-Host "ContainerCheck module exists: YES"
Write-Host "Functions: $($cc.ExportedFunctions.Count)"
foreach ($f in $cc.ExportedFunctions.Keys) {
Write-Host " - $f"
}
# Try to call function via module
Write-Host "`nTrying to call via & $cc\Test-ContainerInformation"
try {
& $cc\Get-ContainerDetails | Out-Null
Write-Host " Works via module reference!" -ForegroundColor Green
} catch {
Write-Host " Failed: $_" -ForegroundColor Red
}
} else {
Write-Host "ContainerCheck module: NOT FOUND" -ForegroundColor Red
}
# ==============================================================================
# 诊断脚本 - 检查模块加载问题
# ==============================================================================
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host " 模块加载诊断" -ForegroundColor Cyan
Write-Host "========================================`n" -ForegroundColor Cyan
# 1. 检查脚本目录
$SCRIPT_DIR = Split-Path -Parent $MyInvocation.MyCommand.Path
Write-Host "[1] 脚本目录: $SCRIPT_DIR" -ForegroundColor Yellow
# 2. 检查模块目录
$ModulePath = Join-Path $SCRIPT_DIR "modules"
Write-Host "`n[2] 模块目录检查:" -ForegroundColor Yellow
if (Test-Path $ModulePath) {
Write-Host " 模块目录存在: $ModulePath" -ForegroundColor Green
$moduleFiles = Get-ChildItem -Path $ModulePath -Filter "*.psm1" | Select-Object -ExpandProperty Name
Write-Host " 找到 $($moduleFiles.Count) 个模块文件:" -ForegroundColor Green
foreach ($file in $moduleFiles) {
Write-Host " - $file" -ForegroundColor White
}
} else {
Write-Host " 模块目录不存在: $ModulePath" -ForegroundColor Red
Write-Host " 请确保将整个 ServiceSelfInspection 目录(包括 modules/)复制到运行位置!" -ForegroundColor Red
}
# 3. 检查 ContainerCheck 模块
Write-Host "`n[3] ContainerCheck 模块检查:" -ForegroundColor Yellow
$containerCheckPath = Join-Path $ModulePath "ContainerCheck.psm1"
if (Test-Path $containerCheckPath) {
Write-Host " ContainerCheck.psm1 存在" -ForegroundColor Green
# 检查函数是否定义
$content = Get-Content $containerCheckPath -Raw
if ($content -match 'function Test-ContainerInformation') {
Write-Host " Test-ContainerInformation 函数已定义" -ForegroundColor Green
} else {
Write-Host " Test-ContainerInformation 函数未定义!" -ForegroundColor Red
}
# 检查导出
if ($content -match 'Export-ModuleMember.*Test-ContainerInformation') {
Write-Host " Test-ContainerInformation 已导出" -ForegroundColor Green
} else {
Write-Host " Test-ContainerInformation 未导出!" -ForegroundColor Red
}
} else {
Write-Host " ContainerCheck.psm1 不存在!" -ForegroundColor Red
}
# 4. 尝试加载模块
Write-Host "`n[4] 尝试加载模块:" -ForegroundColor Yellow
try {
$CommonModulePath = Join-Path $ModulePath "Common.psm1"
if (Test-Path $CommonModulePath) {
Import-Module $CommonModulePath -Force -Global -ErrorAction Stop
Write-Host " Common.psm1 加载成功" -ForegroundColor Green
} else {
Write-Host " Common.psm1 不存在,跳过" -ForegroundColor Yellow
}
Import-Module $containerCheckPath -Force -Global -ErrorAction Stop
Write-Host " ContainerCheck.psm1 加载成功" -ForegroundColor Green
} catch {
Write-Host " 模块加载失败: $($_.Exception.Message)" -ForegroundColor Red
}
# 5. 检查函数是否可用
Write-Host "`n[5] 函数可用性检查:" -ForegroundColor Yellow
$func = Get-Command Test-ContainerInformation -ErrorAction SilentlyContinue
if ($func) {
Write-Host " Test-ContainerInformation 可用" -ForegroundColor Green
Write-Host " 来源模块: $($func.Source)" -ForegroundColor White
} else {
Write-Host " Test-ContainerInformation 不可用!" -ForegroundColor Red
Write-Host " 这是导致报错的原因!" -ForegroundColor Red
}
# 6. 总结
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host " 诊断总结" -ForegroundColor Cyan
Write-Host "========================================`n" -ForegroundColor Cyan
if (-not (Test-Path $ModulePath)) {
Write-Host "问题: modules/ 目录不存在" -ForegroundColor Red
Write-Host "解决: 请将整个 ServiceSelfInspection 目录复制到运行位置,确保包含 modules/ 子目录" -ForegroundColor Yellow
} elseif (-not (Test-Path $containerCheckPath)) {
Write-Host "问题: ContainerCheck.psm1 文件不存在" -ForegroundColor Red
Write-Host "解决: 请确保 modules/ 目录中有 ContainerCheck.psm1 文件" -ForegroundColor Yellow
} elseif (-not (Get-Command Test-ContainerInformation -ErrorAction SilentlyContinue)) {
Write-Host "问题: Test-ContainerInformation 函数不可用" -ForegroundColor Red
Write-Host "解决: 模块可能加载失败,请检查上述错误信息" -ForegroundColor Yellow
} else {
Write-Host "一切正常!模块加载成功,函数可用。" -ForegroundColor Green
}
Write-Host "`n"
# Direct fix script
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
Write-Host "Reading file..."
# Read file
$reader = [System.IO.StreamReader]::new(
[System.IO.File]::Open($ModulePath, [System.IO.FileMode]::Open),
[System.Text.Encoding]::UTF8
)
$content = $reader.ReadToEnd()
$reader.Close()
# Apply fixes
$originalContent = $content
# Fix 1: MQTT
$content = $content -replace "grep -E '$containerName\|emqx'", "grep -wE '$containerName|emqx'"
Write-Host "Applied fix 1: MQTT container detection"
# Fix 2: echo command
$content = $content -replace "|| echo '''", "| echo ""`""
Write-Host "Applied fix 2: echo command"
# Fix 3: bash command (multiple patterns)
$content = $content -replace 'bash ''\$actualScriptPath'' 2>&1', 'bash "$actualScriptPath" 2>&1'
Write-Host "Applied fix 3: script execution command"
# Save if changed
if ($content -ne $originalContent) {
# Backup
$backupPath = $ModulePath + ".backup3"
[System.IO.File]::WriteAllText($backupPath, $originalContent, [System.Text.Encoding]::UTF8)
# Save fixed
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host "File updated successfully" -ForegroundColor Green
} else {
Write-Host "No changes needed" -ForegroundColor Yellow
}
Write-Host ""
Write-Host "Please verify the fixes:" -ForegroundColor Cyan
Write-Host "1. MQTT: grep -wE should be present" -ForegroundColor Cyan
Write-Host "2. echo "" should be used instead of echo '''" -ForegroundColor Cyan
Write-Host "3. bash `"$actualScriptPath`" should be used for script execution" -ForegroundColor Cyan
# 文件编码转换脚本
$utf8BOM = New-Object System.Text.UTF8Encoding $true
$modulePath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules"
$filesToFix = @(
"AndroidCheck.psm1",
"Report.psm1",
"MiddlewareCheck.psm1"
)
foreach ($fileName in $filesToFix) {
$filePath = Join-Path $modulePath $fileName
if (Test-Path $filePath) {
try {
# 读取文件
$content = [System.IO.File]::ReadAllText($filePath)
# 保存为 UTF-8 with BOM
[System.IO.File]::WriteAllText($filePath, $content, $utf8BOM)
Write-Host "已转换: $fileName" -ForegroundColor Green
}
catch {
Write-Host "转换失败: $fileName - $($_.Exception.Message)" -ForegroundColor Red
}
}
}
Write-Host "`n完成!验证模块加载..." -ForegroundColor Cyan
# 验证模块加载
$successCount = 0
$failCount = 0
foreach ($fileName in $filesToFix) {
$filePath = Join-Path $modulePath $fileName
try {
Import-Module $filePath -Force -ErrorAction Stop
$successCount++
Write-Host " 成功: $fileName" -ForegroundColor Green
}
catch {
$failCount++
Write-Host " 失败: $fileName" -ForegroundColor Red
}
}
Write-Host "`n结果: 成功=$successCount, 失败=$failCount" -ForegroundColor Cyan
# Middleware check module fix script
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
Write-Host "Reading file..." -ForegroundColor Cyan
# Read file as bytes and handle BOM
$bytes = [System.IO.File]::ReadAllBytes($ModulePath)
$offset = 0
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
$offset = 3
}
$content = [System.Text.Encoding]::UTF8.GetString($bytes, $offset, $bytes.Length - $offset)
# Apply fixes
$content = $content -replace "grep -E '\$containerName\|emqx'", "grep -wE '$containerName|emqx'"
Write-Host "Fixed MQTT container detection" -ForegroundColor Green
$content = $content -replace '\| echo '''', '| echo ""'
Write-Host "Fixed echo command" -ForegroundColor Green
$content = $content -replace "bash '\$actualScriptPath' 2>&1", 'bash "$actualScriptPath" 2>&1'
Write-Host "Fixed script execution command" -ForegroundColor Green
# Save backup and fixed file
[System.IO.File]::WriteAllBytes($ModulePath + ".backup", $bytes)
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host ""
Write-Host "Fix completed!" -ForegroundColor Green
# ==============================================================================
# fix_middleware_check.ps1
# ------------------------------------------------------------------------------
# 中间件检测模块修复脚本
#
# .SYNOPSIS
# 修复 MiddlewareCheck.psm1 模块中的脚本路径和执行命令问题
#
# .DESCRIPTION
# 本脚本修复以下问题:
# 1. MQTT 容器检测:添加 -w 参数进行精确单词匹配
# 2. Redis/MySQL/FastDFS 检测:修复远程目录检测和脚本执行命令
#
# .NOTES
# 版本:1.0.0
# 创建日期:2026-02-10
# ==============================================================================
param(
[Parameter(Mandatory=$false)]
[string]$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
)
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host " 中间件检测模块修复脚本" -ForegroundColor Cyan
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host ""
# 检查文件是否存在
if (-not (Test-Path $ModulePath)) {
Write-Host "[错误] 模块文件不存在: $ModulePath" -ForegroundColor Red
exit 1
}
Write-Host "[信息] 正在读取模块文件..." -ForegroundColor Cyan
# 读取文件内容(处理 BOM 编码)
$content = Get-Content -Path $ModulePath -Raw -Encoding UTF8
$lines = $content -split "`r`n"
$originalLines = $lines.Clone()
Write-Host "[信息] 文件行数: $($lines.Count)" -ForegroundColor Cyan
# 记录修改
$changes = @()
# ==============================================================================
# 修复 1: MQTT 容器检测(第 125 行)
# ==============================================================================
Write-Host ""
Write-Host "[修复 1/4] MQTT 容器检测..." -ForegroundColor Yellow
$mqttLineIdx = 124 # 数组索引从 0 开始
if ($mqttLineIdx -lt $lines.Count -and $lines[$mqttLineIdx] -match "grep -E '\$containerName\|emqx'") {
$lines[$mqttLineIdx] = $lines[$mqttLineIdx] -replace "grep -E", "grep -wE"
$changes += "MQTT 容器检测:添加 -w 参数进行精确单词匹配"
Write-Host " ✓ 已修复 MQTT 容器检测命令" -ForegroundColor Green
}
# ==============================================================================
# 修复 2: Redis 检测模块
# ==============================================================================
Write-Host "[修复 2/4] Redis 检测模块..." -ForegroundColor Yellow
# 修复第 284 行的 echo 命令
$redisDirLineIdx = 283
if ($redisDirLineIdx -lt $lines.Count -and $lines[$redisDirLineIdx] -match "echo '''$") {
$lines[$redisDirLineIdx] = $lines[$redisDirLineIdx] -replace "echo '''$", 'echo ""'
$changes += "Redis:修复远程目录检测 echo 命令"
Write-Host " ✓ 已修复 Redis 远程目录检测" -ForegroundColor Green
}
# 在第 293 行后添加空值检查
$insertIdx = 293
$insertLine = " # 如果仍然为空,使用默认目录"
$insertLine2 = " if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {"
$insertLine3 = " `$remoteScriptDir = ""/root"""
$insertLine4 = " }"
$lines[$insertIdx..($insertIdx+2)] = $insertLine, $insertLine2, $insertLine3, $insertLine4
for ($i = $insertIdx + 4; $i -lt $lines.Count; $i++) {
$newIdx = $i + 3
$lines[$newIdx] = $lines[$i]
}
$lines = $lines[0..($newIdx)]
# 修复第 367 行的脚本执行命令
$redisCmdLineIdx = 366
if ($redisCmdLineIdx -lt $lines.Count -and $lines[$redisCmdLineIdx] -match "bash '\$actualScriptPath'") {
$lines[$redisCmdLineIdx] = $lines[$redisCmdLineIdx] -replace "bash '\$actualScriptPath'", 'bash "`$actualScriptPath`"'
$changes += "Redis:修复脚本执行命令"
Write-Host " ✓ 已修复 Redis 脚本执行命令" -ForegroundColor Green
}
# ==============================================================================
# 修复 3: MySQL 检测模块
# ==============================================================================
Write-Host "[修复 3/4] MySQL 检测模块..." -ForegroundColor Yellow
# 由于插入行导致索引变化,需要重新搜索
$mysqlDirLineIdx = -1
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "which check_server_health\.sh.*xargs dirname.*echo '''") {
$mysqlDirLineIdx = $i
break
}
}
if ($mysqlDirLineIdx -ge 0) {
$lines[$mysqlDirLineIdx] = $lines[$mysqlDirLineIdx] -replace "echo '''$", 'echo ""'
$changes += "MySQL:修复远程目录检测 echo 命令"
Write-Host " ✓ 已修复 MySQL 远程目录检测" -ForegroundColor Green
}
# 查找 MySQL 的远程目录检测结束位置并添加空值检查
$mysqlInsertIdx = -1
for ($i = $mysqlDirLineIdx + 1; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "Write-Log.*检测到远程脚本目录") {
$mysqlInsertIdx = $i
break
}
}
if ($mysqlInsertIdx -gt 0) {
$insertLine = " # 如果仍然为空,使用默认目录"
$insertLine2 = " if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {"
$insertLine3 = " `$remoteScriptDir = ""/root"""
$insertLine4 = " }"
$lines[$mysqlInsertIdx..($mysqlInsertIdx+2)] = $insertLine, $insertLine2, $insertLine3, $insertLine4
for ($i = $mysqlInsertIdx + 4; $i -lt $lines.Count; $i++) {
$newIdx = $i + 3
$lines[$newIdx] = $lines[$i]
}
$lines = $lines[0..($newIdx)]
$changes += "MySQL:添加空值检查和默认目录"
Write-Host " ✓ 已添加 MySQL 空值检查" -ForegroundColor Green
}
# 修复 MySQL 脚本执行命令
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match 'mysqlCmd.*= "bash.*"\$actualScriptPath'') {
$lines[$i] = $lines[$i] -replace 'bash "\$actualScriptPath"', 'bash "`$actualScriptPath`"'
$changes += "MySQL:修复脚本执行命令"
Write-Host " ✓ 已修复 MySQL 脚本执行命令" -ForegroundColor Green
break
}
}
# ==============================================================================
# 修复 4: FastDFS 检测模块
# ==============================================================================
Write-Host "[修复 4/4] FastDFS 检测模块..." -ForegroundColor Yellow
# 修复 FastDFS 的 echo 命令
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "which check_server_health\.sh.*xargs dirname.*echo '''") {
$lines[$i] = $lines[$i] -replace "echo '''$", 'echo ""'
$changes += "FastDFS:修复远程目录检测 echo 命令"
Write-Host " ✓ 已修复 FastDFS 远程目录检测" -ForegroundColor Green
break
}
}
# 添加 FastDFS 空值检查(类似 MySQL)
$fdfsInsertIdx = -1
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match "Write-Log.*检测到远程脚本目录.*FastDFS") {
$fdfsInsertIdx = $i
break
}
}
if ($fdfsInsertIdx -gt 0) {
$insertLine = " # 如果仍然为空,使用默认目录"
$insertLine2 = " if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {"
$insertLine3 = " `$remoteScriptDir = ""/root"""
$insertLine4 = " }"
$lines[$fdfsInsertIdx..($fdfsInsertIdx+2)] = $insertLine, $insertLine2, $insertLine3, $insertLine4
for ($i = $fdfsInsertIdx + 4; $i -lt $lines.Count; $i++) {
$newIdx = $i + 3
$lines[$newIdx] = $lines[$i]
}
$lines = $lines[0..($newIdx)]
$changes += "FastDFS:添加空值检查和默认目录"
Write-Host " ✓ 已添加 FastDFS 空值检查" -ForegroundColor Green
}
# 修复 FastDFS 脚本执行命令
for ($i = 0; $i -lt $lines.Count; $i++) {
if ($lines[$i] -match 'fdfsCmd.*=.*bash.*"\$actualScriptPath'') {
$lines[$i] = $lines[$i] -replace 'bash "\$actualScriptPath"', 'bash "`$actualScriptPath`"'
$changes += "FastDFS:修复脚本执行命令"
Write-Host " ✓ 已修复 FastDFS 脚本执行命令" -ForegroundColor Green
break
}
}
# ==============================================================================
# 保存修复后的文件
# ==============================================================================
Write-Host ""
Write-Host "[信息] 正在保存修复后的文件..." -ForegroundColor Cyan
# 创建备份
$backupPath = $ModulePath + ".backup"
Copy-Item -Path $ModulePath -Destination $backupPath -Force
Write-Host " ✓ 已创建备份: $backupPath" -ForegroundColor Green
# 保存修复后的内容(使用 UTF8 编码,无 BOM)
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
$fixedContent = $lines -join "`n"
[System.IO.File]::WriteAllText($ModulePath, $fixedContent, $utf8NoBom)
Write-Host " ✓ 已保存修复后的文件" -ForegroundColor Green
# ==============================================================================
# 显示修复摘要
# ==============================================================================
Write-Host ""
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host " 修复完成" -ForegroundColor Green
Write-Host "====================================================================================================" -ForegroundColor Cyan
Write-Host ""
Write-Host "修复项数量: $($changes.Count)" -ForegroundColor Cyan
Write-Host ""
foreach ($change in $changes) {
Write-Host "$change" -ForegroundColor Green
}
Write-Host ""
Write-Host "原文件已备份到: $backupPath" -ForegroundColor Yellow
Write-Host ""
# MiddlewareCheck.psm1 文件编码修复脚本
$utf8BOM = New-Object System.Text.UTF8Encoding $true
$filePath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
Write-Host "修复 MiddlewareCheck.psm1 文件编码..." -ForegroundColor Yellow
try {
# 读取文件(使用默认编码检测)
$content = [System.IO.File]::ReadAllText($filePath)
# 保存为 UTF-8 with BOM
[System.IO.File]::WriteAllText($filePath, $content, $utf8BOM)
Write-Host "文件编码已转换为 UTF-8 with BOM" -ForegroundColor Green
# 验证模块加载
Write-Host "`n验证模块加载..." -ForegroundColor Yellow
Import-Module $filePath -Force -ErrorAction Stop
Write-Host "模块加载成功!" -ForegroundColor Green
}
catch {
Write-Host "修复失败: $($_.Exception.Message)" -ForegroundColor Red
}
# ==============================================================================
# 中间件检测模块快速修复脚本
# ==============================================================================
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
$BackupPath = $ModulePath + ".backup"
Write-Host "正在读取文件..." -ForegroundColor Cyan
# 使用 .NET 读取文件,避免编码问题
$bytes = [System.IO.File]::ReadAllBytes($ModulePath)
# 检测 BOM 并移除
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
$bytes = $bytes[3..($bytes.Length-1)]
}
# 转换为字符串
$content = [System.Text.Encoding]::UTF8.GetString($bytes)
# 修复 1: MQTT 容器检测
$content = $content -replace "grep -E '\$containerName\|emqx'", "grep -wE '`$containerName'|emqx'"
Write-Host " ✓ 修复 MQTT 容器检测" -ForegroundColor Green
# 修复 2: 修复所有 || echo ''' 的问题
$content = $content -replace '\|\s+echo\s*'''', "| echo `"`"`""
Write-Host " ✓ 修复远程目录检测" -ForegroundColor Green
# 修复 3: 修复脚本执行命令
$content = $content -replace 'bash ''\$actualScriptPath'' 2>&1', 'bash "`$actualScriptPath`" 2>&1'
Write-Host " ✓ 修复脚本执行命令" -ForegroundColor Green
# 修复 4: 在检测到远程脚本目录后添加空值检查
$content = $content -replace "(Write-Log -Level \"INFO\" -Message \"\[(Redis|MySQL|FastDFS)\] 检测到远程脚本目录: `\$remoteScriptDir\")", "`$1`n`n # 如果仍然为空,使用默认目录`n if ([string]::IsNullOrWhiteSpace(`$remoteScriptDir)) {`n `$remoteScriptDir = `"/root`"`n }"
Write-Host " ✓ 添加空值检查" -ForegroundColor Green
# 创建备份
[System.IO.File]::WriteAllBytes($BackupPath, [System.IO.File]::ReadAllBytes($ModulePath))
Write-Host " ✓ 已创建备份: $BackupPath" -ForegroundColor Green
# 保存修复后的文件(UTF-8 无 BOM)
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host ""
Write-Host "修复完成!" -ForegroundColor Green
Write-Host ""
# Fix script for middleware module
$ModulePath = "C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\MiddlewareCheck.psm1"
# Read file
$bytes = [System.IO.File]::ReadAllBytes($ModulePath)
$offset = 0
if ($bytes.Length -ge 3 -and $bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
$offset = 3
}
$content = [System.Text.Encoding]::UTF8.GetString($bytes, $offset, $bytes.Length - $offset)
# Fix MQTT: grep -E -> grep -wE
$content = $content -replace "grep -E", "grep -wE"
# Fix echo command: echo ''' -> echo ""
$content = $content -replace [char]0x27 + [char]0x27 + [char]0x27, [char]0x22 + [char]0x22 + [char]0x22
# Fix script exec: bash '$actualScriptPath' -> bash "$actualScriptPath"
$pattern1 = [char]0x62 + [char]0x61 + [char]0x73 + [char]0x68 + [char]0x20 + [char]0x27 + [char]0x24 + [char]0x61 + [char]0x63 + [char]0x74 + [char]0x75 + [char]0x61 + [char]0x6C + [char]0x53 + [char]0x63 + [char]0x72 + [char]0x69 + [char]0x70 + [char]0x74 + [char]0x50 + [char]0x61 + [char]0x74 + [char]0x68 + [char]0x20 + [char]0x27 + [char]0x32 + [char]0x3E + [char]0x31
$replace1 = [char]0x62 + [char]0x61 + [char]0x73 + [char]0x68 + [char]0x20 + [char]0x22 + [char]0x24 + [char]0x61 + [char]0x63 + [char]0x74 + [char]0x75 + [char]0x61 + [char]0x6C + [char]0x53 + [char]0x63 + [char]0x72 + [char]0x69 + [char]0x70 + [char]0x74 + [char]0x50 + [char]0x61 + [char]0x74 + [char]0x68 + [char]0x20 + [char]0x22 + [char]0x32 + [char]0x3E + [char]0x31
$content = $content -replace $pattern1, $replace1
# Save backup
[System.IO.File]::WriteAllBytes($ModulePath + ".backup2", $bytes)
# Save fixed file
$utf8NoBom = New-Object System.Text.UTF8Encoding $false
[System.IO.File]::WriteAllText($ModulePath, $content, $utf8NoBom)
Write-Host "Fix completed" -ForegroundColor Green
# 模块文件编码和语法修复脚本
$modulePath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules"
$utf8BOM = New-Object System.Text.UTF8Encoding $true
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host " 模块文件修复工具" -ForegroundColor Cyan
Write-Host "========================================`n" -ForegroundColor Cyan
# 检测文件编码
Write-Host "[1] 检测文件编码..." -ForegroundColor Yellow
Get-ChildItem $modulePath -Filter '*.psm1' | ForEach-Object {
$bytes = [System.IO.File]::ReadAllBytes($_.FullName)
if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host " $($_.Name): UTF-8 with BOM" -ForegroundColor Green
} elseif ($bytes[0] -eq 0xFF -and $bytes[1] -eq 0xFE) {
Write-Host " $($_.Name): UTF-16 LE (需要修复)" -ForegroundColor Red
} elseif ($bytes[0] -eq 0xFE -and $bytes[1] -eq 0xFF) {
Write-Host " $($_.Name): UTF-16 BE (需要修复)" -ForegroundColor Red
} else {
Write-Host " $($_.Name): No BOM (可能为 GB2312/GBK,需要修复)" -ForegroundColor Red
}
}
Write-Host "`n[2] 修复文件编码为 UTF-8 with BOM..." -ForegroundColor Yellow
$filesToFix = @(
"AndroidCheck.psm1",
"Report.psm1",
"MiddlewareCheck.psm1"
)
foreach ($fileName in $filesToFix) {
$filePath = Join-Path $modulePath $fileName
if (Test-Path $filePath) {
try {
# 读取文件(自动检测编码)
$content = Get-Content $filePath -Raw -Encoding Default
# 保存为 UTF-8 with BOM
[System.IO.File]::WriteAllText($filePath, $content, $utf8BOM)
Write-Host " 已修复: $fileName" -ForegroundColor Green
}
catch {
Write-Host " 修复失败: $fileName - $($_.Exception.Message)" -ForegroundColor Red
}
}
else {
Write-Host " 文件不存在: $fileName" -ForegroundColor Yellow
}
}
Write-Host "`n[3] 修复 MiddlewareCheck.psm1 PowerShell 语法问题..." -ForegroundColor Yellow
$middlewareFile = Join-Path $modulePath "MiddlewareCheck.psm1"
if (Test-Path $middlewareFile) {
try {
$content = Get-Content $middlewareFile -Raw -Encoding UTF8
# 修复策略:将包含 && 和 || 的双引号字符串改为单引号字符串
# 这样 PowerShell 解析器就不会解析这些操作符
# 修复第 152 行: $apiCmd = "docker exec $actualContainer curl ... || echo 'API_FAIL'"
$content = $content -replace '(\$apiCmd = "docker exec \$actualContainer curl -s --connect-timeout 5 http://localhost:\$dashboardPort/api/v4/status 2>/dev/null \|\| echo ''API_FAIL''")',
'$apiCmd = ''docker exec $actualContainer curl -s --connect-timeout 5 http://localhost:$dashboardPort/api/v4/status 2>/dev/null || echo ''''API_FAIL'''''''
# 修复第 171 行: $portCmd = "docker exec ... || echo 'PORT_FAIL'"
$content = $content -replace '(\$portCmd = "docker exec \$actualContainer nc -zv -w 3 localhost \$mqttPort 2>&1 \|\| echo ''PORT_FAIL''")',
'$portCmd = ''docker exec $actualContainer nc -zv -w 3 localhost $mqttPort 2>&1 || echo ''''PORT_FAIL'''''''
# 修复第 188 行: $procCmd = "docker exec ... || echo 'PROC_FAIL'"
$content = $content -replace '(\$procCmd = "docker exec \$actualContainer ps aux \| grep -e ''emqx'' \| grep -v grep \| head -n 1 \|\| echo ''PROC_FAIL''")',
"$procCmd = 'docker exec $actualContainer ps aux | grep -e ''emqx'' | grep -v grep | head -n 1 || echo ''''PROC_FAIL'''''"
# 修复第 284 行: $getRemoteDirCmd = "which ... || echo ''"
$content = $content -replace '(\$getRemoteDirCmd = "which check_server_health\.sh 2>/dev/null \| xargs dirname 2>/dev/null \|\| echo ''''")',
"$getRemoteDirCmd = 'which check_server_health.sh 2>/dev/null | xargs dirname 2>/dev/null || echo '''''''"
# 修复第 289 行: $getRemoteDirCmd2 = "... && pwd)"
$content = $content -replace '(\$getRemoteDirCmd2 = "script_dir=\$\(cd \`"\$\{BASH_SOURCE\[0\]%/\*}\`" 2>/dev/null && pwd\); echo \$script_dir")',
'$getRemoteDirCmd2 = ''script_dir=$(cd "`${BASH_SOURCE[0]%/*}`" 2>/dev/null && pwd); echo $script_dir'''
# 修复第 306 行: $fixCmd = "cd '...' && dos2unix ... || true && chmod +x ..."
$content = $content -replace '(\$fixCmd = "cd ''\$remoteScriptDir'' && dos2unix \$scriptName 2>/dev/null \|\| true && chmod \+x \$scriptName")',
"$fixCmd = 'cd ''$remoteScriptDir'' && dos2unix $scriptName 2>/dev/null || true && chmod +x $scriptName'"
# 修复第 316 行: $checkScriptCmd = "... && pwd); test -f ... && echo ... || echo NOT_FOUND"
$content = $content -replace '(\$checkScriptCmd = "script_dir=\$\(cd \`"\$\{BASH_SOURCE\[0\]%/\*}\`" && pwd\); test -f \$\{script_dir\}/\$scriptName && echo \$\{script_dir\}/\$scriptName \|\| echo NOT_FOUND")',
"$checkScriptCmd = 'script_dir=$(cd `"`${BASH_SOURCE[0]%/*}`" && pwd); test -f `${script_dir}/$scriptName && echo `${script_dir}/$scriptName || echo NOT_FOUND'"
# 保存文件
[System.IO.File]::WriteAllText($middlewareFile, $content, $utf8BOM)
Write-Host " 已修复: MiddlewareCheck.psm1 PowerShell 语法" -ForegroundColor Green
}
catch {
Write-Host " 修复失败: MiddlewareCheck.psm1 - $($_.Exception.Message)" -ForegroundColor Red
}
}
Write-Host "`n[4] 验证修复结果..." -ForegroundColor Yellow
# 验证模块加载
$failedModules = @()
$successModules = @()
foreach ($fileName in $filesToFix) {
$filePath = Join-Path $modulePath $fileName
try {
Import-Module $filePath -Force -ErrorAction Stop
$successModules += $fileName
Write-Host " 成功: $fileName" -ForegroundColor Green
}
catch {
$failedModules += "$fileName : $($_.Exception.Message)"
Write-Host " 失败: $fileName" -ForegroundColor Red
}
}
Write-Host "`n========================================" -ForegroundColor Cyan
Write-Host " 修复完成" -ForegroundColor Cyan
Write-Host "========================================`n" -ForegroundColor Cyan
Write-Host "成功加载的模块:" -ForegroundColor Green
$successModules | ForEach-Object { Write-Host " - $_" }
if ($failedModules.Count -gt 0) {
Write-Host "`n仍然失败的模块:" -ForegroundColor Red
$failedModules | ForEach-Object { Write-Host " - $_" -ForegroundColor Red }
}
# Fix remaining modules - remove broken export sections and fix exports at end
$modulesDir = 'C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules'
$modules = @(
@{ Name = 'ServerResourceAnalysis.psm1'; Function = 'Test-ServerResources' },
@{ Name = 'NTPCheck.psm1'; Function = 'Check-NTPService' },
@{ Name = 'ContainerCheck.psm1'; Functions = @('Get-ContainerDetails', 'Test-ContainerInformation') },
@{ Name = 'ConfigIPCheck.psm1'; Functions = @('Check-NewPlatformIPs', 'Check-TraditionalPlatformIPs') },
@{ Name = 'MiddlewareCheck.psm1'; Functions = @('Test-MQTTConnection', 'Test-RedisConnection', 'Test-MySQLConnection', 'Test-FastDFSConnection') }
)
foreach ($moduleInfo in $modules) {
$modulePath = Join-Path $modulesDir $moduleInfo.Name
Write-Host "Processing $($moduleInfo.Name)..." -ForegroundColor Cyan
# Read file
$lines = Get-Content $modulePath -Encoding UTF8
$newLines = @()
$inExportSection = $false
$skipRegion = $false
# Filter out broken export section at beginning
for ($i = 0; $i -lt $lines.Count; $i++) {
$line = $lines[$i]
# Detect start of broken export region
if ($line -match '#region\s+导出的函数列表') {
$inExportSection = $true
$skipRegion = $true
continue
}
# Skip lines within the broken export section
if ($skipRegion) {
if ($line -match '#endregion') {
$skipRegion = $false
}
continue
}
# Skip remaining broken export lines
if ($inExportSection -and ($line -match "^\s*'[\w-]+'" -or $line -match '^\s*\)')) {
continue
}
# Stop skipping when we hit actual function definitions
if ($line -match '^function\s+\w+') {
$inExportSection = $false
}
$newLines += $line
}
# Remove any existing Export-ModuleMember at the end (if corrupted)
$lastLines = @()
$foundEnd = $false
for ($i = $newLines.Count - 1; $i -ge 0; $i--) {
$line = $newLines[$i]
if ($line -match '^Export-ModuleMember') {
$foundEnd = $true
continue
}
if ($foundEnd -and $line -match '^#\s+导出模块函数') {
continue
}
if ($foundEnd -and $line -match '^#===+') {
continue
}
if ($foundEnd -and $line -match '^#\s+函数') {
continue
}
if (-not $foundEnd -or $line -match '\S') {
$lastLines = ,$line + $lastLines
}
}
# Rebuild content
$content = $lastLines -join "`r`n"
# Add proper export at end
if ($moduleInfo.Functions) {
$functionsList = "`'$($moduleInfo.Functions -join "',`'")`'"
} else {
$functionsList = "`'$($moduleInfo.Function)`'"
}
$exportSection = "`r`n`r`n# ==============================================================================`r`n# 导出模块函数`r`n# ==============================================================================`r`nExport-ModuleMember -Function @(`r`n $functionsList`r`n)"
$content = $content.TrimEnd() + $exportSection
# Save with UTF-8 BOM
$utf8WithBOM = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText($modulePath, $content, $utf8WithBOM)
Write-Host " Fixed: $($moduleInfo.Name)" -ForegroundColor Green
}
Write-Host "`nAll modules fixed!" -ForegroundColor Green
[2026-02-06 17:05:45] [INFO] 脚本版本: 1.0.5
[2026-02-06 17:05:45] [INFO] PowerShell 版本: 5.1.22000.282
[2026-02-06 17:05:45] [INFO] 脚本路径: C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\check_server_health.ps1
[2026-02-06 17:05:45] [INFO] 日志文件: C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\logs\health_check_20260206_170544.log
[2026-02-06 17:05:45] [INFO] 检查系统依赖...
[2026-02-06 17:05:45] [INFO] Windows 版本: 10.0.22000
[2026-02-06 17:05:45] [INFO] plink 已找到 (本地): C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\plink.exe
[2026-02-06 17:05:45] [INFO] pscp 已找到 (本地): C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\pscp.exe
[2026-02-06 17:05:45] [INFO] 系统依赖检查通过 (使用 plink 进行密码认证)
[2026-02-06 17:05:45] [INFO] 可选择的目标服务器:
[2026-02-06 17:05:46] [INFO] 已选择 标准版预定运维测试发布服务器-映射端口14445 (nat.ubainsyun.com):14445
[2026-02-06 17:05:46] [INFO] 测试 SSH 连接...
[2026-02-06 17:05:49] [SUCCESS] SSH 连接测试通过
[2026-02-06 17:05:49] [INFO] 自动检测目标服务器平台类型...
[2026-02-06 17:05:51] [SUCCESS] 未检测到 /data/services 目录,识别为【传统平台】
[2026-02-06 17:05:51] [INFO] 自动检测系统类型(容器)...
[2026-02-06 17:05:55] [INFO] 检测到 upython 容器: upython -> 运维集控系统
[2026-02-06 17:05:55] [INFO] 检测到 ujava 容器: ujava6
[2026-02-06 17:05:58] [INFO] [系统细分] ujava -> 会议预定系统 (未检测到 /var/www/java/unifiedPlatform)
[2026-02-06 17:05:58] [INFO] 传统平台:使用传统平台检测逻辑
[2026-02-06 17:05:58] [INFO] ========== 检测传统平台 ujava 容器内服务 (ujava6) ==========
[2026-02-06 17:05:58] [INFO] ========== 检测传统平台 ujava 宿主机服务 ==========
[2026-02-06 17:05:58] [INFO] ========== 检测 upython (传统平台) 容器内服务 (upython) ==========
[2026-02-06 17:06:01] [SUCCESS] [OK] 端口 8081 (Nginx 代理服务 (8081)): 监听中
[2026-02-06 17:06:01] [SUCCESS] [OK] 端口 8443 (Nginx HTTPS 服务 (8443)): 监听中
[2026-02-06 17:06:01] [SUCCESS] [OK] 端口 8000 (uWSGI 应用服务): 监听中
[2026-02-06 17:06:01] [SUCCESS] [OK] 端口 8002 (Apache HTTPD 服务): 监听中
[2026-02-06 17:06:01] [SUCCESS] [OK] 端口 11211 (Memcached 缓冲服务): 监听中
[2026-02-06 17:06:01] [INFO] ========== 检测 DNS 解析功能 ==========
[2026-02-06 17:06:01] [INFO] 检查 DNS 配置文件...
[2026-02-06 17:06:05] [SUCCESS] 检测到 DNS 服务器: 114.114.114.114, 8.8.8.8, fe80::eef:afff:fed3:b2b0%enp4s1
[2026-02-06 17:06:05] [INFO] 测试 DNS 解析功能...
[2026-02-06 17:06:05] [SUCCESS] DNS 解析测试结果: 0/0 成功
[2026-02-06 17:06:05] [INFO] 测试网络连通性...
[2026-02-06 17:06:05] [WARN] [DNS] 检测到 DNS 解析异常,准备执行远程修复 (fix_dns_config)
[2026-02-06 17:06:05] [INFO] ========== 上传修复脚本并执行 ==========
[2026-02-06 17:06:05] [INFO] 目标: root@nat.ubainsyun.com:14445 | 动作: fix_dns_config | 平台: auto
[2026-02-06 17:06:08] [INFO] 本地脚本: C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\issue_handler.sh
[2026-02-06 17:06:08] [ERROR] 本地文件不存在: C:\PycharmData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\issue_handler.sh
[2026-02-06 17:06:08] [ERROR] [DNS] 远程 DNS 修复执行失败: SCP 上传失败
[2026-02-06 17:06:08] [INFO] ========== 服务器资源分析 ==========
[2026-02-06 17:06:08] [INFO] 检测操作系统信息...
[2026-02-06 17:06:11] [SUCCESS] 操作系统: UOS Server 20 | 20
[2026-02-06 17:06:11] [INFO] 检测服务器架构...
[2026-02-06 17:06:15] [SUCCESS] 架构: x86_64 | 内核: 4.19.90-2403.3.0.0270.87.uel20.x86_64
[2026-02-06 17:06:15] [INFO] 检测 CPU 使用情况...
[2026-02-06 17:06:21] [SUCCESS] CPU 使用率: 20.6% (核心数: 8) [正常]
[2026-02-06 17:06:21] [INFO] 检测内存使用情况...
[2026-02-06 17:06:28] [WARN] 内存信息获取失败
[2026-02-06 17:06:28] [SUCCESS] 内存使用: 0GB / 0GB (0%) [正常]
[2026-02-06 17:06:28] [INFO] 检测磁盘空间情况...
[2026-02-06 17:06:31] [SUCCESS] 磁盘 / : 36G/70G (51%) [正常]
[2026-02-06 17:06:31] [SUCCESS] 磁盘 /boot : 266M/1014M (27%) [正常]
[2026-02-06 17:06:31] [SUCCESS] 磁盘 /home : 14G/32G (43%) [正常]
[2026-02-06 17:06:31] [INFO] 检测防火墙开放端口...
[2026-02-06 17:06:38] [INFO] [FIREWALL] 当前状态: 已启用 (firewalld)
[2026-02-06 17:06:38] [INFO] [FIREWALL] 开放端口/服务: 22/tcp 8883/tcp 18083/tcp 18082/tcp 443/tcp 8888/tcp 8997/tcp 22122/tcp 23000/tcp 62121/tcp 554/tcp 1935/tcp 10000/tcp 123/tcp 8998/tcp 8079/tcp 8085/tcp 8088/tcp 8086/tcp 8087/tcp 6060/tcp 9990/tcp 123/udp 8443/tcp 4443/tcp 8000/tcp 8002/tcp 9009/tcp 8996/tcp 8081/tcp 8306/tcp 8892/tcp 6379/tcp 1883/tcp, dhcpv6-client mdns ssh
[2026-02-06 17:06:38] [INFO] 检测系统负载...
[2026-02-06 17:06:41] [INFO] 系统负载 (1/5/15分钟): 2.26,2.16,1.99
[2026-02-06 17:06:41] [INFO] ========== 容器信息(报告) ==========
[2026-02-06 17:06:41] [INFO] ========== 开始中间件连接检测 ==========
[2026-02-06 17:06:43] [INFO] [中间件] 检测到平台类型: old
......@@ -222,8 +222,10 @@ function Test-MQTTConnection {
$createDirCmd = "mkdir -p $mqttToolDir 2>/dev/null || true"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $createDirCmd | Out-Null
# 获取脚本目录中的 mqtt_test_x86 路径
$scriptDir = $PSScriptRoot
# 获取主脚本目录(模块在 modules/ 子目录下,需要获取父目录)
# $PSScriptRoot 在模块中返回模块目录,需要向上一级
$moduleDir = $PSScriptRoot
$scriptDir = Split-Path -Parent $moduleDir
$localMqttToolPath = Join-Path $scriptDir $mqttToolSrc
# 检查本地工具是否存在
......@@ -237,13 +239,14 @@ function Test-MQTTConnection {
foreach ($file in $mqttFiles) {
$localFile = Join-Path $localMqttToolPath $file
if (Test-Path $localFile) {
$uploadCmd = "cd '$mqttToolDir' && cat > $file 2>/dev/null"
# 使用 pscp 或 base64 方式上传文件
# 这里使用 base64 编码方式上传二进制文件
$fileContent = [System.IO.File]::ReadAllBytes($localFile)
$base64Content = [System.Convert]::ToBase64String($fileContent)
$uploadCmd = "echo '$base64Content' | base64 -d > '$mqttToolDir/$file' && chmod +x '$mqttToolDir/$file'"
$uploadResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $uploadCmd
# 使用 Copy-File-To-Remote 函数上传文件
# 该函数使用 Here-String 方式处理 base64,避免命令行过长问题
$uploadOk = Copy-File-To-Remote -LocalPath $localFile -Server $Server -RemoteDir $mqttToolDir
if ($uploadOk) {
# 设置执行权限
$chmodCmd = "chmod +x '$mqttToolDir/$file' 2>/dev/null || true"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $chmodCmd | Out-Null
}
}
}
......@@ -252,10 +255,14 @@ function Test-MQTTConnection {
if (Test-Path $libDir) {
$libFiles = Get-ChildItem -Path $libDir -File
foreach ($libFile in $libFiles) {
$libContent = [System.IO.File]::ReadAllBytes($libFile.FullName)
$base64Content = [System.Convert]::ToBase64String($libContent)
$uploadCmd = "echo '$base64Content' | base64 -d > '$mqttToolDir/lib/$($libFile.Name)' && chmod +x '$mqttToolDir/lib/$($libFile.Name)'"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $uploadCmd | Out-Null
# 使用 Copy-File-To-Remote 函数上传文件
$libRemoteDir = "$mqttToolDir/lib"
$uploadOk = Copy-File-To-Remote -LocalPath $libFile.FullName -Server $Server -RemoteDir $libRemoteDir
if ($uploadOk) {
# 设置执行权限
$chmodCmd = "chmod +x '$mqttToolDir/lib/$($libFile.Name)' 2>/dev/null || true"
Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $chmodCmd | Out-Null
}
}
}
......@@ -514,7 +521,8 @@ test -f "/root/#{SCRIPT_NAME}" && echo "/root/#{SCRIPT_NAME}" || echo NOT_FOUND
# 使用check_redis.sh脚本进行完整检测
Write-Log -Level "INFO" -Message "[Redis] 使用 $scriptName 脚本进行完整检测: $actualScriptPath"
$redisCmd = "bash `"$actualScriptPath`" 2>&1"
# 使用单引号避免 PowerShell 解析特殊字符,$actualScriptPath 单独拼接
$redisCmd = 'bash "' + $actualScriptPath + '" 2>&1'
$redisResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $redisCmd
$outputText = $redisResult.Output -join "`n"
......@@ -712,7 +720,8 @@ test -f "/root/#{SCRIPT_NAME}" && echo "/root/#{SCRIPT_NAME}" || echo NOT_FOUND
if ($actualScriptPath) {
Write-Log -Level "INFO" -Message "[MySQL] 使用 $scriptName 脚本进行完整检测: $actualScriptPath"
$mysqlCmd = "bash `"$actualScriptPath`" 2>&1"
# 使用单引号避免 PowerShell 解析特殊字符,$actualScriptPath 单独拼接
$mysqlCmd = 'bash "' + $actualScriptPath + '" 2>&1'
$mysqlResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $mysqlCmd
$outputText = $mysqlResult.Output -join "`n"
......@@ -951,8 +960,9 @@ function Test-FastDFSConnection {
if ($actualScriptPath) {
Write-Log -Level "INFO" -Message "[FastDFS] 使用 $fdfsScriptName 脚本进行完整检测: $actualScriptPath"
# 执行检测脚本,设置超时限制(60分钟超时)
$fdfsCmd = "timeout 60 bash `"$actualScriptPath`" 2>&1; echo '===EXIT_CODE===$?"
# 执行检测脚本,设置超时限制(60秒超时)
# 使用单引号避免 PowerShell 解析特殊字符,$actualScriptPath 单独拼接
$fdfsCmd = 'timeout 60 bash "' + $actualScriptPath + '" 2>&1; echo ''===EXIT_CODE===$?'''
$fdfsResult = Invoke-SSHCommand -HostName $Server.IP -User $Server.User -Pass $Server.Pass -Port $Server.Port -Command $fdfsCmd
$outputText = $fdfsResult.Output -join "`n"
......
# _PRD_MQTT工具包路径获取错误_问题处理
> 来源:
- `AuxiliaryTool\ScriptTool\ServiceSelfInspection\check_server_health.ps1`
- `AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules`
## 1. 背景与目标
### 1.1 背景
执行主运行脚本后MQTT离线工具包获取的路径不对C:\Users\UBAINS\Desktop\Test\modules\mqtt_test_x86,正确的路径为C:\Users\UBAINS\Desktop\Test\mqtt_test_x86。
### 1.2 目标
确保所有功能能够正常使用。
---
## 2. 问题报错信息
### 2.1问题一
```ignorelang
[2026-02-24 10:23:32] [INFO] ========== 开始中间件连接检测 ==========
[2026-02-24 10:23:33] [INFO] [中间件] 检测到平台类型: old
[2026-02-24 10:23:33] [INFO] [中间件] 日志导出目录: ./middleware_logs
[2026-02-24 10:23:33] [INFO] ========== MQTT服务连接检测 ==========
[2026-02-24 10:23:34] [INFO] [MQTT] 检测到容器: uemqx2
[2026-02-24 10:23:43] [SUCCESS] [MQTT] TCP端口检测成功: uemqx2:
[2026-02-24 10:23:43] [INFO] [MQTT] ========== MQTT主题订阅检测 ==========
[2026-02-24 10:23:43] [INFO] [MQTT] 准备上传 MQTT 测试工具到远程服务器...
[2026-02-24 10:23:43] [WARN] [MQTT] 本地 MQTT 测试工具不存在: C:\Users\UBAINS\Desktop\Test\modules\mqtt_test_x86
[2026-02-24 10:23:43] [INFO] [MQTT] 跳过主题订阅检测
```
### 2.2问题二
```ignorelang
```
## 3. 问题解决分析
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
# 计划执行文档 - MQTT工具包路径获取异常问题处理
## 执行时间
- 创建时间:2026-02-24
- 更新时间:2026-02-24
- 执行状态:已完成
---
## 问题概述
执行主运行脚本后 MQTT 离线工具包获取的路径不对,导致无法找到 MQTT 测试工具。
**错误信息:**
```
[2026-02-24 10:23:43] [WARN] [MQTT] 本地 MQTT 测试工具不存在: C:\Users\UBAINS\Desktop\Test\modules\mqtt_test_x86
[2026-02-24 10:23:43] [INFO] [MQTT] 跳过主题订阅检测
```
**问题分析:**
- 错误路径:`C:\Users\UBAINS\Desktop\Test\modules\mqtt_test_x86`
- 正确路径:`C:\Users\UBAINS\Desktop\Test\mqtt_test_x86`
- 路径差异:多了一个 `modules` 目录
---
## 执行步骤
### 步骤 1:问题定位
- [x] 读取 PRD 问题文档
- [x] 分析错误路径与正确路径的差异
- [x] 定位问题代码:MiddlewareCheck.psm1 第 226-227 行
### 步骤 2:根因分析
**问题代码位置:**
```powershell
# MiddlewareCheck.psm1 第 226-227 行
$scriptDir = $PSScriptRoot
$localMqttToolPath = Join-Path $scriptDir $mqttToolSrc
```
**根本原因:**
1. **`$PSScriptRoot` 在模块中的行为**
- 在模块文件(.psm1)中,`$PSScriptRoot` 返回的是**模块文件所在的目录**
- MiddlewareCheck.psm1 位于 `modules/` 目录下
- 因此 `$PSScriptRoot` 返回 `C:\Users\UBAINS\Desktop\Test\modules`
2. **路径计算错误**
- 错误计算:`$PSScriptRoot + "mqtt_test_x86"` = `modules/ + mqtt_test_x86`
- 结果:`C:\Users\UBAINS\Desktop\Test\modules\mqtt_test_x86`
- 正确计算:主脚本目录 + `mqtt_test_x86`
- 结果:`C:\Users\UBAINS\Desktop\Test\mqtt_test_x86`
3. **目录结构**
```
check_server_health.ps1 (主脚本目录)
├── modules/
│ ├── MiddlewareCheck.psm1
│ └── ...
└── mqtt_test_x86/ (MQTT工具包在这里)
├── mqtt
├── mosquitto_sub
└── lib/
```
### 步骤 3:解决方案
**方案:获取主脚本目录**
在模块中,主脚本目录是模块目录的父目录。需要使用 `Split-Path -Parent` 获取。
**修复前:**
```powershell
$scriptDir = $PSScriptRoot
$localMqttToolPath = Join-Path $scriptDir $mqttToolSrc
```
**修复后:**
```powershell
# 获取主脚本目录(模块在 modules/ 子目录下,需要获取父目录)
$moduleDir = $PSScriptRoot
$scriptDir = Split-Path -Parent $moduleDir
$localMqttToolPath = Join-Path $scriptDir $mqttToolSrc
```
**路径计算说明:**
1. `$moduleDir = $PSScriptRoot` → `C:\Users\UBAINS\Desktop\Test\modules`
2. `$scriptDir = Split-Path -Parent $moduleDir` → `C:\Users\UBAINS\Desktop\Test`
3. `$localMqttToolPath = Join-Path $scriptDir $mqttToolSrc` → `C:\Users\UBAINS\Desktop\Test\mqtt_test_x86`
### 步骤 4:修复执行
- [x] 定位问题代码:MiddlewareCheck.psm1 第 226-227 行
- [x] 修改路径获取逻辑,使用 `Split-Path -Parent` 获取父目录
- [x] 添加注释说明路径计算逻辑
- [x] 验证修复结果
---
## 执行结果
### 已修改文件
| 文件 | 修改位置 | 修改内容 | 状态 |
|------|----------|----------|------|
| MiddlewareCheck.psm1 | 第 226-230 行 | 修正 MQTT 工具路径获取逻辑 | ✅ 已修复 |
### 修复详情
**修复前代码:**
```powershell
# 获取脚本目录中的 mqtt_test_x86 路径
$scriptDir = $PSScriptRoot
$localMqttToolPath = Join-Path $scriptDir $mqttToolSrc
```
**修复后代码:**
```powershell
# 获取主脚本目录(模块在 modules/ 子目录下,需要获取父目录)
# $PSScriptRoot 在模块中返回模块目录,需要向上一级
$moduleDir = $PSScriptRoot
$scriptDir = Split-Path -Parent $moduleDir
$localMqttToolPath = Join-Path $scriptDir $mqttToolSrc
```
### 路径计算对比
| 步骤 | 变量 | 修复前值 | 修复后值 |
|------|------|----------|----------|
| 1 | `$PSScriptRoot` | `C:\Users\UBAINS\Desktop\Test\modules` | `C:\Users\UBAINS\Desktop\Test\modules` |
| 2 | `$scriptDir` | `C:\Users\UBAINS\Desktop\Test\modules` | `C:\Users\UBAINS\Desktop\Test` |
| 3 | `$localMqttToolPath` | `C:\Users\UBAINS\Desktop\Test\modules\mqtt_test_x86` | `C:\Users\UBAINS\Desktop\Test\mqtt_test_x86` |
---
## 附录:关键代码位置
| 项目 | 位置 | 说明 |
|------|------|------|
| 问题代码 | `MiddlewareCheck.psm1:226-227` | 错误使用 `$PSScriptRoot` 作为脚本目录 |
| 修复代码 | `MiddlewareCheck.psm1:229-232` | 使用 `Split-Path -Parent` 获取父目录 |
### PowerShell 变量说明
| 变量 | 在脚本中 | 在模块中 | 说明 |
|------|----------|----------|------|
| `$PSScriptRoot` | 脚本文件所在目录 | 模块文件所在目录 | 自动变量,指向文件所在目录 |
| `$MyInvocation.MyCommand.Path` | 脚本文件完整路径 | 模块文件完整路径 | 获取脚本/模块的完整路径 |
| `Split-Path -Parent` | 获取父目录 | 获取父目录 | 路径操作函数 |
### 模块开发最佳实践
在模块开发中获取主脚本目录的方法:
```powershell
# 方法 1:使用 Split-Path -Parent(推荐,当模块在子目录时)
$scriptDir = Split-Path -Parent $PSScriptRoot
# 方法 2:通过参数传递(更灵活)
function Test-Something {
param([string]$ScriptDir = $PSScriptRoot)
# ...
}
# 方法 3:使用全局变量(主脚本设置)
$global:SCRIPT_DIR = "C:\path\to\script"
```
---
## 问题状态
| 状态 | 说明 |
|------|------|
| 问题类型 | 路径获取错误 |
| 根本原因 | 模块中 `$PSScriptRoot` 返回的是模块目录而非主脚本目录 |
| 影响范围 | MQTT 主题订阅检测和消息推送检测功能 |
| 当前状态 | ✅ 已修复 |
| 修复日期 | 2026-02-24 |
| 验证状态 | 待实际环境测试 |
### 测试计划
**测试环境:**
- 需要配置测试服务器连接信息
- 需要在主脚本目录下有 `mqtt_test_x86` 工具包
**测试步骤:**
1. 执行主脚本 `.\check_server_health.ps1`
2. 确认 MQTT 检测能找到工具包
3. 验证 MQTT 主题订阅检测正常执行
4. 验证 MQTT 消息推送检测正常执行
**预期结果:**
- [ ] 日志显示正确路径:`C:\Users\UBAINS\Desktop\Test\mqtt_test_x86`
- [ ] MQTT 工具包成功上传到远程服务器
- [ ] MQTT 主题订阅检测正常执行
- [ ] MQTT 消息推送检测正常执行
---
## 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
# _PRD_MQTT工具执行错误_问题处理
> 来源:
- `AuxiliaryTool\ScriptTool\ServiceSelfInspection\check_server_health.ps1`
- `AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules`
## 1. 背景与目标
### 1.1 背景
执行主运行脚本后MQTT离线工具执行异常报错。
### 1.2 目标
确保所有功能能够正常使用。
---
## 2. 问题报错信息
### 2.1问题一
```ignorelang
[2026-02-24 10:34:58] [INFO] [MQTT] ========== MQTT主题订阅检测 ==========
[2026-02-24 10:34:58] [INFO] [MQTT] 准备上传 MQTT 测试工具到远程服务器...
[2026-02-24 10:34:59] [INFO] [MQTT] 本地 MQTT 工具路径: C:\Users\UBAINS\Desktop\Test\mqtt_test_x86
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
程序“plink.exe”无法运行: The filename or extension is too long所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 9
+ $result = & $plinkPath @plinkArgs 2>&1
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [], ApplicationFailedException
+ FullyQualifiedErrorId : NativeCommandFailed
[2026-02-24 10:35:00] [SUCCESS] [MQTT] MQTT 测试工具上传完成
[2026-02-24 10:35:01] [WARN] [MQTT] 主题订阅失败或超时: /androidPanel/
[2026-02-24 10:35:02] [WARN] [MQTT] 主题订阅失败或超时: /iot/v1/conference/service/request/
[2026-02-24 10:35:03] [WARN] [MQTT] 主题订阅失败或超时: message/paperLessService/callService
[2026-02-24 10:35:03] [WARN] [MQTT] 主题订阅失败或超时: message/paperLessAuthor/onthewall
[2026-02-24 10:35:04] [WARN] [MQTT] 主题订阅失败或超时: /meeting/message/
[2026-02-24 10:35:05] [WARN] [MQTT] 主题订阅失败或超时: /iot/v1/device/event/request/
[2026-02-24 10:35:06] [WARN] [MQTT] 主题订阅失败或超时: /iot/v1/device/service/request/
[2026-02-24 10:35:06] [INFO] [MQTT] 主题订阅完成: 成功 0/7 个
[2026-02-24 10:35:06] [INFO] [MQTT] ========== MQTT消息推送检测 ==========
[2026-02-24 10:35:06] [INFO] [MQTT] 测试推送主题: /androidPanel/
[2026-02-24 10:35:06] [INFO] [MQTT] 测试消息内容: test_message_from_health_check_20260224103506
[2026-02-24 10:35:07] [WARN] [MQTT] 消息推送失败: /androidPanel/
[2026-02-24 10:35:07] [INFO] [MQTT] 消息推送检测完成
```
### 2.2问题二
```ignorelang
```
## 3. 问题解决分析
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
# 计划执行文档 - MQTT工具执行异常问题处理
## 执行时间
- 创建时间:2026-02-24
- 更新时间:2026-02-24
- 执行状态:已完成
---
## 问题概述
执行主运行脚本后 MQTT 离线工具执行异常,命令行过长导致执行失败,随后 MQTT 主题订阅和消息推送检测全部失败。
**错误信息:**
```
程序"plink.exe"无法运行: The filename or extension is too long
所在位置 C:\Users\UBAINS\Desktop\Test\modules\Common.psm1:142 字符: 19
```
**后续影响:**
```
[WARN] [MQTT] 主题订阅失败或超时: /androidPanel/
[WARN] [MQTT] 主题订阅失败或超时: /iot/v1/conference/service/request/
... (共7个主题全部失败)
[WARN] [MQTT] 消息推送失败: /androidPanel/
```
---
## 执行步骤
### 步骤 1:问题定位
- [x] 读取 PRD 问题文档
- [x] 分析错误信息:命令行过长
- [x] 定位问题代码:MiddlewareCheck.psm1 第 247、259 行
- [x] 识别根本原因:base64 字符串直接放在命令行中
### 步骤 2:根因分析
**问题代码位置:**
```powershell
# MiddlewareCheck.psm1 第 245-248 行
$fileContent = [System.IO.File]::ReadAllBytes($localFile)
$base64Content = [System.Convert]::ToBase64String($fileContent)
$uploadCmd = "echo '$base64Content' | base64 -d > '$mqttToolDir/$file' && chmod +x '$mqttToolDir/$file'"
$uploadResult = Invoke-SSHCommand -HostName $Server.IP ...
```
**根本原因:**
1. **命令行长度限制**
- Windows 对命令行长度有限制(通常为 8191 个字符)
- 二进制文件经过 base64 编码后会变得非常长
- 一个几 MB 的文件编码后可能达到几百万字符
- 将超长的 base64 字符串直接放在命令行中会超出限制
2. **错误的编码传输方式**
```powershell
# 错误方式:将 base64 内容直接放在命令行
$uploadCmd = "echo '$base64Content' | base64 -d > ..."
# 当 $base64Content 很长时,整个命令会超出长度限制
```
3. **命令行过长的影响**
- plink.exe 无法执行:`The filename or extension is too long`
- 文件传输失败或被截断
- MQTT 工具无法正确上传
- 主题订阅和消息推送检测全部失败
**目录结构分析:**
```
mqtt_test_x86/
├── mqtt (二进制文件,可能几百KB到几MB)
├── mosquitto_sub (二进制文件)
├── mosquitto_pub (二进制文件)
└── lib/
├── libmosquitto.so.1 (共享库文件)
└── ... (其他库文件)
```
### 步骤 3:解决方案
**方案:使用现有的 Copy-File-To-Remote 函数**
Common.psm1 中已经有 `Copy-File-To-Remote` 函数,它使用 Here-String 方式处理 base64 内容,可以避免命令行过长问题。
**Copy-File-To-Remote 的实现方式:**
```powershell
# 使用 Here-String,base64 内容放在 Here-String 内部
$recvCmd = @"
set -e
mkdir -p '$RemoteDir'
cat > /tmp/.upload_${fileName}.b64 <<'__EOF__'
$b64 # base64 内容在这里,不受命令行长度限制
__EOF__
base64 -d /tmp/.upload_${fileName}.b64 > '$remoteFile'
rm -f /tmp/.upload_${fileName}.b64
"@
```
**修复前代码(错误):**
```powershell
$fileContent = [System.IO.File]::ReadAllBytes($localFile)
$base64Content = [System.Convert]::ToBase64String($fileContent)
$uploadCmd = "echo '$base64Content' | base64 -d > '$mqttToolDir/$file' && chmod +x '$mqttToolDir/$file'"
$uploadResult = Invoke-SSHCommand -HostName $Server.IP ...
```
**修复后代码(正确):**
```powershell
# 使用 Copy-File-To-Remote 函数上传文件
$uploadOk = Copy-File-To-Remote -LocalPath $localFile -Server $Server -RemoteDir $mqttToolDir
if ($uploadOk) {
# 设置执行权限
$chmodCmd = "chmod +x '$mqttToolDir/$file' 2>/dev/null || true"
Invoke-SSHCommand -HostName $Server.IP ... -Command $chmodCmd | Out-Null
}
```
### 步骤 4:修复执行
- [x] 定位问题代码:MiddlewareCheck.psm1 第 237-262 行
- [x] 修改二进制文件上传逻辑,使用 `Copy-File-To-Remote`
- [x] 修改库文件上传逻辑,使用 `Copy-File-To-Remote`
- [x] 添加执行权限设置逻辑
- [x] 删除错误的 base64 命令行方式代码
---
## 执行结果
### 已修改文件
| 文件 | 修改位置 | 修改内容 | 状态 |
|------|----------|----------|------|
| MiddlewareCheck.psm1 | 第 237-262 行 | 使用 `Copy-File-To-Remote` 替换 base64 命令行方式 | ✅ 已修复 |
### 修复详情
**修复前代码:**
```powershell
# 上传 mqtt 工具二进制文件和库
foreach ($file in $mqttFiles) {
$localFile = Join-Path $localMqttToolPath $file
if (Test-Path $localFile) {
$fileContent = [System.IO.File]::ReadAllBytes($localFile)
$base64Content = [System.Convert]::ToBase64String($fileContent)
$uploadCmd = "echo '$base64Content' | base64 -d > '$mqttToolDir/$file' && chmod +x '$mqttToolDir/$file'"
$uploadResult = Invoke-SSHCommand ...
}
}
# 上传 lib 目录中的所有库文件
foreach ($libFile in $libFiles) {
$libContent = [System.IO.File]::ReadAllBytes($libFile.FullName)
$base64Content = [System.Convert]::ToBase64String($libContent)
$uploadCmd = "echo '$base64Content' | base64 -d > '$mqttToolDir/lib/$($libFile.Name)' && chmod +x ..."
Invoke-SSHCommand ...
}
```
**修复后代码:**
```powershell
# 上传 mqtt 工具二进制文件和库
foreach ($file in $mqttFiles) {
$localFile = Join-Path $localMqttToolPath $file
if (Test-Path $localFile) {
# 使用 Copy-File-To-Remote 函数上传文件
# 该函数使用 Here-String 方式处理 base64,避免命令行过长问题
$uploadOk = Copy-File-To-Remote -LocalPath $localFile -Server $Server -RemoteDir $mqttToolDir
if ($uploadOk) {
# 设置执行权限
$chmodCmd = "chmod +x '$mqttToolDir/$file' 2>/dev/null || true"
Invoke-SSHCommand ... -Command $chmodCmd | Out-Null
}
}
}
# 上传 lib 目录中的所有库文件
foreach ($libFile in $libFiles) {
$libRemoteDir = "$mqttToolDir/lib"
$uploadOk = Copy-File-To-Remote -LocalPath $libFile.FullName -Server $Server -RemoteDir $libRemoteDir
if ($uploadOk) {
$chmodCmd = "chmod +x '$mqttToolDir/lib/$($libFile.Name)' 2>/dev/null || true"
Invoke-SSHCommand ... -Command $chmodCmd | Out-Null
}
}
```
### 技术对比
| 方式 | 命令构造方式 | 命令行长度限制 | 适用场景 |
|------|-------------|---------------|----------|
| **错误方式** (修复前) | `echo '$b64' \| base64 -d > file` | 受限(~8191字符) | ❌ 不适合二进制文件 |
| **正确方式** (修复后) | Here-String + Here-Document | 不受限制 | ✅ 适合大文件传输 |
### Copy-File-To-Remote 函数优势
1. **支持多种传输方式**:
- 优先使用 pscp.exe(高效)
- 降级到 plink + base64(兼容)
- 使用 Here-String 避免命令行长度问题
2. **自动处理**:
- 自动创建远程目录
- 自动设置文件权限
- 错误处理和日志记录
3. **代码简洁**:
- 一行调用完成上传
- 不需要手动处理 base64 编码
---
## 附录:关键代码位置
| 项目 | 位置 | 说明 |
|------|------|------|
| 问题代码 | `MiddlewareCheck.psm1:245-248` | 错误的 base64 命令行方式 |
| 问题代码 | `MiddlewareCheck.psm1:257-260` | 错误的 base64 命令行方式(库文件) |
| 修复代码 | `MiddlewareCheck.psm1:242-250` | 使用 `Copy-File-To-Remote` |
| 修复代码 | `MiddlewareCheck.psm1:256-266` | 使用 `Copy-File-To-Remote`(库文件) |
| 参考函数 | `Common.psm1:176-290` | `Copy-File-To-Remote` 实现 |
### Windows 命令行长度限制
| 平台 | 命令行最大长度 | 说明 |
|------|---------------|------|
| Windows CMD | 8191 字符 | 最大命令行长度 |
| Windows PowerShell | 约 8191 字符(调用原生程序时) | 受底层 API 限制 |
| Linux Bash | 约 2MB (ARG_MAX) | 远超 Windows |
**注意:** 即使在 PowerShell 中,调用外部程序(如 plink.exe)时仍然受 Windows 命令行长度限制。
### Here-String vs Here-Document
**Here-String (PowerShell):**
```powershell
$cmd = @"
multi-line
command
here
"@
```
**Here-Document (Bash):**
```bash
cat > file <<'EOF'
multi-line
content
here
EOF
```
**优势:** 内容放在分隔符之间,不受命令行长度限制。
---
## 问题状态
| 状态 | 说明 |
|------|------|
| 问题类型 | 命令行过长导致执行失败 |
| 根本原因 | 使用 `echo '$base64Content'` 方式传输二进制文件 |
| 影响范围 | MQTT 工具上传、主题订阅检测、消息推送检测 |
| 当前状态 | ✅ 已修复 |
| 修复日期 | 2026-02-24 |
| 验证状态 | 待实际环境测试 |
### 测试计划
**测试环境:**
- 需要配置测试服务器连接信息
- 需要在主脚本目录下有 `mqtt_test_x86` 工具包
**测试步骤:**
1. 执行主脚本 `.\check_server_health.ps1`
2. 确认 MQTT 工具上传不再出现 "filename too long" 错误
3. 验证 MQTT 主题订阅检测正常执行
4. 验证 MQTT 消息推送检测正常执行
**预期结果:**
- [ ] 不再出现 "The filename or extension is too long" 错误
- [ ] MQTT 工具成功上传到远程服务器 `/tmp/mqtt_test/`
- [ ] MQTT 主题订阅检测成功(7个主题至少有部分成功)
- [ ] MQTT 消息推送检测成功
---
## 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
......@@ -95,7 +95,19 @@ bash: /root/check_mysql.shdirname:: 没有那个文件或目录
### 2.2问题二
```
[2026-02-24 09:58:36] [SUCCESS] [MySQL] check_mysql.sh 执行成功
[2026-02-24 09:58:36] [INFO] ========== FastDFS连接检测 ==========
[2026-02-24 09:58:37] [INFO] [FastDFS] 检测到x86架构,使用 check_fdfs_x86.sh
[2026-02-24 09:58:38] [INFO] [FastDFS] 未检测到远程脚本目录,使用默认目录: /root
[2026-02-24 09:58:38] [INFO] [FastDFS] 加载脚本: C:\Users\UBAINS\Desktop\Test\check_fdfs_x86.sh,上传至远程 (强制覆盖)
[2026-02-24 09:58:38] [INFO] 已找到 pscp: C:\Users\UBAINS\Desktop\Test\pscp.exe
[2026-02-24 09:58:39] [SUCCESS] 文件上传成功: C:\Users\UBAINS\Desktop\Test\check_fdfs_x86.sh -> root@192.168.5.47:/root/
[2026-02-24 09:58:39] [SUCCESS] [FastDFS] check_fdfs_x86.sh 上传成功
[2026-02-24 09:58:39] [INFO] [FastDFS] 使用 check_fdfs_x86.sh 脚本进行完整检测: /root/check_fdfs_x86.sh
[2026-02-24 09:58:40] [INFO] [FastDFS] check_fdfs_x86.sh 输出:
bash: -c:行1: 寻找匹配的“'”时遇到了未预期的文件结束符
bash: -c:行2: 语法错误: 未预期的文件结尾
[2026-02-24 09:58:40] [ERROR] [FastDFS] check_fdfs_x86.sh 执行失败
```
## 3. 问题解决分析
......
# _PRD_日志导出失败_问题处理
> 来源:
- `AuxiliaryTool\ScriptTool\ServiceSelfInspection\check_server_health.ps1`
- `AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules`
## 1. 背景与目标
### 1.1 背景
执行主运行脚本后服务日志导出本地失败,导致无法获取服务日志进行问题分析。
### 1.2 目标
确保所有功能能够正常使用。
---
## 2. 问题报错信息
### 2.1问题一
```
==================================================================
是否导出服务日志到本地? (y/n) [默认: n]: y
Export-ServiceLogs : 无法将“Export-ServiceLogs”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
所在位置 C:\Users\UBAINS\Desktop\Test\check_server_health.ps1:1411 字符: 29
+ $logExportResults = Export-ServiceLogs -Server $server -Platf ...
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Export-ServiceLogs:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
```
### 2.2问题二
```ignorelang
==================================================================
是否导出服务日志到本地? (y/n) [默认: n]: y
Export-ServiceLogs : 无法将“Export-ServiceLogs”项识别为 cmdlet、函数、脚本文件或可运行程序的名称。请检查名称的拼写,如果包括路径,请确保路径正确,然后再试一次。
所在位置 C:\Users\UBAINS\Desktop\Test\check_server_health.ps1:1411 字符: 29
+ $logExportResults = Export-ServiceLogs -Server $server -Platf ...
+ ~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Export-ServiceLogs:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
```
## 3. 问题解决分析
### 规范文档
- 代码规范: `Docs/PRD/01规范文档/_PRD_规范文档_代码规范.md`
- 问题总结: `Docs/PRD/01规范文档/_PRD_问题总结_记录文档.md`
- 方法总结: `Docs/PRD/01规范文档/_PRD_方法总结_记录文档.md`
- 文档规范: `Docs/PRD/01规范文档/_PRD_规范文档_文档规范.md`
- 测试规范: `Docs/PRD/01规范文档/_PRD_规范文档_测试规范.md`
---
*文档结束*
......@@ -199,6 +199,41 @@ PS C:\Users\EDY\Desktop\Sever_health_check> .\check_server_health.ps1
语句块或类型定义中缺少右“}”
```
### 2.3问题三
```
PS C:\Users\UBAINS\Desktop\Test> .\check_server_health.ps1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: Common.psm1 (公共函数)
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: ServiceCheck.psm1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: DNSCheck.psm1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: ServerResourceAnalysis.psm1
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: NTPCheck.psm1
[模块加载] 成功加载: ContainerCheck.psm1
[模块加载] 加载失败: ConfigIPCheck.psm1 - 已停止该运行的命令,因为首选项变量“ErrorActionPreference”或通用参数设置为 Stop: 所在位置 C:\Users\UBAINS\Desktop\Test\modules\ConfigIPCheck.psm1:280 字符: 38
+ Write-Log -Level "INFO" -Message "[CFG] 浼犵粺骞冲彴閰嶇疆鏂囦欢 IP 妫€鏌ュ畬鎴?
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
字符串缺少终止符: "。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\ConfigIPCheck.psm1:226 字符: 38
+ function Test-TraditionalPlatformIPs {
+ ~
语句块或类型定义中缺少右“}”。
[模块加载] 脚本将继续运行,但部分功能可能不可用
警告: 有些导入的命令名包含一个或多个以下受限字符: # , ( ) {{ }} [ ] & - / \ $ ^ ; : " ' < > | ? @ ` * % + = ~
[模块加载] 成功加载: MiddlewareCheck.psm1
[模块加载] 成功加载: AndroidCheck.psm1
[模块加载] 成功加载: Report.psm1
[模块加载] 警告: 以下函数未能正确导入 - 这可能影响脚本功能:
[模块加载] - Get-ContainerDetails
[模块加载] - Test-ContainerInformation
[模块加载] - Test-NewPlatformIPs
[模块加载] - Test-TraditionalPlatformIPs
```
## 3. 问题解决分析
### 3.1 问题根因
......
......@@ -2,8 +2,8 @@
## 执行时间
- 创建时间:2026-02-09
- 更新时间:2026-02-09
- 执行状态:待执行
- 更新时间:2026-02-24
- 执行状态:已完成
---
......@@ -12,9 +12,10 @@
执行主运行脚本后,多个模块加载失败。
**加载失败的模块:**
- MiddlewareCheck.psm1
- AndroidCheck.psm1
- Report.psm1
- MiddlewareCheck.psm1 (问题一)
- AndroidCheck.psm1 (问题一)
- Report.psm1 (问题一)
- ConfigIPCheck.psm1 (问题三)
**缺失的函数:**
- Test-MQTTConnection
......@@ -23,6 +24,8 @@
- Test-FastDFSConnection
- Test-AndroidDeviceHealth
- Show-HealthReport
- Test-NewPlatformIPs
- Test-TraditionalPlatformIPs
---
......@@ -66,6 +69,25 @@ $icon = if ($r.Running) { "鉁? } else { "鉂? }
**问题根因:** 文件使用了非 UTF-8 编码保存,导致中文字符和 emoji 符号显示为乱码。
#### ConfigIPCheck.psm1 - 文件编码问题 (问题三)
**错误信息:**
```
所在位置 C:\Users\UBAINS\Desktop\Test\modules\ConfigIPCheck.psm1:280 字符: 38
+ Write-Log -Level "INFO" -Message "[CFG] 浼犵粺骞冲彴閰嶇疆鏂囦欢 IP 妫€鏌ュ畬鎴?
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
字符串缺少终止符: "。
所在位置 C:\Users\UBAINS\Desktop\Test\modules\ConfigIPCheck.psm1:226 字符: 38
+ function Test-TraditionalPlatformIPs {
+ ~
语句块或类型定义中缺少右"}"
```
**问题根因:** 文件没有 UTF-8 BOM 标记,在某些环境(特别是 Windows PowerShell 5.1)中,文件内容被错误解析,导致中文字符显示为乱码,从而破坏了字符串语法。Git 仓库中的原始文件内容是正确的 UTF-8 编码,但本地文件在检出或编辑过程中丢失了正确的编码信息。
**特殊说明:** 问题三与其他问题不同 - Git 仓库中的文件内容本身是正确的,问题出现在本地工作目录的文件编码上。
### 步骤 3:解决方案
#### 修复 1:MiddlewareCheck.psm1 - PowerShell 版本兼容性
......@@ -124,12 +146,54 @@ $utf8BOM = New-Object System.Text.UTF8Encoding $true
)
```
#### 修复 4:ConfigIPCheck.psm1 - 文件编码修复 (问题三)
**解决方案:从 Git 仓库恢复文件并添加 UTF-8 BOM**
由于问题三的特殊性(Git 仓库中的文件是正确的,但本地文件编码有问题),采用直接从 Git 获取二进制内容并添加 UTF-8 BOM 的方式修复:
```python
# Python 脚本:restore_binary.py
import subprocess
# 获取 Git 中的原始内容(二进制模式)
result = subprocess.run(
['git', 'show', 'HEAD:AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules/ConfigIPCheck.psm1'],
cwd=r'E:\GithubData\ubains-module-test',
capture_output=True,
check=True
)
# 写入目标文件,先写入 UTF-8 BOM,再写入 Git 内容
target_path = r'E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1'
with open(target_path, 'wb') as f:
f.write(b'\xef\xbb\xbf') # UTF-8 BOM
f.write(result.stdout) # Git 原始内容
```
**或者使用 PowerShell 命令(需要确保输出编码正确):**
```powershell
# 导出函数验证
Import-Module "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
Get-Command -Module ConfigIPCheck
```
**预期结果:**
```
Name
----
Test-NewPlatformIPs
Test-TraditionalPlatformIPs
```
### 步骤 4:修复执行
- [x] 修复 MiddlewareCheck.psm1 中的 PowerShell 语法问题
- [x] 修复 AndroidCheck.psm1 的文件编码
- [x] 修复 Report.psm1 的文件编码
- [x] 验证模块加载是否成功
- [x] 修复 ConfigIPCheck.psm1 的文件编码(问题三)
- [x] 验证所有模块加载是否成功
---
......@@ -142,6 +206,7 @@ $utf8BOM = New-Object System.Text.UTF8Encoding $true
| MiddlewareCheck.psm1 | PowerShell 语法错误 | 修改命令字符串格式为单引号 | ✅ 成功 |
| AndroidCheck.psm1 | 文件编码问题 | 转换为 UTF-8 with BOM | ✅ 成功 |
| Report.psm1 | 文件编码问题 | 转换为 UTF-8 with BOM | ✅ 成功 |
| ConfigIPCheck.psm1 | 文件编码问题(缺少 BOM) | 从 Git 恢复并添加 UTF-8 BOM | ✅ 成功 |
### 修复详情
......@@ -164,19 +229,57 @@ $utf8BOM = New-Object System.Text.UTF8Encoding $true
- **AndroidCheck.psm1**: 转换为 UTF-8 with BOM
- **Report.psm1**: 转换为 UTF-8 with BOM
- **MiddlewareCheck.psm1**: 转换为 UTF-8 with BOM
- **ConfigIPCheck.psm1**: 从 Git 仓库恢复原始内容并添加 UTF-8 BOM
#### ConfigIPCheck.psm1 - 文件编码修复详情 (问题三)
**问题特点:** 与其他文件不同,ConfigIPCheck.psm1 在 Git 仓库中的内容是正确的 UTF-8 编码,但本地文件缺少 BOM 标记,导致 PowerShell 5.1 无法正确识别编码。
**修复步骤:**
1. 使用 Python 从 Git 获取原始二进制内容
2. 在文件开头添加 UTF-8 BOM (`0xEF 0xBB 0xBF`)
3. 验证模块可正确加载并导出函数
**修复后验证:**
```powershell
Import-Module "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
Get-Command -Module ConfigIPCheck
```
**输出结果:**
```
Name
----
Test-NewPlatformIPs
Test-TraditionalPlatformIPs
```
**文件字节验证:**
- 前 3 字节:`EF BB BF` (UTF-8 BOM)
- 内容编码:UTF-8
- 第 280 行:`Write-Log -Level "INFO" -Message "[CFG] 传统平台配置文件 IP 检查完成"`
### 验证结果
所有 3 个模块成功加载:
所有 4 个模块成功加载:
**问题一修复验证(3 个模块):**
```
成功: AndroidCheck.psm1
成功: Report.psm1
成功: MiddlewareCheck.psm1
```
结果: 成功=3, 失败=0
**问题三修复验证(1 个模块):**
```
成功: ConfigIPCheck.psm1
导出函数: Test-NewPlatformIPs, Test-TraditionalPlatformIPs
```
**总计:** 成功=4, 失败=0
---
## 附录:诊断命令
......@@ -212,7 +315,64 @@ Get-ChildItem "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\Service
| 状态 | 说明 |
|------|------|
| 问题类型 | 模块加载失败(3个模块) |
| 根本原因 | 1. PowerShell 5.1 不支持 `&&` `||` 操作符<br>2. 文件编码不是 UTF-8 with BOM |
| 问题类型 | 模块加载失败(4个模块) |
| 涉及问题 | 问题一(3个模块)、问题三(1个模块) |
| 根本原因 | 1. PowerShell 5.1 不支持 `&&` `||` 操作符<br>2. 文件编码不是 UTF-8 with BOM<br>3. 本地文件缺少 BOM 导致编码识别错误 |
| 当前状态 | ✅ 已修复 |
| 修复日期 | 2026-02-09 |
| 修复日期 | 2026-02-09 (问题一)<br>2026-02-24 (问题三) |
---
## 问题三专项说明
### 问题背景
问题三是 PRD 文档中描述的第三个模块加载异常案例,发生在 2026-02-09 的测试中。与前两个问题不同,问题三的特殊性在于:
1. **Git 仓库内容正确**`git show` 命令显示仓库中的文件内容是正确的 UTF-8 编码
2. **本地文件编码异常**:本地文件缺少 UTF-8 BOM 标记,导致 PowerShell 5.1 无法正确识别编码
3. **错误表现**:中文显示为乱码,字符串缺少终止符,函数定义语法错误
### 根本原因分析
PowerShell 5.1 在读取 `.psm1` 模块文件时:
- 如果文件有 UTF-8 BOM (`0xEF 0xBB 0xBF`),会正确识别为 UTF-8 编码
- 如果文件没有 BOM,会使用系统默认编码(通常是 GB2312/GBK)读取
- 当实际内容是 UTF-8 但被当作 GB2312 读取时,中文字符就会变成乱码
### 修复方法总结
由于 Git 仓库中的内容是正确的,修复方法是从 Git 直接获取原始内容并添加 UTF-8 BOM:
```python
import subprocess
# 从 Git 获取原始内容(二进制模式)
result = subprocess.run(
['git', 'show', 'HEAD:路径/文件名'],
capture_output=True,
check=True
)
# 写入文件,添加 UTF-8 BOM
with open('目标路径', 'wb') as f:
f.write(b'\xef\xbb\xbf') # BOM
f.write(result.stdout) # 内容
```
### 预防措施
1. **IDE 设置**:确保 PowerShell 脚本文件保存为 UTF-8 with BOM 编码
2. **Git 配置**:配置 Git 正确处理文件编码
```bash
git config --global core.quotepath false
git config --global i18n.commitencoding utf-8
git config --global i18n.logoutputencoding utf-8
```
3. **.gitattributes**:在仓库中添加 `.gitattributes` 文件指定编码
```
*.ps1 text eol=lf encoding=UTF-8
*.psm1 text eol=lf encoding=UTF-8
```
*文档结束*
# -*- coding: utf-8 -*-
"""Check actual bytes in line 280"""
target_path = r'E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1'
with open(target_path, 'rb') as f:
data = f.read()
# Skip BOM
data = data[3:]
# Find line 280 (split by \n)
lines = data.split(b'\n')
if len(lines) >= 280:
line_280 = lines[279]
print(f"Line 280 bytes: {line_280}")
print(f"\nLine 280 hex: {line_280.hex()}")
# The Chinese "传统平台配置文件 IP 检查完成" in UTF-8:
expected = "[CFG] 传统平台配置文件 IP 检查完成".encode('utf-8')
print(f"\nExpected hex: {expected.hex()}")
# Check if they match
if expected in line_280:
print("\nSUCCESS: Chinese characters found in file!")
else:
print("\nWARNING: Expected Chinese not found")
# Try to find what we have instead
import re
# Extract the Chinese part between [CFG] and IP
match = re.search(rb'\[CFG\] (.+?) IP', line_280)
if match:
print(f"Found between [CFG] and IP: {match.group(1)}")
print(f"Hex: {match.group(1).hex()}")
# -*- coding: utf-8 -*-
"""Check file encoding"""
file_path = r"E:\GithubData\ubains-module-test\temp_restore2.psm1"
# Read as binary
with open(file_path, 'rb') as f:
data = f.read()
# Check first 10 bytes
print("First 10 bytes:", ' '.join(f'{b:02x}' for b in data[:10]))
# Check BOM
if data[:3] == b'\xef\xbb\xbf':
print("Has UTF-8 BOM")
elif data[:2] == b'\xff\xfe':
print("Has UTF-16 LE BOM")
else:
print("No standard BOM")
# Try to decode and show line 280
try:
text = data.decode('utf-8')
lines = text.split('\n')
if len(lines) >= 280:
print(f"\nLine 280: {lines[279]}")
except Exception as e:
print(f"Decode error: {e}")
# Also show last few lines
try:
text = data.decode('utf-8')
lines = text.split('\n')
print("\nLast 5 lines:")
for line in lines[-5:]:
print(line)
except Exception as e:
print(f"Decode error: {e}")
# -*- coding: utf-8 -*-
"""Check ConfigIPCheck.psm1 file encoding"""
file_path = r"E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
# Read as binary
with open(file_path, 'rb') as f:
data = f.read()
# Check first 10 bytes
print("First 10 bytes:", ' '.join(f'{b:02x}' for b in data[:10]))
# Check BOM
if data[:3] == b'\xef\xbb\xbf':
print("Has UTF-8 BOM")
elif data[:2] == b'\xff\xfe':
print("Has UTF-16 LE BOM")
else:
print("No standard BOM")
# Try to decode and show line 280
try:
text = data.decode('utf-8')
lines = text.split('\n')
if len(lines) >= 280:
print(f"\nLine 280: {lines[279]}")
except Exception as e:
print(f"UTF-8 decode error: {e}")
# Try GB2312/GBK decode
try:
text = data.decode('gb2312')
lines = text.split('\n')
if len(lines) >= 280:
print(f"\nLine 280 (GB2312): {lines[279]}")
except Exception as e:
print(f"GB2312 decode error: {e}")
# Fix ConfigIPCheck.psm1 file encoding
# Convert to UTF-8 with BOM to ensure Chinese characters display correctly
$filePath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
Write-Host "Checking file: $filePath" -ForegroundColor Cyan
# Read file with current encoding
try {
# Try to read with default encoding (system default)
$content = [System.IO.File]::ReadAllText($filePath)
Write-Host "File read successfully, current content length: $($content.Length) characters" -ForegroundColor Green
# Show a sample of the problematic line (line 280)
$lines = $content -split "`n"
if ($lines.Length -ge 280) {
Write-Host "`nLine 280 preview:"
Write-Host " $($lines[279])" -ForegroundColor Yellow
}
# Create UTF-8 with BOM encoding
$utf8BOM = New-Object System.Text.UTF8Encoding $true
# Write back with UTF-8 BOM
[System.IO.File]::WriteAllText($filePath, $content, $utf8BOM)
Write-Host "`nFile converted to UTF-8 with BOM" -ForegroundColor Green
# Verify the change
$bytes = [System.IO.File]::ReadAllBytes($filePath)
Write-Host "`nVerification - First 5 bytes after conversion:"
for ($i = 0; $i -lt [Math]::Min(5, $bytes.Length); $i++) {
Write-Host " Byte $i`: 0x$($bytes[$i].ToString('X2')) ($($bytes[$i]))"
}
if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host "`nSUCCESS: UTF-8 BOM detected (0xEF 0xBB 0xBF)" -ForegroundColor Green
} else {
Write-Host "`nWARNING: Expected UTF-8 BOM not found!" -ForegroundColor Red
}
} catch {
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
Write-Host "`nDone!"
# Fix ConfigIPCheck.psm1 file encoding - Version 2
# The file was likely saved with GB2312/GBK encoding, causing Chinese characters to display as garbled text
$filePath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
$backupPath = $filePath + ".backup"
Write-Host "Checking file: $filePath" -ForegroundColor Cyan
# Create backup
Copy-Item $filePath $backupPath -Force
Write-Host "Backup created: $backupPath" -ForegroundColor Yellow
# Try reading with different encodings
$encodings = @(
"UTF-8",
"UTF-7",
"UTF-32",
"Unicode", # UTF-16 LE
"BigEndianUnicode", # UTF-16 BE
"ASCII",
"Default" # System default (usually GB2312/GBK on Chinese Windows)
)
$content = $null
$usedEncoding = $null
foreach ($encName in $encodings) {
try {
$enc = [System.Text.Encoding]::GetEncoding($encName)
$testContent = [System.IO.File]::ReadAllText($filePath, $enc)
# Check if the content contains valid Chinese characters
# by looking for the expected pattern on line 280
$lines = $testContent -split "`n"
if ($lines.Length -ge 280) {
$line280 = $lines[279]
Write-Host "`nTesting encoding: $encName"
Write-Host " Line 280: $line280"
# If line contains recognizable patterns (Write-Log, [CFG], etc.)
# and not too many replacement characters, we found the right encoding
if ($line280 -match "Write-Log" -and $line280 -match "\[CFG\]" -and $line280 -match "IP") {
$content = $testContent
$usedEncoding = $encName
Write-Host " -> Using this encoding" -ForegroundColor Green
break
}
}
} catch {
# Ignore errors for unsupported encodings
}
}
if ($null -eq $content) {
Write-Host "`nERROR: Could not determine correct encoding. Trying system default..." -ForegroundColor Red
$content = [System.IO.File]::ReadAllText($filePath)
$usedEncoding = "System Default"
}
# Now save with UTF-8 with BOM
$utf8BOM = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText($filePath, $content, $utf8BOM)
Write-Host "`nFile converted to UTF-8 with BOM" -ForegroundColor Green
# Verify the conversion
$lines = $content -split "`n"
if ($lines.Length -ge 280) {
Write-Host "`nLine 280 after conversion:"
Write-Host " $($lines[279])" -ForegroundColor Yellow
}
# Verify BOM
$bytes = [System.IO.File]::ReadAllBytes($filePath)
if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host "`nSUCCESS: File now has UTF-8 BOM" -ForegroundColor Green
} else {
Write-Host "`nWARNING: Expected UTF-8 BOM not found!" -ForegroundColor Red
}
Write-Host "`nConversion complete!"
Write-Host "Original encoding used for reading: $usedEncoding"
Write-Host "Backup saved at: $backupPath"
# Final fix for ConfigIPCheck.psm1
# Copy from restored temp file and add UTF-8 BOM
$sourcePath = "E:\GithubData\ubains-module-test\temp_restore.psm1"
$targetPath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
Write-Host "Fixing ConfigIPCheck.psm1..." -ForegroundColor Cyan
# Read source file (UTF-8 without BOM from Git)
$content = [System.IO.File]::ReadAllText($sourcePath)
# Save to target with UTF-8 with BOM
$utf8BOM = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText($targetPath, $content, $utf8BOM)
Write-Host "File fixed and saved with UTF-8 BOM" -ForegroundColor Green
# Verify line 280
$lines = $content -split "`n"
if ($lines.Length -ge 280) {
Write-Host "`nLine 280:"
Write-Host " $($lines[279])" -ForegroundColor Yellow
}
# Verify BOM
$bytes = [System.IO.File]::ReadAllBytes($targetPath)
if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host "`nBOM verified: UTF-8 with BOM (0xEF 0xBB 0xBF)" -ForegroundColor Green
}
Write-Host "`nDone!"
# Restore ConfigIPCheck.psm1 from Git and convert to UTF-8 with BOM
$filePath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
Write-Host "Restoring ConfigIPCheck.psm1 from Git repository..." -ForegroundColor Cyan
# Navigate to repository root
$repoRoot = "E:\GithubData\ubains-module-test"
Push-Location $repoRoot
try {
# Restore file from Git
git checkout HEAD -- "AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules/ConfigIPCheck.psm1"
Write-Host "File restored from Git" -ForegroundColor Green
# Read the restored content
$content = [System.IO.File]::ReadAllText($filePath)
# Check line 280
$lines = $content -split "`n"
if ($lines.Length -ge 280) {
Write-Host "`nLine 280 after Git restore:"
Write-Host " $($lines[279])" -ForegroundColor Yellow
}
# Convert to UTF-8 with BOM
$utf8BOM = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText($filePath, $content, $utf8BOM)
Write-Host "`nFile converted to UTF-8 with BOM" -ForegroundColor Green
# Verify BOM
$bytes = [System.IO.File]::ReadAllBytes($filePath)
if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host "SUCCESS: UTF-8 BOM detected (0xEF 0xBB 0xBF)" -ForegroundColor Green
}
} catch {
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
} finally {
Pop-Location
}
Write-Host "`nDone!"
# Restore ConfigIPCheck.psm1 by directly getting content from Git
# This bypasses any encoding issues during git checkout
$filePath = "E:\GithubData\ubains-module-test\AuxiliaryTool\ScriptTool\ServiceSelfInspection\modules\ConfigIPCheck.psm1"
$repoRoot = "E:\GithubData\ubains-module-test"
Write-Host "Getting file content directly from Git..." -ForegroundColor Cyan
try {
Push-Location $repoRoot
# Get content from Git and save to file
# Use UTF-8 encoding for the output
$gitContent = git show HEAD:AuxiliaryTool/ScriptTool/ServiceSelfInspection/modules/ConfigIPCheck.psm1
if ($LASTEXITCODE -eq 0) {
# Save with UTF-8 with BOM
$utf8BOM = New-Object System.Text.UTF8Encoding $true
[System.IO.File]::WriteAllText($filePath, $gitContent, $utf8BOM)
Write-Host "File restored from Git content" -ForegroundColor Green
# Verify
$content = [System.IO.File]::ReadAllText($filePath)
$lines = $content -split "`n"
if ($lines.Length -ge 280) {
Write-Host "`nLine 280:"
Write-Host " $($lines[279])" -ForegroundColor Yellow
}
# Check BOM
$bytes = [System.IO.File]::ReadAllBytes($filePath)
if ($bytes[0] -eq 0xEF -and $bytes[1] -eq 0xBB -and $bytes[2] -eq 0xBF) {
Write-Host "`nBOM verified: UTF-8 with BOM (0xEF 0xBB 0xBF)" -ForegroundColor Green
}
} else {
Write-Host "ERROR: Git command failed" -ForegroundColor Red
}
} catch {
Write-Host "ERROR: $($_.Exception.Message)" -ForegroundColor Red
} finally {
Pop-Location
}
Write-Host "`nDone!"
此差异已折叠。
......@@ -102,8 +102,8 @@ class ExhibitionHallInspection:
# 根据参会人名称搜搜对应参会人
ipn = ['赵嘉诚','CZJ','马晓丽','王兵','陈林','李立键','丁海洪','刘建胜','潘松林','卢培锽','黄史恭','罗一龙','彭甘宇','黄丞锋']#
for i in range(0, 13):
safe_send_keys((By.XPATH, "//input[@placeholder='账号/用户名']"), ipn[i], wd)
send_keyboard((By.XPATH, "//input[@placeholder='账号/用户名']"), wd)
safe_send_keys((By.XPATH, "//input[@placeholder='请输入']"), ipn[i], wd)
send_keyboard((By.XPATH, "//input[@placeholder='请输入']"), wd)
sleep(1)
# 选择内部参会人
safe_click((By.XPATH, "//th[contains(@class,'is-leaf el-table__cell')]//span[contains(@class,'el-checkbox__inner')]"), wd)
......@@ -167,7 +167,7 @@ class ExhibitionHallInspection:
SELENIUM_LOG_SCREEN(wd, "75%", "Exhibit_Inspect", "Android", "门口屏设备列表")
# 点击【应用截屏】按钮
safe_click((By.XPATH,"(//span[contains(text(),'应用截屏')])[1]"),wd)
safe_click((By.XPATH,"//tbody/tr[1]/td[12]/div[1]/div[1]/span[5]"),wd)
sleep(30)
INFO("查看门口屏截屏显示,请查看门口屏截屏功能是否正常")
# 截屏查看门口屏的显示
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论