Link to home
Start Free TrialLog in
Avatar of recurve
recurve

asked on

Reading Extended File Attributes on NTFS (Part 2)

I'm a complete scripting newb, so please forgive any stupidity.

I'm trying to do the same thing that the guy from the following thread wrote about (hence this thread title).

Reider wrote:
> Is it possible to read a files comments as added in windows
> explorer using the file system object in ASP.

> I'm using W2K server with SP3 and IIS 5

in this thread:
https://www.experts-exchange.com/questions/20442743/Reading-File-attributes.html#1
 
The consensus answer was, "No, it's not possible." But I found the following script somewhere at MSDN that seems read and write from named streams that could be extended file attributes (???). But I can't make it work so far because I can't seem to figure out the exact names of the attributes for things like "Comment" and "Title" and "Subject" (which you can turn in on Explorer in Windows 2000). Is this script a red herring? If not, what are the correct strings for the extended file attributes on NTFS? Thanks!

' CreateStream.vbs
' Demonstrates streams on NTFS volumes
' --------------------------------------------------------

Option Explicit

' Some constants
Const L_NotNTFS = "Sorry, the current volume is not NTFS."
Const L_EnterFile = "Enter a file name"
Const L_TestNTFS = "Test NTFS"
Const L_StdFile = "c:\testntfs\test.txt"
Const L_EnterStream = "Enter a stream name"
Const L_StdStream = "VersionInfo"
Const L_EnterTextStream = "Enter the text of the stream"
Const L_StdContent = "1.0"

' Makes sure the current volume is NTFS
if Not IsNTFS() then
   MsgBox L_NotNTFS
   WScript.Quit
end if

' Query for a file name
dim sFileName
sFileName = InputBox(L_EnterFile, L_TestNTFS, L_StdFile)
if sFileName = "" then WScript.Quit

' Query for the stream to be written
dim sStreamName
sStreamName = InputBox (L_EnterStream, L_TestNTFS, L_StdStream)
if sStreamName = "" then WScript.Quit

' Initializes the FS object model
dim fso, bExist
set fso = CreateObject("Scripting.FileSystemObject")  

' Creates the file if it doesn't exist
dim ts
if Not fso.FileExists(sFileName) then
   set ts = fso.CreateTextFile(sFileName)
   ts.Close
end if

' Try to read the current content of the stream
dim sFileStreamName, sStreamText
sFileStreamName = sFileName & ":" & sStreamName
if Not fso.FileExists(sFileStreamName) then
   sStreamText = L_StdContent
else
   set ts = fso.OpenTextFile(sFileStreamName)
   sStreamText = ts.ReadAll()
   ts.Close
end if

' Query for the content of the stream to be written
sStreamText = InputBox (L_EnterTextStream, L_TestNTFS, sStreamText)
if sStreamText = "" then WScript.Quit

' Try to write to the stream
set ts = fso.CreateTextFile(sFileStreamName)
ts.Write sStreamText


' Close the app
set ts = Nothing
set fso = Nothing
WScript.Quit




' ////////////////////////////////////////////////////////
' // Helper functions

' IsNTFS() - Verifies whether the current volume is NTFS
' --------------------------------------------------------
function IsNTFS()
   dim fso, drv
   
   IsNTFS = False
   set fso = CreateObject("Scripting.FileSystemObject")  
   set drv = fso.GetDrive(fso.GetDriveName(WScript.ScriptFullName))
   set fso = Nothing
   
   if drv.FileSystem = "NTFS" then IsNTFS = True
end function
Avatar of markhoy
markhoy
Flag of United Kingdom of Great Britain and Northern Ireland image

The standard file attributes can be read:

Dim objFolder
  Set objFolder = objFSO.GetFolder(strRootFolder)

For Each objSubFolder in objFolder.SubFolders
     
     ModDate=objSubFolder.datelastmodified
          CreDate=objSubFolder.datecreated
          AccDate=objSubFolder.DateLastAccessed
          Attribs=objSubFolder.Attributes

next

Also,

'########################
Function GetFileInfo(f)
'########################
ShowOwner=True 'Show NTFS file owner info (owner includes domain name, so can be switched off for internet use)
On Error resume next
Set objShell = Server.CreateObject("Shell.Application")
Set objFolder = objShell.Namespace(fso.getparentFoldername(f))
s="<table bgcolor=EEEEEE cellpadding=2 cellspacing=0>"
s=s & "<tr align=center bgcolor=" & Application("BgColorHeader") & "><td colspan=2><b><font color=FFFFFF>" & fso.getfilename(f) & "</font></b></tr>"
For Each strFileName in objFolder.Items
     If LCase(strFileName.path)=LCase(f) Then
          For i = 1 to 39
               PropName=objFolder.GetDetailsOf(objFolder.Items, i)
               PropValue=objFolder.GetDetailsOf(strFileName, i)
                           If  PropName<> "" AND PropValue<>"" AND (ShowOwner OR i<>8) Then s=s & "<tr><td>" & PropName & "</td><td>" & PropValue & "</td></tr>"
          Next
     End If
