Доработка автоматизации поиска внешних ссылок с помощью 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) {       # Поиск только в зарегистрированных связях   }  

Стало (множественные источники):

powershellCopy Code# 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. Детальная статистика результатов

Было:

powershellCopy 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 тыс в каждом). А Основной задаче было суметь разобраться в чужой структуре файлов и понять зависимости быстро… А в таком случае расследования будут затягиваться…


ссылка на оригинал статьи https://habr.com/ru/articles/912318/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *