2016-08-28 14 views
2

ファイル共有上で開いているファイルを確認し、見つかった場合はファイルへのセッションを終了するVBScriptを作成しようとしています。問題は、オブジェクトのセッションIDが時々マイナスに戻ってしまうため、常に機能するとは限りません。 Net Fileを使用して実際のセッションIDと比較すると、それはまったく異なります。以下はコードです。VBScriptとネガティブセッションIDの

ここでは、スクリプトからのネガティブセッション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> 

符号なし整数であり、私は何が起こっているのかを知ることで完全に間違っている可能性があります。

答えて

0

ネガティブファイルIDで問題を再現できます(見つかったすべてのドキュメントでName/IDプロパティが文字列である必要があるため、Microsoftの製品バグのようです)。
次のようにコメントしました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" 
    } 

出力からCopy&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]を意味します。あなたはCDbl() functionを参照して、-2,147,483,648から+2,147,483,647に範囲外の値を保持するために[double]サブタイプを使用する必要があります。

Doubleサブタイプに任意のデータ型からの変換を提供するために、CDbl機能を使用してください。たとえば、CDblは、通貨または整数の算術演算が通常発生するときに、倍精度 の演算を強制します。

さらにリソース

+0

ありがとうございます!これは本当に何らかのバグであったという私の疑惑を確認します。私はPowershellの教祖ではありませんが、これは本当に良い解決策です。 – Corplexis

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