Next
s=s & "</table><br>"
GetFileInfo=s
End Function

check for NTFS:

'########################
Function IsNTFS(f)
'########################
On Error resume next
Set drv = fso.GetDrive(fso.GetDriveName(f))
If drv.FileSystem = "NTFS" then IsNTFS=True Else IsNTFS=False
Set Drv=Nothing
End Function

and this may be what you're asking but I'm not sure...

'########################
SUB GetFileDescription(f,Description,DateCreated,UserName,IP)
'########################
On Error resume next
Description=""
If Right(f,1)="\" Then
     StreamFile=Left(f,len(f)-1) & ":FMInfo" 'Remove trailing backslash
Else
     StreamFile=f & ":FMInfo" 'Remove trailing backslash
End If
If fso.FileExists(StreamFile) Then
     Set ts=fso.OpenTextFile(StreamFile,1,True)
     s=ts.ReadAll
     aTmp=Split(s,VbCrLf)
     ts.Close
     If Ubound(aTmp)>0 Then
          aTmp1=Split(aTmp(0),"|")
          If Ubound(aTmp1)=2 Then
               DateCreated=aTmp1(0)
               UserName=aTmp1(1)
               IP=aTmp1(2)
          End If
          For i=1 To UBound(aTmp)
               Description=Description & aTmp(i) & VbCrLf
          Next
          Description=Left(Description,Len(Description)-2)
     End If
End If
End SUB
Avatar of recurve
recurve

ASKER

Hmmm... I'm not sure this is quite what I'm looking for, although I need to try out this script you have some more.

The file attributes I'm trying to read are:
Title
Comment
Subject
Category
Author
etc.

These are visible from Windows 2000 if you select a file in Explorer and then hit Alt-Enter (or File, Properties) and go to the Summary Tab.
Avatar of recurve

ASKER

Hmmm... I'm not sure this is quite what I'm looking for, although I need to try out this script you have some more.

The file attributes I'm trying to read are:
Title
Comment
Subject
Category
Author
etc.

These are visible from Windows 2000 if you select a file in Explorer and then hit Alt-Enter (or File, Properties) and go to the Summary Tab.
yes, looking at it the above doesn't do it. The extended file properties only exist for Office documents. You need to use Dsofile.dll :

http://support.microsoft.com/default.aspx?scid=kb;EN-US;q224351

http://msdn.microsoft.com/msdnmag/issues/0300/fso/default.aspx

Also,

https://www.experts-exchange.com/questions/20528038/dso-file.html
Avatar of recurve

ASKER

I'll look into these. However, I'm pretty sure these extended attributes don't have anything to do with MS Office since I can set and access them from Explorer for any file on my machine without having Office installed.

Someone should be able to verify this. Using Windows 2000 Explorer, pick any file anywhere on an NTFS volume; hit Alt-Enter, and go to the Summary tab. There's a long list of extended attributes even if it's not an Office document or you don't even have Office installed.
Avatar of recurve

ASKER

Markhoy, I really appreciate all the time and links you've provided so far. I don't really understand the "point system" here (I just registered to post this question), but I'll probably close this question soon and give you the points (assuming they're worth something).

However, before I give up, I'll try to clarify a couple more parts:

1. When I'm talking about Explorer above, I mean Windows Explorer (for files), not Internet Explorer.

