PowerShell: поиск пути к файлу на верхнем уровне папки; предупредить пользователя, если он не найден, и продолжить поиск рекурсивно

PowerShell: поиск пути к файлу на верхнем уровне папки; предупредить пользователя, если он не найден, и продолжить поиск рекурсивно
PowerShell: поиск пути к файлу на верхнем уровне папки; предупредить пользователя, если он не найден, и продолжить поиск рекурсивно - gregbulla @ Unsplash

Я пишу сценарий автоматической оценки, который предупреждает пользователя, если учащийся выполнил/не выполнил требования к каталогу: в частности, один файл main.cpp в папке с соответствующим именем. Если этот файл не найден на верхнем уровне, предупредите пользователя, но продолжайте рекурсивно искать файл в любом подкаталоге. Если файл не найден, отправить сообщение об ошибке, но продолжить обработку остальных каталогов в родительском каталоге.

Пока это моя попытка, и она не совсем работает — предупреждение отправляется даже тогда, когда у пользователя вообще нет файла main.cpp, когда мне нужны только 3 возможных выхода:

  1. без предупреждения, и продолжать строить;
  2. файл найден рекурсивно, но отправлено предупреждение;
  3. файл не найден и ошибка, но продолжайте обработку других папок.

Как я могу это исправить?

function Copy-Files {
    param (
        [Parameter(Mandatory)][string]$CurrentDir,
        [Parameter(Mandatory)][string]$StudentNum
    )

    # Try to copy assignment files to the marking folder. Check error conditions and warn marker appropriately.
    try {
        $DoneFiles | ForEach-Object {
            Copy-Item -Force -Path "$CurrentDir\$_" -Destination .\marking -ErrorAction Stop
        }
    }
    catch {
        try {
            $DoneFiles | ForEach-Object {
                Get-ChildItem -Path $CurrentDir -File -Recurse -Filter "$_" | Copy-Item -Force -Destination .\marking -ErrorAction Stop
            }
            Write-Warning "$StudentNumber did not follow the specified folder convention, but all files were submitted."
        }
        catch {
            Write-Error -Message "$StudentNumber did not submit any of: $DoneFiles." -Category InvalidData
            Read-Host -Prompt "Press Enter to continue"
        }
    }
}

Get-ChildItem -Directory -Filter "*_lab${Env:AssignNumber}" | ForEach-Object {
    $CurrentFolder = $_
    $StudentNumber = $CurrentFolder.Name.Replace("_lab${Env:AssignNumber}", "")

    Copy-Files -CurrentDir $CurrentFolder -StudentNum $StudentNumber

    if ($AllFound -and $IsCMake) {
        Invoke-CMake -DoneFileNames $DoneFiles -IsFirstCompile $FirstCompile -StudentNum $StudentNumber
    }
    # Run VS Code with diff
    Compare-Code -DoneFileNames $DoneFiles -StudentNum $StudentNumber
}

Проблема заключается в неудобном поведении Copy-Item. Если вы передаете пустую/нулевую коллекцию через конвейер (как в Get-ChildItem), он не выдает ошибку. Это отличается от того, что вы ожидаете, поскольку конвейер в $null выдает ошибку:

Get-ChildItem './MySrc' -Filter 'BadFilter' | Copy-Item ./MyDst  ## No Error
$Null | Copy-Item ./MyDst  ## Does Error

Для файлов я предпочитаю структуру типа If (Test-Path){}, а не Try/Catch, чтобы убедиться, что пути и тому подобное все еще действительны, прежде чем пытаться внести изменения:

# Check if file exists in correct path and copy,
If (Test-Path "$CurrentDir\$_") {
  Copy-Item -Force -Path "$CurrentDir\$_" -Destination .\marking
}

# Otherwise check recursively for the correct file and show a warning if found
ElseIf (Get-ChildItem -Path $CurrentDir -File -Recurse -Filter "$_") {
  Write-Warning "$StudentNumber did not follow the specified folder convention, but all files were submitted."
  Get-ChildItem -Path $CurrentDir -File -Recurse -Filter "$_" |
    Copy-Item -Force -Destination .\marking
}

# Error out if file not found
Else { 
  Write-Error -Message "$StudentNumber did not submit any of: $DoneFiles." -Category InvalidData
  Read-Host -Prompt "Press Enter to continue"
}

NevaDev, 3 февраля 2023 г., 10:50