ИВАН КОРОБКО
Программное управление файловой системой с помощью VBScript
Создавая сценарии, позволяющие автоматизировать различные процессы в сети, зачастую необходимо программно управлять файловой системой NTFS, а именно: создавать, удалять, перемещать, копировать файлы и папки; изменять их атрибуты и права доступа к ним. Такие сценарии могут быть созданы с помощью VBScript или JSсript. В данной статье все примеры будут приведены на VBScript.
Основы программного управления файловой системой
Для программного управления файловой системой NTFS с помощью VBScript рекомендуется использовать встроенный объект FileSystem Object, поддерживающий набор методов, перечисленных в таблице 1:
Таблица 1
Объект или набор
|
Описание
|
Drives
|
Набор всех логических, физических и съемных дисков
|
Drive
|
Объект, методы и свойства которого позволяют обращаться к диску, получать о нем различную информацию
|
Folders
|
Набор всех подпапок в каталоге
|
Folder
|
Объект, методы которого используются для создания, перемещения, переименования и удаления папок, а свойства – для получения имен папок, путей и т.д.
|
Files
|
Набор всех файлов в папке
|
File
|
Объект, методы которого используются для создания, перемещения, переименования и удаления файлов, а свойства – для получения имен файлов и путей
|
FileSystemObject
|
Главный объект объектной модели. Поддерживает все методы и свойства для доступа к файловой системе
|
TextStream
|
Методы этого объекта позволяют осуществлять различные манипуляции с текстовыми файлами
|
Для получения доступа к объектам FSO необходимо создать переменную-объект и присвоить ей ссылку на объект FileSystemObject:
Set fso=WScript.CreateObject(“Scripting.FileSystemObject”)
После создания объекта становятся доступны его методы, свойства и дочерние объекты. Поскольку в данной статье будут рассмотрены вопросы, касающиеся операций с файлами и папками, то некоторые объекты и наборы, такие как Drive(s) и TextStream, не будут рассмотрены.
Программное получение доступа к папкам
С помощью набора Folders осуществляется формирование списка вложенных файлов и папок в указанном каталоге; просмотр атрибутов каталога; создание, перемещение, переименование и удаление папок.
Доступ к набору Folders можно получить, воспользовавшись следующим шаблоном:
path="…"
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
Set oFolders=fso.GetFolder(path)
где path – путь к каталогу, например, «C:FolderName» или «ServerShareName».
В качестве обработчика ошибок рекомендуется использовать функцию FolderExists(), с помощью которой можно определить существует ли каталог, по указанному пути:
path="…"
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
If fso.FolderExists(path) then
Set oFolders=fso.GetFolder(path)
…
Else
MsgBox "Folder " + path + " Not Exists"
End If
Определение списка подпапок в указанной директории
Формирование списка осуществляется с помощью свойства Name набора SubFolders и Files. С помощью набора SubFolders определяется список папок, вложенных в указанный каталог, а с помощью Files – соответственно список файлов. Приведем пример, в котором будет определены подпапки каталога Windows:
path="C:\Windows"
Temp=""
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
If fso.FolderExists(path) then
Set oFolders=fso.GetFolder(path)
Set OSubFolders=oFolders.Subfolders
For each i In OSubFolders
Temp=Temp+i.Name+chr(13)
Next
Else
Temp= "Folder " + path + " Not Exists"
End If
MsgBox Temp
Определение списка всех вложенных подпапок в каталоге
Для чтения всей структуры подкаталогов необходимо вышеописанный механизм поместить в функцию и сделать ее рекурсивной[1]. Функция будет иметь два параметра – путь к абсолютному подкаталогу (PATH) и уровень вложенности подкаталогов (IDX).
Данные, содержащие абсолютные пути к подкаталогам, разумно записывать в динамический одномерный массив. Приведем пример создания и заполнения элементов динамического массива на примере чтения структуры подкаталогов, затем приведем шаблон рекурсивной функции.
Path="C:\RootFolder"
i=0
Dim Array() 'Объявление динамического массива
Set fso=Wscript.CreateObject("Scripting.FileSystemObject")
Set oFolder=fso.GetFolder(path)
Set oFolders=oFolder.SubFolders
' Изменение размера динамического массива
Redim Preserve Array(oFolders.count)
For Each of In oFolders
Array(i)=cstr(oF.Path) ' Запись элементов в массив
i=i+1
Next
'Чтение элементов массива:
Temp=""
For i=Lbound(Array) to Ubound(Array)
Temp=Temp+cstr(Array(i))+chr(13)+chr(10)
Next
MsgBox Temp
Шаблон рекурсивной функции:
………..
' Вызов функции RecFolder в теле сценария
RecFolder index, path
………..
Function Recfolder (idx, path)
………..
………..
………..
Call Recfolder (idx+1, path)
………..
End Function
На основе изложенного материала приведем листинг скрипта, который позволяет определить названия всех подпапок, вложенных в указанный каталог (в примере – переменная path):
dim path_array()
path="c:\windows"
i=0
temp=""
detect(q)
MsgBox "oFolders_count: "+cstr(detect(q))
For j=0 to cstr(ubound(path_array)-1)
path=cstr(path_array(j))
temp=temp+cstr(j)+": "+path+chr(13)
Next
MsgBox temp
Function detect(c)
i=0
Set fso=Wscript.CreateObject("Scripting.FileSystemObject")
Set oFolder=fso.GetFolder(path)
Set oFolders=oFolder.SubFolders
Redim Preserve path_array(oFolders.count)
detect=oFolders.count
For Each oF In oFolders
path_array(i)=path+"\"+cstr(oF.Name)
i=i+1
Next
End Function
Определение списка файлов, находящихся в директории
Методика определения списка файлов, содержащихся в директории, та же, что и в случае определения списка подкаталогов. Разница заключается в том, что вызывается набор Files, а не SubFolder:
path="c:\windows"
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso=createobject("Scripting.filesystemobject")
Set oFolder=fso.GetFolder(path)
Set oFiles=oFolder.files
MsgBox "oFiles_count: "+cstr(oFiles.count)
temp=""
For each oFile in oFiles
temp=temp & oFile.name & chr(13)
Next
MsgBox text
Управление атрибутами файлов
Каждый файл имеет набор параметров, которые его характеризуют – название, расширение, размер, даты создания и последнего изменения файла, его атрибуты. О том, как считывать названия файлов и их расширения, было рассказано ранее. Пришло время рассказать о методике чтения дат и атрибутов файлов.
Определение атрибутов файлов
Получив доступ к файлам, как это показано в предыдущем разделе, с помощью свойства Attributes можно определить атрибуты файлов.
Свойство Attributes возвращает двоичное значение, расшифровка которых приведена в таблице:
Таблица 2
Константа
|
Значение
|
Описание
|
Normal
|
0
|
Файл без установленных атрибутов
|
ReadOnly
|
1
|
Файл с атрибутом «только для чтения»
|
Hidden
|
2
|
Скрытый файл
|
System
|
4
|
Системный файл
|
Directory
|
16
|
Папка
|
Archive
|
32
|
Файл с атрибутом «архивный», модифицированный со времени последнего резервного копирования
|
Alias
|
1024
|
Ярлык (файл с расширением LNK)
|
Compressed
|
2048
|
Сжатый файл (только для Windows 2k)
|
Приведем пример чтения атрибута файла boot.ini:
path="c:\boot.ini"
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso=createobject("Scripting.filesystemobject")
Set oFile=fso.GetFile(path)
MsgBox oFile.Name&": "& oFile.Attributes
Если атрибуты этого файла никто не изменял, то значение свойства oFile.Attributes будет равно 39, что в соответствии с таблицей обозначает, что boot.ini имеет следующие атрибуты: только для чтения, скрытый, системный, архивный.
Для того чтобы пользователь каждый раз не занимался определением атрибутов файлов, необходимо использовать функцию, с помощью которой будет осуществляться сопоставление кода, возвращаемого функцией атрибутам. Также необходимо осуществлять проверку на существование файла с помощью функции FileExists():
path="c:\boot.ini"
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso=createobject("Scripting.filesystemobject")
if fso.FileExists(path) then
Set oFile=fso.GetFile(path)
Attr_value=oFile.Attributes
temp=A_detect()
MsgBox oFile.Name&": "& temp
else
MggBox "Файл " &path& " не существует"
end if
function A_detect()
t=""
if (Attr_value and &H01)> 0 Then t=t+"Только для чтения; "
if (Attr_value and &H02)> 0 Then t=t+"Скрытый; "
if (Attr_value and &H04)> 0 Then t=t+"Системный; "
if (Attr_value and &H20)> 0 Then t=t+"Архивный; "
if (Attr_value and &H800)> 0 Then t=t+"Сжатый; "
A_detect=t
end function
Изменение атрибутов файлов
Изменение атрибутов файлов с помощью FSO осуществляется присвоением другого значения переменной oFile.Name. Значение может быть присвоено как в шестнадцатеричном, так и в десятеричном виде в (см. таблицу 2):
path="c:\readme.txt"
Set WSHShell = WScript.CreateObject("WScript.Shell")
Set fso=createobject("Scripting.filesystemobject")
Set oFile=fso.GetFile(path)
MsgBox oFile.Name&": "& oFile.Attributes
oFile.Attributes=39
MsgBox oFile.Name&": "& oFile.Attributes
По умолчанию вновь созданный файл readme.txt имеет атрибут «Архивный»(32). Присвоив параметру oFile.Attributes значение 39, файлу будут назначены следующие атрибуты: только чтение, скрытый, системный, архивный.
Операции над файлами и папками
Над файлами и папками можно производить следующие операции: создание, копирование, перемещение, удаление. Сначала опишем операции, выполняемые с папками, затем файлами.
Создание и удаление папок
Создание и удаление каталогов осуществляется с помощью методов CreateFolder(path) и DeleteFolder(path) объекта FSO. Параметром каждого из этих методов является путь к каталогу – path. Используя эти методы, желательно включать в листинг скрипта обработчик ошибок, который проверяет наличие или отсутствие папки перед осуществлением каких-либо манипуляций с ней. Приведем два примера: первым из них проиллюстрируем процесс создания новой папки C:TempFolder; во втором – процесс удаления этой папки.
path="C:\TempFolder"
Temp=""
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
If fso.FolderExists(path)=0 then
fso.CreateFolder(path)
Temp= "Folder " + path + " Created "
Else
Temp= "Folder " + path + " Already Exists"
End If
MsgBox Temp
Удаление папки:
path="C:\TempFolder"
Temp=""
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
If fso.FolderExists(path)<>0 then
fso.DeleteFolder(path)
Temp= "Folder " + path + " Deleted"
Else
Temp= "Folder " + path + " is Absent "
End If
MsgBox Temp
Переименование, копирование и перемещение папок
Копирование папок осуществляется с помощью метода CopyFolder source, destination, overwrite, перемещение и переименование – с помощью MoveFolder source, destination, overwrite. Каждый их этих методов имеет три параметра:
Source – обязательный параметр, в котором передается строка с именем исходной папки (путем); путь может включать знаки подстановки, такие как «?» или «*». Рекомендуется использовать знаки подстановки для копирования или перемещения нескольких папок, одновременно удовлетворяющих заданному шаблону
Destination – обязательный параметр, задающий путь к папке назначения в виде строки. Значение этого параметра не может содержать символов подстановки. В том случае если путь заканчивается «» и папка-приемник не существует, то она будет создана.
Overwrite – необязательный параметр, который принимает значение False(0) или True(1). Если он равен True, т.е. 1 (по умолчанию), то целевая папка будет перезаписана.
Обратите внимание на то, что параметры указываются без скобок. Приведем примеры копирования и перемещения папок. Копирование папки:
OldPath="C:\TempFolderOld"
NewPath="C:\TempFolderNew"
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
fso.CopyFolder OldPath, NewPath, 1
MsgBox "Папка " + OldPath + " скопирована в " + NewPath
Удаление папки:
OldPath="C:\TempFolderOld"
NewPath="C:\TempFolderNew"
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
fso.MoveFolder OldPath, NewPath, 1
MsgBox "Папка " + OldPath + " перемещена в " + NewPath
Копирование и перемещение файлов
Копирование и перемещение файлов осуществляются с помощью методов Copy и Move соответственно. Поскольку использование этих методов одинаково, то они будут рассмотрены совместно. Шаблон вызова любого метода следующий:
PathOld="C:\Folder\FileNameOld"
PathNew="C:\Folder\FileNameNew"
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
If (fso.FileExistes(PathOld)) Then
Set oFile=fso.GetFile(PathOld)
oFile.**** PathNew
End If
где вместо «****» указывается название метода. Различие в использовании методов заключается в том, что при вызове метода Move после копирования файла осуществляется удаление первоисточника.
Приведем пример копирования файла:
PathOld="C:\Folder\1.txt"
PathNew="C:\Folder\2.txt"
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
If (fso.FileExistes(PathOld)) Then
Set oFile=fso.GetFile(PathOld)
oFile.Copy PathNew
End If
Удаление файлов
Удаление файла осуществляется с помощью метода Delete, вызываемого аналогичным способом. Отличается лишь синтаксис самого метода: у метода Delete, в отличие от Copy или Move, отсутствуют параметры:
PathDel="C:\Folder\1.txt"
Set fso=WScript.CreateObject("Scripting.FileSystemObject")
If (fso.FileExistes(PathDel)) Then
Set oFile=fso.GetFile(PathDel)
oFile.Delete
End If
Управление правами доступа на файлы и папки
Создавая новую папку или файл на жестком диске с файловой системой NTFS, новому объекту присваиваются права доступа по определенным правилам. Если разговор идет о создании общих папок на сервере, то системного администратора, как правило, не устроят права доступа, назначаемые по умолчанию: они должны быть изменены в соответствии с определенными правилами, описываемыми шаблоном. О том, как программно изменить права доступа на папки и файлы, и пойдет разговор в следующем разделе.
Библиотека ADsSequrity.dll
Программное управление правами доступа к файлам и папкам можно реализовать с помощью библиотеки ADs Sequrity.dll, входящей в комплект поставки ADSI Resource Kit (http://www.microsoft.com). Перед использованием библиотеки ее необходимо зарегистрировать на компьютере, на котором будет запускаться сценарий.
Команда регистрации библиотеки выглядит следующим образом:
regsvr32.exe /s ADsSequrity.dll
Доступ к вышеуказанной библиотеке осуществляется с помощью функции CreateObject(«ADsSecurity») по следующему сценарию:
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\folder")
Set dacl = sd.DiscretionaryAcl
For Each ace In dacl
Wscript.Echo cstr(ace.Trustee)+" " + cstr(ace.AccessMask) + " " + cstr(ace.AceType) + chr(13)+chr(10)
Next
Wscript.Echo dacl.AceCount
Как видно из примера, для управления правами необходимо создать новый экземпляр объекта ADsSecurity и указать к нему путь, который является параметром функции GetSecurityDescriptor(). Таким образом, можно получить доступ к коллекции DiscretionaryAcl, членами которой являются Trustee, AccessMask, AceType, AceCount и не фигурирующий в данном шаблоне RemoveAcl:
Таблица 3
Параметр
|
Описание
|
Параметр
|
Описание
|
Trustee
|
Пользователь или группа, которым определяется уровень доступа
|
AceType
|
Определяет тип доступа (Allow, Deny, Audit)
|
AccessMask
|
Определяет уровень доступа к ресурсу (Full Control, Modify, Read, Execute и т.д.)
|
AceCount
|
Количество объектов, которым назначены права
|
RemoveAcl
|
Удаление существующего объекта (группы или пользователя)
|
|
|
После многочисленных экспериментов были установлены и сведены в таблицы значения различных параметров:
Параметр AccessMask (см. рис. 1):
Таблица 4
|
&h1
|
&h2
|
&h4
|
&h8
|
&h10
|
&h20
|
&h40
|
&h80
|
&h100
|
&h10000
|
&h20000
|
&h40000
|
&h80000
|
&h100000
|
&h10000000
|
&h20000000
|
&h40000000
|
&h80000000
|
Full Control
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
Traverse Folder/Execute Folder
|
|
|
|
|
|
+
|
|
|
|
|
|
|
|
+
|
|
+
|
|
|
List Folder/ReadData
|
+
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
Read Attributes
|
|
|
|
|
|
|
|
+
|
|
|
|
|
|
+
|
|
+
|
|
+
|
Read Extended Attributes
|
|
|
|
+
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
Create Files/Write Data
|
|
+
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
Create Folder/Append Data
|
|
|
+
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
Write Attributes
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
+
|
|
Write Extended Attributes
|
|
|
|
|
+
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
|
Delete Subfolders and Files
|
|
|
|
|
|
|
+
|
|
|
|
|
|
|
+
|
|
|
|
|
Delete
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
+
|
|
|
|
|
Read Permissions
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
+
|
+
|
+
|
+
|
+
|
Change Permissions
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
+
|
|
|
|
|
Take Ownership
|
|
|
|
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
Рисунок 1
Параметр AccessFlags (см. рис. 2):
Таблица 5
|
Inheritance
|
Not Inheritance
|
Parent Object
|
This folder only
|
&h0 (&h4)
|
&h10 (&h14)
|
This folder, subfolder and files (•)
|
&h3 (&h7)
|
&h13 (&h17)
|
This folder and subfolder
|
&h2 (&h6)
|
&h12 (&h16)
|
This folder and files
|
&h1 (&h5)
|
&h11 (&h15)
|
Subfolders and files only
|
&h0b (&h0f)
|
&h1b (&h1f)
|
Subfolder only
|
&h0a (&h0e)
|
&h1a (&h1e)
|
Files only
|
&h0d (&h9)
|
&h1d (&h19)
|
Nothing
|
&h0c(&h8)
|
&h1c(&h18)
|
Рисунок 2
Параметр AceType (см. рис. 1, 3):
Таблица 6
Type
|
Flag
|
Deny
|
&h1
|
Allow (Full Control)
|
&h0
|
Audit
|
&h2
|
Рисунок 3
Также приведем таблицу, в которой описан набор стандартных атрибутов (см. рис. 3):
Таблица 7
Установка атрибута
|
Фактические атрибуты
|
.AccessMask
|
.AceFlags
|
Full Control
|
Full Control
Modify
Read & Execute
List Folder Contents
Read
Write
|
&h10000000
|
&h3
|
Modify
|
Modify
Read & Execute
List Folder Contents
Read
Write
|
&h20,
&h10000,
&h80000000,
&h40000000
|
&h3
|
Read & Execute
|
Read & Execute
List Folder Contents
Read
|
&h20000000+&h80000000
|
&h2
|
List Folder Contents
|
List Folder Contents
|
&h20000000+&h80000000
|
&h3
|
Read
|
Read
|
&h80000000
|
&h3
|
Write
|
Write
|
&h2, &h4, &h10, &h100
|
&h3
|
Добавление новых объектов
В качестве новых объектов могут выступать пользователи или группы. Приведем пример добавления нового пользователя:
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\Folder")
Set dacl = sd.DiscretionaryAcl
Set ace = CreateObject("AccessControlEntry")
ace.Trustee = "Domain\Administrator"
ace.AccessMask = &h20000000
ace.AceType = &h0
ace.AceFlags = &h3
dacl.AddAce ace1
sd.DiscretionaryAcl = dacl
sec.SetSecurityDescriptor sd
set dacl=nothing
set sec=nothing
Если необходимо добавить сразу несколько новых объектов, то необходимо учесть некоторые нюансы, о которых скажем несколько слов после примера:
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\Folder")
Set dacl = sd.DiscretionaryAcl
Set ace1 = CreateObject("AccessControlEntry")
ace1.Trustee = "msk\corwin"
ace1.AccessMask = &h20000000
ace1.AceType = &h0
ace1.AceFlags = &h3
dacl.AddAce ace1
for i=0 to 10000000
next
Set ace2 = CreateObject("AccessControlEntry")
ace2.Trustee = "msk\sneretin"
ace2.AccessMask = &h20000000
ace2.AceType = &h0
ace2.AceFlags = &h3
dacl.AddAce ace2
sd.DiscretionaryAcl = dacl
sec.SetSecurityDescriptor sd
set dacl=nothing
set sec=nothing
Изучив пример, можно обнаружить две особенности:
- Для каждого нового добавляемого объекта необходимо создать свой собственный объект AccessControlEntry, при этом описание объекта GetSecurityDescriptor и ADsSecurity у них может быть общим.
- После добавления нового объекта должно пройти некоторое время (особенно если сценарий находится на одном сервере, a объект, права доступа на который необходимо изменить, на другом), прежде чем он станет доступен для последующих действий. Для этого необходимо сделать в сценарии паузу. Поскольку в VBScript не существует такой функции, то предлагается вставить пустой цикл For…Next, на выполнение которого требуется определенное время.
Удаление существующих объектов
Удаление существующих групп или пользователей осуществляется с помощью свойства RemoveAcl коллекции объектов DiscretionaryAcl.
Set sec = CreateObject("ADsSecurity")
Set sd = sec.GetSecurityDescriptor("FILE://c:\2")
Set dacl = sd.DiscretionaryAcl
For Each ace In dacl
If (ace.Trustee="EveryOne")
dacl.RemoveAce ace
end if
Next
sd.DiscretionaryAcl = dacl
set dacl=nothing
set sec=nothing
Рассмотрев основы управления NTFS, читатель может приступить к реализации более сложных задач.