Hey, Scripting Guy! Quick-Hits Friday: The Scripting Guys Respond to a Bunch of Questions (02/20/09)


How Do I Determine the Versions of Several Executable Files Not Registered in the Registry?


Hey, Scripting Guy! Question

Hey, Scripting Guy! I need your help. I need to know the version of several executable files not registered in the registry. I can find the version of a single executable by using the following code.

Set objFSO = CreateObject("Scripting.FileSystemObject")
Wscript.Echo objFSO.GetFileVersion("C:\... nameofexefile")

But I need to “scan” several directories (or all Drive C:\).

– UG

SpacerHey, Scripting Guy! Answer

Hi UG,

What you need to do is to use a technique called recursion. When you recurse through something, you basically use a subroutine that will call itself. We need to do a couple of things. First we need to connect to your target folder. We then need to get a collection of all the files in that folder and check them out. After we have done that, we next need to get the subfolders. We then pass the subfolders back to the subroutine, get the files and do it all over again. We will continue to do this until we have checked out all the files. Here is a script, named GetFileVersionInfoRecurse.vbs that will do that.

strTarget = "c:\fso"
Set objFSO = CreateObject("Scripting.FileSystemObject")
subRecursiveFolders objFSO.GetFolder(strTarget)
Sub subRecursiveFolders(Folder)
Set colFiles = Folder.files
  For Each file In colFiles
      WScript.Echo file.path
      ver = objFSO.GetFileVersion(file.path)
      If Len(ver) Then
          WScript.Echo ver
      WScript.Echo  "No version information available."
   End If
  Next 'for each file
  For Each objFolder In Folder.subFolders
      subRecursiveFolders objFolder
End Sub

How Do I Determine Who Has a Particular File Open?


Hey, Scripting Guy! Question

Hey, Scripting Guy! I have been trawling the net for days trying to find a way to determine who has a file open. How do I script this?

– KP

SpacerHey, Scripting Guy! Answer

Hi KP,

There is not really a good way to get this information, and it is not always reliable. But we can use ADSI to obtain this information. On Windows Vista this script needs to run with admin rights. The ListUsedResources.vbs script uses the WinNT provider to connect to the local computer account, and to return what is called an IadsFileServiceOperations interface. This interface is documented on MSDN. When we call the Resources method, it returns a collection of IadsResource objects. These objects are also documented on MSDN. Here is the ListUsedResources.vbs script.

Set fso = GetObject("WinNT://Mred1/LanmanServer")
For Each r In fso.resources
WScript.Echo  "User " & r.user
WScript.Echo  vbTab & "Resource path: " & r.Path
WScript.Echo  vbTab & "Resource Lock count: " & r.lockCount

How Do I Execute Different Commands on Different Servers but from the Same Input File?


Hey, Scripting Guy! Question

Hey, Scripting Guy! I need to create a script that connects to several remote servers, using an input file like servers.txt with one hostname per line. And then I want it to execute a specific command, using the command prompt. I’m using VBScript; I know how to write the script and there are many examples on Script Center, but what I was asked is to have the same input file with the server name separated using a semicolon or a comma and the command to be run. So we’ll have something that looks like the following:

Server2;net use t: \\server4\shares

All this data will be written on servers.txt. Is there a script that can do it? You know, the script will read each line and execute the command on that server. When it reads the next line, it should run another command on a different server, but both server name and command will be in the same input file. I know I can do it using two separate input files, such as servers.txt and commands.txt, but for security reasons I must read this info from the same file. Is it possible?

– AG

SpacerHey, Scripting Guy! Answer

Hi AG,

Of course it is possible. What you want to do is to read a text file line by line, and then split the line into an array. You can then connect to server in element 0 and run the command from element 1. Here is a link that talks about working with text files.

We’ll assume your text file looks something like this:

Image of how the text file for this script might look


You can read the text file by using the readline method from the FileSystemObject.You can then use the split function to break each line into an array. After you have an array, you can use element 0 to refer to the computer and element 1 to refer to the command. You can then execute each command as you work your way through the file. This technique is illustrated in this script:

Const ForReading = 1
Set objShell = WScript.CreateObject("WScript.Shell")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objTextFile = objFSO.OpenTextFile("c:\fso\arycommand.txt", ForReading)
Do Until objTextFile.AtEndOfStream
    strNextLine = objTextFile.Readline
    arrServiceList = Split(strNextLine , ",")
    Wscript.Echo "Server name: " & arrServiceList(0)
    For i = 1 to Ubound(arrServiceList)
        Wscript.Echo "Command: " & arrServiceList(i)
        Set objExecObject = objShell.Exec("cmd /c " & arrServiceList(i))
           Do While Not objExecObject.StdOut.AtEndOfStream
             strText = objExecObject.StdOut.ReadLine()
             Wscript.Echo strText

How Can I Write to a File What I Can Already Write to the Screen?


Hey, Scripting Guy! Question

Hey, Scripting Guy! How come I can output stuff to my screen with no problem, but when I try to write it to a file (htm, csv, or text), all I get are blank lines. What’s the deal with that? My code is seen here.

Get-ChildItem $inPath -Recurse -ErrorAction Continue | foreach{
            $_.fullname | Get-Acl | select path -expand access |
            where {$_.IdentityReference -like "Domain*"} |
            ft path, IdentityReference -autosize
Write-Host "Number of files: " $i

– GE

SpacerHey, Scripting Guy! Answer

Hi GE,

In general, the Windows PowerShell team recommends against using Write-Host unless you need to use one of the parameters it provides such as coloring. What is happening is that Write-Host basically interrupts the pipeline, and there is no passthrough parameter for Write-Host. Here is code that works:

Get-ChildItem $inPath -Recurse -ErrorAction Continue |
Foreach-object {
            $_.fullname |
            Get-Acl |
            Select-Object path -expand access |
             Where-object {$_.IdentityReference -like "Domain*"} |
             Format-Table path, IdentityReference -autosize
"Number of files: $i" |
Out-File -filepath c:\fso\filecount.txt
notepad "c:\fso\filecount.txt"

Well, that is it for this week’s Quick-Hits Friday. It is also the end of another week. Have a safe and productive weekend, and we will see you here next week. Take care.


Ed Wilson and Craig Liebendorfer, Scripting Guys