Possible to close an open file with script or command line?

We have a file that is linked to from our intranet. The file is a PDF file that a process recreates with the same name every several hours. The problem is, if a user is viewing that file (or has just left it open), the process cannot update the file because it is locked. An admin has to go into the server and through Computer Management -> System Tools ->Shared Folders -> Open Files -> Close open file.

Since this happens several times a day, I'd like to give the user a script or similar to run (or add to the beginning of his process) to force closed the file before updating. The user has full rights to the share and NTFS folder where the PDF file gets created.

Any help would be great. Thanks.
LVL 5
drothbartAsked:
Who is Participating?
 
RobSampsonConnect With a Mentor Commented:
OK, I've added a bit more error checking, and the Microsoft Scripting Guys said this didn't work very well when run from a Windows XP system....

'====================
Set objNetwork = CreateObject("WScript.Network")
strDomain = objNetwork.UserDomain
strServerName = "ntfp"
strFileToClose = "An_Open_File_To_Force_Closed.doc"

On Error Resume Next

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

strResults = "Files open on " & strServerName & VbCrLf & "=============================="
For Each objFile In objOpenFiles
      strResults = strResults & VbCrLf & "ResourceID: " & objFile.Name
      strResults = strResults & VbCrLf & "Resource: " & objFile.Path
      strResults = strResults & VbCrLf & "Opened by user: " & objFile.User
      strResults = strResults & VbCrLf & "Locks: " & objFile.LockCount & VbCrLf
      
      strFileName = LCase(Mid(objFile.Path, InStrRev(objFile.Path, "\") + 1))
      If Err.Number = 0 Then
            If strFileName = LCase(strFileToClose) Then
                  objOpenFiles.Remove objFile.Name
                  If Err.Number = 0 Then
                        MsgBox "File closed successfully."
                  Else
                        Err.Clear
                        MsgBox "Error closing file."
                  End If
            End If
      Else
            Err.Clear
      End If

Next

MsgBox strResults
'====================

Regards,

Rob.
0
 
tuttlepcCommented:
0
 
drothbartAuthor Commented:
I found that when I searched too, but really didn't know how to incorporate into a script to discriminately close files only in one share on a fileserver. How would that be accomplished?
0
Free Tool: IP Lookup

Get more info about an IP address or domain name, such as organization, abuse contacts and geolocation.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
RobSampsonCommented:
Here's a VBScript that shows open resources.....just need to identify how to close it.....

'=================
Set objNetwork = CreateObject("WScript.Network")
strDomain = objNetwork.UserDomain
strServerName = "NTFP"

On Error Resume Next

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

strResults = "Files open on " & strServerName & VbCrLf & "=============================="
For Each objFile In objOpenFiles.Resources
      strResults = strResults & VbCrLf & "ResourceID: " & objFile.Name
      strResults = strResults & VbCrLf & "Resource: " & objFile.Path
      strResults = strResults & VbCrLf & "Opened by user: " & objFile.User
      strResults = strResults & VbCrLf & "Locks: " & objFile.LockCount & vbCrLf
Next

MsgBox strResults
'=================

Regards,

Rob.
0
 
RobSampsonCommented:
And you can close a specific one by using:

If Mid(objFile.Path, InStrRev(objFile.Path, "\") + 1) = "filename.doc" Then
   objOpenFiles.Remove objFile.Name
End If

Regards,

Rob.
0
 
drothbartAuthor Commented:
Thanks, Rob. I'll try to see if I can roll those two up and let you know.

Dan
0
 
RobSampsonCommented:
No, worries, you can just put the three lines from the last one above the Next statement in the first one...

Regards,

Rob.
0
 
drothbartAuthor Commented:
Rob, I have the below code as a vbs on a test machine. It will list correctly the open files but will not close the listed file "test.pdf". Ideas? Machine name is smh0054559.

Set objNetwork = CreateObject("WScript.Network")
strDomain = objNetwork.UserDomain
strServerName = "smh0054559"

On Error Resume Next

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

strResults = "Files open on " & strServerName & VbCrLf & "=============================="
For Each objFile In objOpenFiles.Resources
      strResults = strResults & VbCrLf & "ResourceID: " & objFile.Name
      strResults = strResults & VbCrLf & "Resource: " & objFile.Path
      strResults = strResults & VbCrLf & "Opened by user: " & objFile.User
      strResults = strResults & VbCrLf & "Locks: " & objFile.LockCount & vbCrLf

If Mid(objFile.Path, InStrRev(objFile.Path, "\") + 1) = "test.pdf" Then
   objOpenFiles.Remove objFile.Name
End If

Next

MsgBox strResults
0
 
RobSampsonCommented:
It may be a case sensitive issue. I'll test it, but try changing this:
If Mid(objFile.Path, InStrRev(objFile.Path, "\") + 1) = "test.pdf" Then

to this
If LCase(Mid(objFile.Path, InStrRev(objFile.Path, "\") + 1)) = LCase("test.pdf") Then

Regards,

Rob.
0
 
drothbartAuthor Commented:
That could be it; my test system is XP but I will be running it on a 2003 server. I'll test it on my test server instead.

0
 
RobSampsonCommented:
OK, let me know how you go.

Regards,

Rob.
0
 
drothbartAuthor Commented:
Rob - It lists the open resources, but the lines to close the file fail. I remarked out the line to clear the error number, and it reports an error -2147467263. I'm running it on a Windows 2003 server, trying to close a PDF file.

Dan
0
 
RobSampsonCommented:
Hi, well I've done some testing too, and from what I can tell, including this info:
http://msdn2.microsoft.com/en-us/library/aa705979(VS.85).aspx

the Resources collection does not support a direct removal command.

You can, however, disconnect the entire user's share, if you like, using the code from that link.

Regards,

Rob.
0
 
drothbartAuthor Commented:
Well, "it's not possible" is sometimes the answer and as a non-programmer I appreciate all of your patience and help. I'll see what I can work out from here.

Thanks!
0
 
drothbartAuthor Commented:
Thanks for hanging in there with me.
0
 
RobSampsonCommented:
No worries. I would like to eventually know if it can be possible with some other method, perhaps a proper API call or something, but it doesn't seem possible with VBScript on files themselves.

Thanks for the grade.

Regards,

Rob.
0
 
RobSampsonCommented:
I don't have a test machine other than Windows XP that has Excel on it, but if you can try this code in Excel on a non-Windows XP machine, maybe it will work.

Insert a new module into a workbook, and paste this code.  Change the strServerName and strFileToClose values, open that file remotely, and see if it will close it.  I got response of 1113 and it didn't close.....


Declare Function NetFileClose Lib "netapi32.dll" _
    (ByVal servername As String, _
    ByVal fileid As Long) As Integer
Sub CloseFile()
    Set objNetwork = CreateObject("WScript.Network")
    strDomain = objNetwork.UserDomain
    strServerName = "ntfp"
    strFileToClose = "File_To_Force_Closed.doc"
   
    On Error Resume Next
   
    Set objConnection = GetObject("WinNT://" & strDomain & "/" & strServerName & "/LanmanServer")
    Set objOpenFiles = objConnection.Resources
   
    strResults = "Files open on " & strServerName & vbCrLf & "=============================="
    For Each objFile In objOpenFiles
          strResults = strResults & vbCrLf & "ResourceID: " & objFile.Name
          strResults = strResults & vbCrLf & "Resource: " & objFile.Path
          strResults = strResults & vbCrLf & "Opened by user: " & objFile.User
          strResults = strResults & vbCrLf & "Locks: " & objFile.LockCount & vbCrLf
         
          strFileName = LCase(Mid(objFile.Path, InStrRev(objFile.Path, "\") + 1))
          If Err.Number = 0 Then
                If strFileName = LCase(strFileToClose) Then
                    strResponse = MsgBox("Are you sure you want to disconnect this resource?" & vbCrLf & _
                        "ResourceID: " & objFile.Name & vbCrLf & _
                        "Resource: " & objFile.Path, vbYesNo, "Close File?")
                    If strResponse = vbYes Then
                        intResult = NetFileClose(strServerName, fileid)
                        MsgBox "Result: " & intResult
                    End If
                End If
          Else
                Err.Clear
          End If
   
    Next

    MsgBox strResults
End Sub



Here's another thread trying the same thing:
http://www.experts-exchange.com/Programming/Languages/Visual_Basic/VB_Script/Q_23100841.html

Regards,

Rob.
0
 
RobSampsonCommented:
Oh, also in Excel, while in the VBE window, add a reference to the Microsoft Scripting Runtime object via Tools --> References.

Regards,

Rob.
0
 
kaascoCommented:
Heya,

I run this command on my NAS (Windows 2003 Storage Server) every night before the backups run. I found this somewhere on the internet, I don't remember where. This runs a loop on the net files command with  the "/close" switch for each file ID.
for /f "skip=4 tokens=1" %%a in ('net files') do net files %%a /close

Open in new window

0
 
kaascoCommented:
Regarding that last comment... use %%a when in a .bat file, otherwise use %a (from cmd.exe).
0
 
RobSampsonCommented:
Hey kaasco, thanks for sharing that info....I've incorporated that (with the user of PSEXEC), to run remotely against a server to close a specific handle on an open file.

Regards,

Rob.
'====================
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 = "FILESERVER"
strFileToClose = "File_To_Force_Closed.doc"
strPSExecPath = "\\server\share\psexec.exe"
 
Set objConnection = GetObject("WinNT://" & strDomain & "/" & strServerName & "/LanmanServer")
Set objOpenFiles = objConnection.Resources
 
WScript.Echo "Files open on " & strServerName & VbCrLf & "=============================="
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
			intFound = intFound + 1
		End If
	Else
		Err.Clear
		On Error GoTo 0
	End If
Next 
WScript.Echo ""
If intFound > 0 Then
	WScript.Echo "Which ID do you want to close? "
	strFileID = WScript.StdIn.ReadLine
	If Trim(strFileID) <> "" Then
		strCommand = strPSExecPath & " -accepteula -e \\" & strServerName & " cmd /c Net Files " & strFileID & " /close"
		'InputBox "About to run:", "Command to Run", strCommand
		objShell.Run strCommand, 0, True
	End If
Else
	WScript.Echo "No matching open files were found."
End If
'====================

Open in new window

0
 
trmade98Commented:
Hey guys, I'm trying to do this same thing with an Access database, basically I make updates to a local version of the database all day and instead of having to manually kick everyone else out before i copy the local version to the network version I'd like to set up a scheduled task that would kick everyone out at like midnight(a lot of people leave it running for no good reason) then copy the database I did work on up to the currently active version that everyone sees on the network. Right now I'm working on making a basic VB.NET program, mainly because my boss wants to keep track of how long each update takes, i have it all set up except this piece, which is a problem cause this is the bulk of the project:-D. I'm trying to adapt some of the code you guys have posted but it doesn't doesn't seem to work at this line:

objConnection = GetObject("WinNT://" & strdomain & "/" & strServerName & "LanmanServer")

unfortunately, for me, I don't know what this function call is trying to do so I can't debug it myself. I've set the strdomain and strServerName varibales to what I think they should be but its still not working.

Thanks
0
 
trmade98Commented:
Hey again, sorry about double post but i mistyped,
I have set the server name and the file to close, the domain being pulled in by the program is getting the right value.

my main question is what the argument to the GetObject fucntion is, it looks like it should be the location of the server you are trying to connect to but if i hard code it in it still doesn't find it. any help is always appreciated!

thanks!
0
All Courses

From novice to tech pro — start learning today.