VBScript和否定会话ID

时间:2016-08-28 21:54:51

标签: vbscript

我正在尝试编写VBScript,它将在我们的文件共享中检查打开的文件,然后关闭会话到文件(如果找到)。问题是对象的会话ID有时会变回负面,所以它并不总是有效。将它与使用Net File的实际会话ID进行比较时,它完全不同。以下是代码。

= request.fields_for :new_category_rate do |u|

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

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

我认为正在进行的是变体的数据类型正在改变,如果数字足够大,它将被存储为负值......我认为你不能将它改为无符号整数,假设我甚至不知道发生了什么,我可能完全错了。

2 个答案:

答案 0 :(得分:0)

我可以使用否定文件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"
    }

输出(来自提升 PowerShell窗口的Copy&Paste):

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功能提供从任何数据类型到a的转换   Double子类型。例如,CDbl强制双精度   通常发生货币或整数算术时的算术。

更多资源

答案 1 :(得分:0)

我最终使用与当前任务系统一起工作的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