【问题标题】:VBScript and Negative Session ID'sVBScript 和否定会话 ID
【发布时间】:2016-08-28 21:54:51
【问题描述】:

我正在尝试编写 VBScript,它将检查我们的文件共享上的打开文件,如果找到,则关闭与该文件的会话。问题是对象的会话 ID 有时会返回负数,因此它并不总是有效。当使用 Net File 将其与实际会话 ID 进行比较时,它是完全不同的。下面是代码。

If LCase(Right(Wscript.FullName, 11)) = "wscript.exe" Then
    strPath = Wscript.ScriptFullName
    strCommand = "%comspec% /k cscript """ & strPath & """"
    Set objShell = CreateObject("Wscript.Shell")
    objShell.Run(strCommand), 1, True
    Wscript.Quit
End If

intFound = 0

Set objNetwork = CreateObject("WScript.Network")
Set objShell = CreateObject("WScript.Shell")

strDomain = objNetwork.UserDomain
strServerName = "myServerName"
strFileToClose = "Some Open File.PDF"

Set objConnection = GetObject("WinNT://" & strDomain & "/" & strServerName & "/LanmanServer")
Set objOpenFiles = objConnection.Resources

WScript.Echo "Files open on " & strServerName & VbCrLf & "=============================="
strIDs = ""

For Each objFile In objOpenFiles
    On Error Resume Next
    temp = objFile.User
If Err.Number = 0 Then
    On Error GoTo 0
    If InStr(LCase(objFile.Path), LCase(strFileToClose)) > 0 Then
        WScript.Echo objFile.Name & " || " & objFile.Path & " || " & objFile.User
        If strIDs = "" Then
            strIDs = objFile.Name
        Else
            strIDs = strIDs & ";" & objFile.Name
        End If
        intFound = intFound + 1
    End If
Else
    Err.Clear
    On Error GoTo 0
End If
Next

WScript.Echo ""

If intFound > 0 Then
    arrIDs = Split(strIDs, ";")
    For Each strFileID In arrIDs
        strCommand = "cmd /c Net File " & strFileID & " /close"
        objShell.Run strCommand, 0, True
        WScript.Echo strFileID & " has been closed."
    Next
Else
    WScript.Echo "No matching open files were found."
End If

这是一个输出示例,其中包含来自脚本的负会话 ID,然后是来自 Net File 的实际结果。请记住,它们有时匹配,有时不匹配!

Microsoft (R) Windows Script Host Version 5.8
Copyright (C) Microsoft Corporation. All rights reserved.

Files open on myServerName
==============================
-2013150206 || C:\\Users\user\Desktop\Some Open File.PDF || user

-2013150206 has been closed. 'Not true since it is a negative number

C:\Users\admin\Desktop>net file 2281817090 'Actual Session ID
File ID         2281817090
User name       user
Locks           0
Path            C:\\Users\user\Desktop\Some Open File.PDF
Permissions     R
The command completed successfully.


C:\Users\admin\Desktop>

我认为正在发生的事情是变体的数据类型正在发生变化,如果数字足够大,它将被存储为负值......我认为您不能将其更改为无符号整数,并且假设我什至知道发生了什么,这可能是完全错误的。

【问题讨论】:

    标签: vbscript


    【解决方案1】:

    我可以用负文件 ID 重现您的问题(似乎是 Microsoft 产品错误,因为我发现的所有文档都说 Name/ID 属性应该是一个字符串)。
    下一个评论 Powershell 脚本显示了一种解决方法:添加 4,294,967,2962^32 值以补偿 32 位算术溢出。

    $server  = "$env:COMPUTERNAME"                      # change to meet your terms
    
    $netfile = [ADSI]"WinNT://$server/LanmanServer"     # bind to an ADSI object
    $netfile.Invoke("Resources") |
      foreach {$collection = @()} {                    <# create and load an array #>
        $collection += New-Object PsObject -Property @{
            Id = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
            UserName = $_.GetType().InvokeMember("User", 'GetProperty', $null, $_, $null)
            LockCount = $_.GetType().InvokeMember("LockCount", 'GetProperty', $null, $_, $null)
            Server = $server
            Path = $_.GetType().InvokeMember("Path", 'GetProperty', $null, $_, $null)
        }
    }
    $collection |
      Where-Object {([long]$_.Id) -lt 0} |               <# for each negative Id  #>
        Format-Table -AutoSize -Property Id, Path        <# show result: Id, Path #>
    $collection | 
      Where-Object {([long]$_.Id) -lt 0} |               <# for each negative Id  #>
        ForEach-Object {
          $IdPlus = [string]([long]$_.Id + 0x100000000)   # add 4294967296
                                                          # and call `net` command
          & cmd /C net file $IdPlus `| findstr `/V "^User successfully.$ ^Locks ^Permissions"
        }
    

    输出Copy&amp;Paste 来自提升 PowerShell 窗口):

    Windows PowerShell
    Copyright (C) 2014 Microsoft Corporation. All rights reserved.
    
    PS C:\Windows\system32> D:\PShell\SO\39196152a.ps1
    
    Id         Path
    --         ----
    -201326469 C:\attachments
    -402652947 C:\$AVG
    -402652182 D:\Downloads\Batch-File-Programming.pdf
    
    
    File ID         4093640827
    Path            C:\attachments
    
    File ID         3892314349
    Path            C:\$AVG
    
    File ID         3892315114
    Path            D:\Downloads\Batch-File-Programming.pdf
    
    PS C:\Windows\system32>
    

    请注意

    • 在Powershell中:[long]数字类型表示[int64];另一方面,
    • 在 VBScript 中:[long] Variant subtype 表示 [int32];您需要使用[double] 子类型来保存从-2,147,483,648+2,147,483,647 范围之外的值,请参阅CDbl() function

    使用CDbl 函数提供从任何数据类型到 Double 子类型。例如,CDbl 强制双精度 通常会发生货币或整数算术时的算术。

    更多资源

    【讨论】:

    • 谢谢!这确实证实了我的怀疑,即它确实是某种错误。虽然我还不是 Powershell 的专家,但这确实是一个很好的解决方法。
    【解决方案2】:

    我最终使用 VBA 编写了一个不同的解决方案,该解决方案适用于我们当前的任务系统,并且能够根据特定文件名可靠地提取文件会话 ID,然后将它们全部关闭。

    Dim strFileToClose As String
    Dim strLine As String
    Dim strSession As String
    Dim time1, time2
    Sub main()
    
    'Initialize strings as empty
    strFileToClose = ""
    strLine = ""
    strSession = ""
    
    strFileToClose = "Some Open File.PDF"
    
    'Update the text file of open file sessions on the server
    Call Shell("cmd /c c:\psexec.exe \\remoteServerName cmd /c net file > c:\temp\file_sessions.txt", vbNormalFocus)
    
    'Need to add a delay before we parse the text file
    time1 = Now
    time2 = Now + TimeValue("0:00:03")
    
    Do Until time1 >= time2
        time1 = Now()
    Loop
    
    'Parse the text file for our open file session ID
    Set objFSO = CreateObject("Scripting.FileSystemObject")
    Set objOutput = objFSO.OpenTextFile("c:\temp\file_sessions.txt", 1)
    
    Do Until objOutput.AtEndOfStream
        strLine = objOutput.ReadLine()
    
        If InStr(LCase(strLine), LCase(strFileToClose)) > 0 Then
            'Extract just the file session ID from the parse
            strSession = Split(strLine, " ")(0)
            'MsgBox strSession
    
            'Take the found session ID from the text file and use it to close the session
            Call Shell("cmd /c c:\psexec.exe \\remoteServerName cmd /c net file """ & strSession & """ /close", vbNormalFocus)
    
        End If
    
    Loop
    'Close the text file once it's done being read
    objOutput.Close
    
    End Sub
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-31
      • 1970-01-01
      相关资源
      最近更新 更多