Close-SMBOpenFile выдает ошибку и не попадает в try-catch - PullRequest
4 голосов
/ 06 марта 2020

Мы используем PowerChell TeamCity в режиме выполнения скрипта как часть конвейера с зависимостями моментальных снимков и артефактов. У нас достаточно надежная система, и мы использовали этот конкретный процесс в течение пары лет, так что это не новый код, который я отлаживаю впервые. К сожалению. Обычно это работает, пока случайно не работает. Агент TeamCity отличается, когда ошибка возникает.

Эта часть нашего процесса выполняет развертывание кода и резервное копирование журналов. Чтобы полностью выполнить резервное копирование, мы должны убедиться, что QA или разработчики не держат файлы открытыми, просматривая журналы, и, возможно, открывают их в режиме чтения-записи или тому подобное. Поскольку они будут открывать их со своего ноутбука / настольного компьютера, они, естественно, являются малыми и средними компаниями. Итак, у нас есть эта функция, которая должна закрывать файлы, открытые на данном сервере. Я говорю «должен», потому что время от времени он выдает эту ошибку, и я не могу ни поймать ее (даже локально), ни подавить, поэтому он прерывает запуск TeamCity. (Я анонимизировал ...SNIP везде, где код является собственными именами или собственными выходными данными)

Вы можете на самом деле проверить это на своей машине, просто перейдя к \\yourhostname\c$\somefilepath\somefile и увидите, что это покажет, что файлы открытый. Он не должен выходить из строя на вашей машине, как только вы прочитаете код и увидите, что он делает, но если вы уберете все «меры предосторожности», вы можете потенциально воспроизвести ошибку локально.

function Close-SMBApplicationLocks {
<#
.SYNOPSIS
    Closes Active SMB Sessions for Default or User Supplied Paths

.DESCRIPTION
    This function is used to prevent interruption to deployments by closing any SMB locks
    in application paths.  Defaults to closing sessions in folders matching regex
    ...SNIP

.PARAMETER Paths
    [string[]] A string array of paths or path segments to match sessions against.

.EXAMPLE
    Close-SMBApplicationLocks

...SNIP

.EXAMPLE
    Close-SMBApplicationLocks -Paths @("TEMP")

...SNIP
#>
    [CmdletBinding()]
    param(
        [Alias("SharePaths")]
        [Parameter(Mandatory=$false)]
        [string[]]$Paths
    )

    $pathsToUse = Test-IsNull ($Paths -join "|") "...SNIP"
    Write-Verbose ("Looking for SMB Sessions Matching Path: {0}" -f $pathsToUse)

    $smbSessions = @(Get-SmbOpenFile | Where-Object {$_.Path -match $pathsToUse})

    if ((Test-IsCollectionNullOrEmpty $smbSessions)) {
        Write-Host ("No Matching SMB Sessions Found")
        return
    }

    Write-Verbose "Found $($smbSessions.Count) Matching SMB Sessions"

    $uniqueFileIds = ($smbSessions).FileId | Sort-Object -Unique

    foreach ($fileId in $uniqueFileIds) {
        $session = @($smbSessions | Where-Object { $_.FileId -eq $fileId })[0]

        $sessionId = $session.SessionId
        $username = $session.ClientUserName
        $path = $session.Path

        Write-Verbose "Closing FileId $fileId on SMB Session $sessionId for user $username in path $path"

        try {
            if ($null -ne (Get-SmbOpenFile -FileId $fileId)) {
                ## Yes this is FOUR ways to suppress output. 
                ## Microsoft has proven remarkably resilient at showing an error here.
                ## the ErrorAction Continue still throws an error in TeamCity but not locally
                ## The try catch doesn't catch
                ## The Out-Null is because on the off chance the redirect works on the output, it shouldn't show the faux-error
                ## The output redirection is because this error isn't written to "standard error"
                ## TeamCity seems to be not honoring this output redirection in the shell it's running under to execute this block
                (Close-SmbOpenFile -FileId $fileId -Force -ErrorAction Continue *>&1) | Out-Null
                ## Run this line instead of the above to actually see the error pretty frequently, by my testing
                ## Close-SmbOpenFile -FileId $fileId -Force
            }
        } catch {
            $errorMessage = $_.Exception.Message
            Write-Warning "An Error Occurred While Trying to Close Session $sessionId : $errorMessage"
        }
    }
}

Первоначально мы проходили сессию, но я переключился на эту версию кода $ fileId, чтобы посмотреть, смогу ли я очистить его таким образом с помощью unique и et c. У тех, кажется, нет улучшений.

Мы могли бы просто сделать Get-SMBOpenFile | Where-Object <pathmatch> | Close-SMBOpenFile (см., Например, здесь https://serverfault.com/questions/718875/close-locked-file-in-windows-share-using-powershell-and-openfiles и здесь https://community.spiceworks.com/topic/2218597-issue-with-close-smbopenfile ) но, как вы можете видеть, мы хотим записать, что закрываем его на случай, если что-то пошло не так, и это помогает нам понять, что.

Вот ошибка, с которой я должен бороться:

[Clearing File Locks] No MSFT_SMBOpenFile objects found with property 'FileId' equal to '825975900669'.  Verify the value of the property 
[Clearing File Locks] and retry.
[Clearing File Locks] At C:\Program Files\WindowsPowerShell\Modules\...SNIP.psm1:2566 char:34
[Clearing File Locks] +         $jobs | ForEach-Object { Receive-Job -Job $_ }
[Clearing File Locks] +                                  ~~~~~~~~~~~~~~~~~~~
[Clearing File Locks]     + CategoryInfo          : ObjectNotFound: (825975900669:UInt64) [Get-SmbOpenFile], CimJobException
[Clearing File Locks]     + FullyQualifiedErrorId : CmdletizationQuery_NotFound_FileId,Get-SmbOpenFile
[Clearing File Locks]     + PSComputerName        : localhost
[Clearing File Locks]  
[Clearing File Locks] Process exited with code 1

Но дело в том, что перед тем, как сделать это, я проверяю еще раз, чтобы убедиться, что файл открыт, верно? Поэтому я говорю: «Это существует? Да? Закройте его», и все же я получаю эту ошибку, которая не имеет смысла для меня.

Я пытался найти другие способы для объекта, который возвращается, чтобы гарантировать, что Мне нужно удалить файл или, если есть что-то, что говорит «это должно быть пропущено», но я ничего не могу понять.

Так как у меня здесь нет вариантов, есть ли альтернативный метод, который я не рассматривал? Какая-то команда CIMInstance? Я, очевидно, ослеп, если есть. Это выполняется локально на компьютере, а не в сеансе.

Кто-то в моей организации наконец заметил, что ошибка говорит, что Get-SmbOpenFile с параметром FileId является ошибкой, поэтому это должно быть та же ошибка перенаправления. На данный момент, похоже, у меня может быть ответ.

Слепота отстой

Соответствующие сведения о машине:

PS Z:\git\...SNIP> $PSVersionTable

Name                           Value
----                           -----
PSVersion                      5.1.17763.1007
PSEdition                      Desktop
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0...}
BuildVersion                   10.0.17763.1007
CLRVersion                     4.0.30319.42000
WSManStackVersion              3.0
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1

PS Z:\git\...SNIP> Get-CimInstance Win32_OperatingSystem | Select-Object Caption, Version, ServicePackMajorVersion, OSArchitecture, CSName, WindowsDirectory


Caption                 : Microsoft Windows 10 Enterprise LTSC
Version                 : 10.0.17763
ServicePackMajorVersion : 0
OSArchitecture          : 64-bit
CSName                  : ...SNIP
WindowsDirectory        : C:\Windows

Но это также работает в Windows Серверных средах. Та же версия PowerShell. Последние Windows патчи и c на всех серверах. Я знаю, что мы еще не перевели флот в Датацентр 2019 года, но у нас есть несколько странных 800 серверов в производстве / тестировании по всему флоту, о котором я знаю, эти вещи, конечно, требуют времени. Если проблема в 2016 году, то в этом проблема.

PS Z:\git\...SNIP> Get-CimInstance Win32_OperatingSystem -ComputerName ...SNIP | Select-Object Caption, Version, ServicePackMajorVersion, OSArchitecture, CSName, WindowsDirectory


Caption                 : Microsoft Windows Server 2016 Datacenter
Version                 : 10.0.14393
ServicePackMajorVersion : 0
OSArchitecture          : 64-bit
CSName                  : ...SNIP
WindowsDirectory        : C:\Windows

