powershell - Close-SMBOpenFile 抛出错误并且未在 try-catch 中捕获

标签 powershell teamcity smb

我们在脚本执行模式下使用 TeamCity powershell 作为具有快照和工件依赖项的管道的一部分。我们有一个相当强大的系统,并且已经使用这个特定的过程几年了,所以这不是我第一次调试的全新代码。可悲的是。它通常会起作用,直到随机不起作用为止。当错误确实发生时,TeamCity Agent 会有所不同。

我们流程的这一部分进行一些代码部署和一些日志备份。为了完全完成备份,我们必须确保质量检查或开发人员在办公 table 上查看日志时不会保持文件打开状态,并且可能以读写模式等打开它们。因为他们会从笔记本电脑/台式机打开它们,所以它们自然是 SMB 共享。所以我们下面有这个函数,它应该关闭给定服务器上打开的文件。我说“应该”,因为它偶尔会抛出此错误,而我似乎无法捕获它(甚至在本地)或抑制它,因此它会破坏 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"
        }
    }
}

我们最初是通过 session ,但我更改为代码的 $fileId 版本,看看是否可以使用 unique 等清理它。这些似乎没有改进。

我们完全可以这样做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 命令?如果有的话,我显然已经雪盲了。这确实在计算机本地运行,而不是跨 session 运行。

Someone in my org finally noticed that the error does say Get-SmbOpenFile with the FileId parameter is the failure, so that has to be the same redirection error. At this point it looks like I may have an answer.

Snowblindness sucks

相关机器详细信息:

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 Server 环境上。相同版本的 PowerShell。所有服务器上的最新 Windows 补丁等。我知道,我们还没有将机群转移到 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 遵守输出重定向? Server 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? 的情况吗?

最佳答案

看起来我们可能已经缩小了由于 Get-SmbOpenFile -FileId $fileId 失败而导致的根本原因。这可能与多个 4 部分并发文件列表有关,例如,在上面的最后一个示例中,当 1065151889485 关闭时,它也会“关闭”1065151889489,然后当我们尝试在循环中迭代该值时,它找不到它,因此出错。

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 行,并使用“错误绕过”废话进行测试,看看那里也会发生什么。或者只是 checkout 并重试。

我仍然非常困惑 try-catch 如何不主动捕获抛出的错误。如果确实如此,我只会收到一个写警告,而不是现在的结束进程。

关于powershell - Close-SMBOpenFile 抛出错误并且未在 try-catch 中捕获,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60556820/

相关文章:

msbuild - TeamCity 构建失败

powershell - 如何使用带有参数的 validatepattern 来使用 try/catch?

powershell - Powershell:一些简单的编号

arrays - 我不明白为什么我的数组会产生我无法使用的输出

teamcity - 无法定位文件 'C :\BuildAgent\temp\buildTmp\SYSTEM_[AGENT NAME] 2013-02-06 16_25_11\

teamcity - 使用 TeamCity 构建后复制文件

windows - Mule 文件传输以从 Windows SMB 共享读取文件

Python Linux-复制文件到windows共享盘(samba)

windows - 使用 Ansible 关闭 SMB 1.0/CIFS 文件共享支持?

windows - 升级到 Windows 10 后,从批处理文件调用 powershell.exe 速度慢得无法忍受