我正在尝试编写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
我认为正在进行的是变体的数据类型正在改变,如果数字足够大,它将被存储为负值......我认为你不能将它改为无符号整数,假设我甚至不知道发生了什么,我可能完全错了。
答案 0 :(得分:0)
我可以使用否定文件ID
重现您的问题(似乎是Microsoft产品错误,因为我发现的所有文档都说Name
/ ID
属性应该是字符串)。
下一个评论 Powershell 脚本显示了一种解决方法:添加4,294,967,296
即2^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>
请注意那
[long]
数字类型表示[int64]
;另一方面,[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