Может быть, мое решение - заставить TeamCity выполнить перенаправление вывода? Сервер 2016 не поддерживает перенаправление вывода? Является ли это просто стремлением надежно закрыть эти соединения? Есть ли версия файловой системы, которую я не собираюсь проверять?

Когда я пытаюсь создать файл в \\mymachine\c$\temp\temp.txt и открыть его, это то, что я получаю (обратите внимание, что я использую только блокнот для открытия файл, поэтому блокировка не выполняется)

PS Z:\git\devops_powershell> Get-SMBOpenFile

FileId        SessionId     Path    ShareRelativePath ClientComputerName   ClientUserName
------        ---------     ----    ----------------- ------------------   --------------
1065151889485 1065151889409 C:\                       ...SNIP              ...SNIP
1065151889489 1065151889409 C:\                       ...SNIP              ...SNIP
1065151889613 1065151889409 C:\temp temp              ...SNIP              ...SNIP
1065151889617 1065151889409 C:\temp temp              ...SNIP              ...SNIP
1065151889833 1065151889409 C:\temp temp              ...SNIP              ...SNIP


PS Z:\git\...SNIP> Get-SmbOpenFile -FileId 1065151889833 | Select-Object -Property *


SmbInstance           : Default
ClientComputerName    : ...SNIP
ClientUserName        : ...SNIP
ClusterNodeName       :
ContinuouslyAvailable : False
Encrypted             : False
FileId                : 1065151889833
Locks                 : 0
Path                  : C:\temp
Permissions           : 1048736
ScopeName             : *
SessionId             : 1065151889409
ShareRelativePath     : temp
Signed                : True
PSComputerName        :
CimClass              : ROOT/Microsoft/Windows/SMB:MSFT_SmbOpenFile
CimInstanceProperties : {ClientComputerName, ClientUserName, ClusterNodeName, ContinuouslyAvailable...}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties



PS Z:\git\...SNIP> Get-SmbOpenFile -FileId 1065151889617 | Select-Object -Property *


SmbInstance           : Default
ClientComputerName    : ...SNIP
ClientUserName        : ...SNIP
ClusterNodeName       :
ContinuouslyAvailable : False
Encrypted             : False
FileId                : 1065151889617
Locks                 : 0
Path                  : C:\temp
Permissions           : 1048705
ScopeName             : *
SessionId             : 1065151889409
ShareRelativePath     : temp
Signed                : True
PSComputerName        :
CimClass              : ROOT/Microsoft/Windows/SMB:MSFT_SmbOpenFile
CimInstanceProperties : {ClientComputerName, ClientUserName, ClusterNodeName, ContinuouslyAvailable...}
CimSystemProperties   : Microsoft.Management.Infrastructure.CimSystemProperties

Должен ли я сосредоточиться только на случае, когда Locks -gt 0?

1 Ответ

0 голосов
/ 06 марта 2020

Похоже, что мы могли сузить причину root из-за сбоя Get-SmbOpenFile -FileId $fileId. Вероятно, это связано с несколькими параллельными списками файлов, разделенными на 4 части, так что когда в последнем примере выше 1065151889485 закрывается, он также «закрывает» 1065151889489, а затем, когда мы пытаемся выполнить итерацию для l oop для это значение, оно не может найти его и, следовательно, выдает ошибки.

PS Z:\git\devops_powershell> Get-SMBOpenFile

FileId        SessionId     Path    ShareRelativePath ClientComputerName   ClientUserName
------        ---------     ----    ----------------- ------------------   --------------
1065151889485 1065151889409 C:\                       ...SNIP              ...SNIP
1065151889489 1065151889409 C:\                       ...SNIP              ...SNIP
1065151889613 1065151889409 C:\temp temp              ...SNIP              ...SNIP
1065151889617 1065151889409 C:\temp temp              ...SNIP              ...SNIP
1065151889833 1065151889409 C:\temp temp              ...SNIP              ...SNIP

Я собираюсь изменить эту строку Get-SmbOpenFile -FileId $fileId утром и протестировать с ерундой "обход ошибки" и посмотреть, что там тоже бывает Или просто возьмите эту проверку и попробуйте еще раз.

Я все еще очень сильно растерялся, потому что try-catch активно не отлавливает ошибку как выданную. Если бы это было так, у меня было бы только предупреждение о записи вместо конечного процесса, который у меня сейчас.

...