2. I realize this is posted under ASP, but it's really more of a WSH/VBScript question. I just didn't know where to ask. The script I want (if it's possible) needs to be portable, so it can't rely on MS Office or DSOFILE.DLL.

3. I suspect that the script I posted in my original question (above) is very close to what I want. If someone who is knowledgeable on NTFS could just run it a couple times on NTFS and explain exactly what it's doing, that would be very helpful. :)

Thanks again.
hello,

1. yes, I know you mean Windows Explorer.
2. Yes, but haven't found any methods other than for office docs.
3. FSO, streaming etc whether asp or .wsh will access the same "properties".

The points are given if you accept or use an "answer". If not you can ask for it to be deleted and points refunded. Give it a couple of days before closing as the USA comes online now ish :-)
You may need an ActiveX component of some kind that can "see" the extended properties. Using FSO (http://www.w3schools.com/asp/asp_ref_filesystem.asp) you are limited, regardless of whether called by asp, .wsh etc.
ASKER CERTIFIED SOLUTION
Avatar of markhoy
markhoy
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I've tested this and it works. You will need to regsiter the dll. Download it from http://www.4guysfromrolla.com/webtech/code/suminfo/suminfo.zip

Mark
Avatar of recurve

ASKER

The ActiveX control suggestion above looks like a pretty good solution.

As followup from my own research, I discovered the SummaryInformation is stored in what is called an NTFS Alternate Data Stream (ADS). ADSes are special, often hidden parts of NTFS files that anyone can store and retrieve information from.

For example, from a Windows NT command-prompt:
C:\>echo This is some hidden text > test.txt:hidden

This will create an "empty" text file called test.txt. (The data actually gets routed to an ADS inside the file.)

C:\>type test.txt

C:\>dir test.txt
 Volume in drive C is SCSI9
 Volume Serial Number is 987D-A528

 Directory of C:\

04/02/2003  05:25a                   0 test.txt
               1 File(s)              0 bytes
               0 Dir(s)   5,016,702,976 bytes free

But the information is still there, witness:

C:\>more < test.txt:hidden
This is some hidden text

There is a free program called "Streams" available from http://www.sysinternals.com/ that will tell you the names of any ADSes in a file or files:
http://www.sysinternals.com/ntw2k/source/misc.shtml#Streams

Windows 2000 file Summary Information (like the Title, Author, Comments, etc.) is stored in a special ADS which the Streams utility identifies as "¢ÀSummaryInformation". But the club symbol at the head is actually ASCII character #5, which will not translate properly into a command-line ADS from that symbol.

Instead, you can read the Summary Information for a NTFS file (if there is any), as follows:

C:\>more < test.txt:^ESummaryInformation

The only problem remaining now is that the Summary Information is binarily encoded, so what you get from the previous command isn't readable. I'll have to see if I can find a way to decode it back into text.

Here are some helpful articles about ADSes:
http://patriot.net/~carvdawg/docs/dark_side.html
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/fileio/base/file_streams.asp
http://www.microsoft.com/msj/defaultframe.asp?page=/msj/1198/ntfs/ntfs.htm&nav=/msj/1198/newnav.htm
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/ntfs5.asp
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/ntfs2.asp

Thanks for your help Markhoy.
are you sure about this:

For example, from a Windows NT command-prompt:
C:\>echo This is some hidden text > test.txt:hidden

This will create an "empty" text file called test.txt. (The data actually gets routed to an ADS inside the file.)


doesn't it just create a hidden file called test.txt?
Avatar of recurve

ASKER

Try it out. You can make up any data stream name you want. The general naming format goes:
[filename]:[datastream name]
(That's a colon : in between the two names.)

The example I show of running a dir command in my post above is copied and pasted right from my command-prompt window. It's pretty strange stuff. I had never heard of these Alternate Data Streams before I started looking into this tonight.
Avatar of recurve

ASKER

Try it out. You can make up any data stream name you want. The general naming format goes:
[filename]:[datastream name]
(That's a colon : in between the two names.)

The example I show of running a dir command in my post above is copied and pasted right from my command-prompt window. It's pretty strange stuff. I had never heard of these Alternate Data Streams before I started looking into this tonight.
Avatar of recurve

ASKER

And, of course, after the two of us have spent all night researching this, I finally find a much simpler way to do this in WSH provided at Microsoft's web site. =(

http://www.microsoft.com/technet/treeview/default.asp?url=/technet/scriptcenter/filefolder/ScrFF64.asp

Dim arrHeaders(34)
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace("C:\Scripts")
For i = 0 to 33
arrHeaders(i) = objFolder.GetDetailsOf(objFolder.Items, i)
Next
For Each strFileName in objFolder.Items
For i = 0 to 33
Wscript.echo i & vbtab & arrHeaders(i) _
& ": " & objFolder.GetDetailsOf(strFileName, i)
Next
Next
OR,

<%
Dim arrHeaders(34)
Set objShell = CreateObject("Shell.Application")
Set objFolder = objShell.Namespace("C:\temp")
For i = 0 to 33
arrHeaders(i) = objFolder.GetDetailsOf(objFolder.Items, i)
Next
For Each strFileName in objFolder.Items
For i = 0 to 33
response.write i & vbtab & arrHeaders(i) _
& ": " & objFolder.GetDetailsOf(strFileName, i)
Next
response.write "<BR><BR>"
Next
%>

Very useful little script!!