Доработка автоматизации поиска внешних ссылок с помощью PowerShell
После прочтенных комментариев, в основном благодаря @DmitryO решил что надо подумать о доработке функционала
Функциональные улучшения:
✅ Расширенные места поиска: именованные диапазоны, диаграммы, проверка данных
✅ Добавлена Детальная статистика с группировкой результатов по файлам
Структурные изменения:
🔄 Модульная архитектура вместо монолитного кода
🔄 Разделение логики поиска для XLSX и XLS форматов
🔄 Улучшенная обработка ошибок с детальным логированием
🔄 Валидация входных данных перед началом поиска
Основные изменения кода
1. Модульная структура функций
Было (монолитный код):
Весь код в одном большом блоке с дублированием логики
foreach ($currentFile in $files) {
# Прямой анализ файла здесь же
$archive = [System.IO.Compression.ZipFile]::OpenRead($currentFile)
# ... логика поиска ...
}
Стало (модульные функции):
Разделение на специализированные функции
function Search-InXlsxFiles { ... }
function Process-XlsxFiles { ... }
function Analyze-XlsxFile { ... }
function Find-InExternalLinks { ... }
2. Поддержка XLS/XLSB файлов
Было:
$files = Get-ChildItem -Path $searchPath -Filter "*.xlsx" -Recurse
$files += Get-ChildItem -Path $searchPath -Filter "*.xlsm" -Recurse
Стало:
Отдельная обработка для разных форматов
function Search-InXlsFiles {
# Использование Excel COM API для старых форматов
$excel = New-Object -ComObject Excel.Application
$wb = $Excel.Workbooks.Open($FilePath, $false, $true)
$linkSources = $Workbook.LinkSources(1)
}
function Get-ExcelFiles {
param([string[]]$Extensions)
foreach ($ext in $Extensions) {
$files += Get-ChildItem -Path $SearchPath -Filter "*.$ext" -Recurse
}
}
3. Расширенные места поиска
Было (только внешние связи):
$linkFiles = $archive.Entries | Where-Object { $_.FullName -like 'xl/externalLinks/_rels/*.rels' }
foreach ($linkFile in $linkFiles) {
# Поиск только в зарегистрированных связях
}
Стало (множественные источники):
1. Зарегистрированные внешние связи
$externalLinks = Find-InExternalLinks $archive $FilePath $SearchFile
# 2. Именованные диапазоны
$namedRangeLinks = Find-InNamedRanges $archive $FilePath $SearchFile
# 3. Диаграммы
$chartLinks = Find-InCharts $archive $FilePath $SearchFile
# 4. Проверка данных
$dataValidationLinks = Find-InDataValidation $archive $FilePath $SearchFile
4. Улучшенная обработка ошибок
Было:
Codetry {
# Простая обработка
} catch {
Write-Host "Ошибка: $($_.Exception.Message)" -ForegroundColor Red
}
Стало:
Codefunction Test-FileAccessible {
try {
$stream = [System.IO.File]::Open($FilePath, 'Open', 'Read', 'None')
$stream.Close()
return $true
} catch {
return $false
}
}
# В основном коде:
if (-not (Test-FileAccessible $FilePath)) {
Write-LogMessage " Файл заблокирован" ([System.Drawing.Color]::Red)
return $foundLinks
}
5. Детальная статистика результатов
Было:
CodeWrite-Host "Найдено ссылок: $foundLinks"
Стало:
powershellCopy Codefunction Write-SearchResults {
Write-LogMessage "ИТОГОВАЯ СТАТИСТИКА:" ([System.Drawing.Color]::Blue)
Write-LogMessage "Проверено файлов: $($Results.ProcessedFiles)"
Write-LogMessage "Найдено ссылок: $($Results.FoundLinks)"
# Группировка по файлам с детальной информацией
$groupedLinks = $Results.FoundLinksInfo | Group-Object SourceFile
foreach ($group in $groupedLinks) {
Write-LogMessage "Файл: $($group.Name)" ([System.Drawing.Color]::Green)
foreach ($link in $group.Group) {
Write-LogMessage " Тип: $($link.LinkType)"
Write-LogMessage " Местоположение: $($link.Location)"
}
}
}
6. Валидация входных данных
Не Было
Стало:
Codefunction Test-SearchInputs {
if ([string]::IsNullOrWhiteSpace($SearchFile)) {
Write-LogMessage "ОШИБКА: Не указан файл для поиска" ([System.Drawing.Color]::Red)
return $false
}
if (-not (Test-Path $SearchPath)) {
Write-LogMessage "ОШИБКА: Папка недоступна: $SearchPath" ([System.Drawing.Color]::Red)
return $false
}
return $true
}
P.S.
Правда ранее в старой версии обработка файлов занимала секунд 10 при условии 60 файлов в папке. А теперь Эти же 60 файлов могу обрабатываться часами из‑за поиска по именам, ибо есть файлы с кучей имен (60 тыс в каждом). А Основной задаче было суметь разобраться в чужой структуре файлов и понять зависимости быстро... А в таком случае расследования будут затягиваться...