Close-SMBOpenFile引发错误,没有被try-catch捕获

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Close-SMBOpenFile引发错误,没有被try-catch捕获相关的知识,希望对你有一定的参考价值。

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

我们的过程的这一部分做了一些代码部署和一些日志备份。为了完全进行备份,我们必须确保QA或Devs不会在他们的办公桌旁查看日志的情况下打开文件,并可能以读写模式等打开文件。因为他们可以从笔记本电脑/台式机打开它们,所以它们自然是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"
        
    

我们最初是通过会话,但是我更改为代码的$ fileId版本,以查看是否可以使用unique和etc来清理它,这些似乎没有改善的地方。

我们可以很好地执行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命令?如果有的话,我显然被雪盲了。它确实在计算机上本地运行,而不是跨会话运行。

我的组织中的某个人终于注意到,该错误确实表明带有FileId参数的Get-SmbOpenFile是失败的,因此必须是相同的重定向错误。在这一点上,我可能已经找到了答案。

雪盲很烂

有关机器的详细说明:

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?的情况>>

我们正在脚本执行模式下使用TeamCity Powershell,作为具有快照和工件依赖项的管道的一部分。我们拥有一个相当强大的系统,并且一直在使用此特定过程...

答案

[似乎由于Get-SmbOpenFile -FileId $fileId失败,我们可能已缩小了根本原因。这可能与多个4个并发文件列表有关,例如,在上面的最后一个示例中,关闭1065151889485时,它也“关闭”了1065151889489,然后当我们尝试对该值进行循环时,它找不到它,因此出错了。

以上是关于Close-SMBOpenFile引发错误,没有被try-catch捕获的主要内容,如果未能解决你的问题,请参考以下文章

OleDbCommand 不会更新 MS Access 数据库,不会引发错误

调用目标引发的运行时错误豁免

跟进:缺少 django Modelform 中所需的 Charfield 被保存为空字符串并且不会引发错误

为啥我的 Django 表单没有引发验证错误?

未应用字体未引发错误

为啥我的 PL/SQL 触发器会引发“错误(2,2):PL/SQL:语句被忽略”和“错误(2,5):PLS-00204:函数或伪列'EXISTS'”错误?