Page 1 of 2 in the PowerShellShares category Next Page

Как вы знаете, я в своё время писал скрипты для управления сетевыми папками (Shares) и наконец-то решил оформить это всё в человеческий модуль PowerShell.

Данный модуль позволяет вытворять следующее:

  • Получать список сетевых папок на локальном и/или удалённых компьютерах;
  • Расшаривать новые папки;
  • Удалять сетевые папки (останавливать шаринг конкретной папки без удаления фактического содержимого);
  • Добавлять/устанавливать/удалять права доступа к сетевой папке.

Вот инструкции по установке:

ZIP архив содержит папку с файлами, которую нужно распаковать в одну из папок:

  1. %USERPROFILE%\Documents\WindowsPowerShell\Modules (модуль будет доступен только для текущего пользователя)
  2. %WINDIR%\System32\WindowsPowerShell\v1.0\Modules (модуль будет доступен для всех пользователей в системе)
  3. Если один из указанных путей не существует, его придётся создать вручную.

Убедитесь, что архив распакован правильно и вы должны получить примерно такой вывод в консоли:

PS C:\> Get-Module -ListAvailable ModuleType Name ExportedCommands ---------- ---- ---------------- Manifest ShareUtils {} PS C:\>

Если вы не получаете таких же результатов, значит вы что-то сделал не так. Убедитесь, что папка ShareUtils расположена в указанном пути: "%USERPROFILE%\Documents\WindowsPowerShell\Modules"

Импорт модуля в сессию:

PS C:\> Import-Module ShareUtils

Примечание: консоль должна быть запущена в elevated mode с правами локального администратора. Если модуль запущен с правами стандартного пользователя (или не в elevated mode), вы получите гневное сообщение и модуль работать не будет. Для просмотра доступных функций можно выполнить следующую команду: 

PS C:\> Get-Command -Module shareutils CommandType Name Definition ----------- ---- ---------- Filter Add-SharePermission ... Function Get-Share ... Function New-Share ... Filter Remove-Share ... Filter Remove-SharePermission ... Filter Set-Share ... Filter Set-SharePermission ... PS C:\>

Каждая функция имеет свой собственный хелп и для получения справки по конкретной функции достаточно набрать:

Get-Help <FunctionName>

И, собственно, ссылка на сам зип:

PowerShell |  ACL |  Shares |  WMI
Friday, October 29, 2010 12:41:12 PM (FLE Daylight Time, UTC+03:00)   Comments [7]    

 

По просьбе читателей, а так же с учётом востребованности (судя по сообщениям форумов и ньюсгрупп) я нашёл время переписать скрипт ShareUtils.ps1 с поддержкой работы с удалёнными машинами и попутно пофиксив недочёты, которые были найдены за время эксплуатации предыдущей версии скрипта. Предыдущая версия опубликована здесь: Управление безопасностью общих папок (сетевых шар) в PowerShell (часть 4)

Технический функционал изменился только возможностью работы с удалёнными компьютерами, но синтаксис был изменён (а так же удалены лишние функции) по аналогии с PrinterUtils и имеет примерно следующий вид:

  1. New-Share –Computer <Computer> –Name <Name> –Path <Path> –Description <Description>
    где Computer – имя или IP адрес компьютера, на котором необходимо расшарить папку. (не обязательный параметр). Если не указан, используется текущий компьютер.
    Name - сетевое имя для папки;
    Path - путь к физической папке;
    Description описание к сетевой папке. При наличии пробелов -  заключить в кавычки (не обязательный параметр);
  2. Remove-Share –Computer <Computer> –Name <Name> – отменяет расшаривание на папке. Сама папка не удаляется.
    где Computer – имя или IP адрес компьютера, на котором нужно отменить расшаривание папки. (не обязательный параметр). Если не указан, используется текущий компьютер.
    Name - сетевое имя папки;
  3. Get-Share –Computer <Computer> –Name <Name> – получает основные сведения и списки DACL Share Permissions с указанных или всех сетевых папок.
    где Computer – имя или IP адрес компьютера, с которого нужно получить сведения о сетевых папках. (не обязательный параметр). Если не указан, используется текущий компьютер.
    Name - имя сетевой папки (не обязательный параметр). Если не указан, то выбираются все сетевые папки с типом Disk Drive (в которые системные шары не входят).
  4. Set-SharePermission –User <User> –AceType <AceType> –AccessMask <AccessMask> – устанавливает единственный Share Permission ACE для указанного в аргументах пользователя.
    User - имя пользователя/группы, которой предоставляется доступ;
    AceType - тип доступа. Этот параметр должен иметь одно из значений Allow/Deny;
    AccessMask - маска доступа. Этот параметр должен иметь одно из значений FullControl/Change/Read;

    Функция не может быть вначале строки, а только после конвейера Get-Share или другого источника с подходящими данными (например, если данные были сохранены в CSV/XML файле, то их можно использовать в качестве источника: Import-Csv path.csv | Set-SharePermission Everyone Allow Change). При этом все текущие права на сетевую папку будут удалены и записан только указанный в аргументах пользователь/группа.
  5. Add-SharePermission –User <User> –AceType <AceType> –AccessMask <AccessMask> – добавляет указанного в аргументах пользователя к Share Permissions выбранной сетевой папки (или папок)
    User - имя пользователя/группы, которой предоставляется доступ;
    AceType - тип доступа. Этот параметр должен иметь одно из значений Allow/Deny;
    AccessMask - маска доступа. Этот параметр должен иметь одно из значений FullControl/Change/Read;

    Функция не может быть вначале строки, а только после конвейера Get-Share или другого источника с подходящими данными (например, если данные были сохранены в CSV/XML файле, то их можно использовать в качестве источника: Import-Csv path.csv | Add-SharePermission Everyone Allow Change).
  6. Remove-SharePermission –User <User> – удаляет указанного пользователя из DACL выбранной сетевой папки (папок). Не может быть вначале строки, а только на выходе конвейера, откуда поступают объекты сетевых папок. Например, Get-Share | Remove-SharePermission Everyone – удалит группу Everyone из всех SharePermissions всех расшаренных папок на локальном компьютере. Разрешения NTFS при этом не изменяются.
    где User - имя пользователя/группы, которого следует удалить из ACL сетевой папки.

Примеры использования практически идентичные, как и в PrinterUtils: http://www.sysadmins.lv/PermaLink,guid,22c0550d-0c46-44ca-97ce-2b0bccbb51de.aspx

И, собственно, сам код:

########################################################
# ShareUtils.ps1
# Version 0.9
#
# Functions for advanced share management
#
# Note:
# Previous version is published at my former blog:
# http://vpodans.spaces.live.com/blog/cns!BB1419A2CFC1E008!188.entry
#
# Vadims Podans (c) 2009
# http://www.sysadmins.lv/
########################################################

# внутренняя функция, которая преобразовывает числовой код возврата операции записи DACL
# в текстовое значение.
function _ShareUtils_Get-Code ($write) {
    switch ($write.ReturnValue) {
        "0" {"Success"}
        "2" {"Access Denied"}
        "8" {"Unknown Failure"}
        "9" {"Invalid Name"}
        "21" {"Invalid Parameter"}
        "22" {"Duplicate Share"}
        "23" {"Redirected Path"}
        "24" {"Unknown Device or Directory"}
        "25" {"Net Name Not Found"}
        default {"Unknown error $write.ReturnValue"}
    }
}

# функция для извлечения сведений и DACL с существующих сетевых папок.
# обязательна для использования функций Add-SharePermission и Set-SharePermission
# если компьютер не указан, то используется текущий. Если имя сетевой паки не указано,
# то возвращается список сведений и DACL всех сетевых папок на локальном или удалённом компьютере
function Get-Share ($computer = ".", $name) {
    if ($name) {
        $shares = gwmi Win32_Share -ComputerName $computer -Filter "name = '$name'"
    } else {
        $shares = gwmi Win32_Share -ComputerName $computer -Filter "type = 0"
    }
    $ShareInfo = @()
    foreach ($share in $shares) {
        $ShareSec = gwmi Win32_LogicalShareSecuritySetting -ComputerName $computer -filter "name='$($share.name)'"
        if ($shareSec) {
            $SD = $sharesec.GetSecurityDescriptor()
            $ShareInfo += $SD.Descriptor.DACL | % {
                $_ | select @{e={$share.ClassPath.Server};n='Computer'},
                @{e={$share.name};n='Name'},
                @{e={$share.Path};n='Path'},
                @{e={$share.Description};n='Description'},
                AccessMask,
                AceFlags,
                AceType,
                @{e={$_.trustee.Name};n='User'},
                @{e={$_.trustee.Domain};n='Domain'},
                @{e={$_.trustee.SIDString};n='SID'}
            }
        } else {
            Write-Warning "Specified share not exist or you may not have sufficient rights to access them!"
        }
    }
    $ShareInfo
}

# функция записи обновлённых сведений в сетевые папки. Не может быть первой в строке, а только после
# конвейера, откуда поступают данные для записи. Если папка не расшарена, то скрипт её расшарит
# автоматически и запишет необходимые сведения о сетевой папке.
function Set-Share {
    $ShareInfo = @($input)
    $ShareInfo | select -unique Computer, Name, Path, Description | % {
        $Computer = $_.Computer
        $name = $_.name
        $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance()
        $ace = ([WMIClass] "Win32_Ace").CreateInstance()
        $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()
        $sd.DACL = @()
        $ShareInfo | ? {$_.Computer -eq $Computer -and $_.name -eq $name} | % {
            $SID = new-object security.principal.securityidentifier($_.SID)
            [byte[]] $SIDArray = ,0 * $SID.BinaryLength
            $SID.GetBinaryForm($SIDArray,0)
            $Trustee.Name = $_.user
            $Trustee.SID = $SIDArray
            $ace.AccessMask = $_.AccessMask
            $ace.AceType = $_.AceType
            $ace.AceFlags = $_.AceFlags
            $ace.trustee = $Trustee
            $SD.DACL += $ace.psObject.baseobject
        }
# проверяется наличие расшаренной папки. Если папка есть, то в неё записывается только SecurityDescriptor
# в противном случае она расшаривается и в неё производится полная запись всех данных
        $share = gwmi Win32_Share -ComputerName $computer -Filter "name = '$name'"
        if ($share) {
            $inParams = $share.psbase.GetMethodParameters("SetShareInfo")
            $inParams.Access = $SD
            $write = $share.psbase.invokemethod("SetShareInfo", $inParams, $null)
            Write-Host "Setting DACL on current share: $name on server $computer" -ForegroundColor green
            _ShareUtils_Get-Code $Write
        } else {
            $shareobject = [wmiClass]"\\$computer\root\cimv2:win32_Share"
            $inParams = $shareobject.psbase.GetMethodParameters("Create")
            $inParams.name = $_.name
            $inParams.path = $_.path
            $inParams.Description = $_.Description
            $inParams.Type = 0
            $inParams.Access = $SD
            $write = $shareobject.psbase.invokemethod("Create", $inParams, $null)
            Write-Host "Processing current share: $name on server $computer" -ForegroundColor green
            _ShareUtils_Get-Code $Write
        }
    }
}

function _Create-SDObject ($user, $AceType, $AccessMask) {
    # преобразование текстового вида прав в числовые значения
    $masks = @{FullControl = 2032127; Change = 1245631; Read = 1179817}
    $types = @{Allow = 0; Deny = 1}
    # создание необходимых свойств для объекта. Для поддержки удалённого управления
    # было добавлено свойство Computer, которое будет принимать от Get-Share аналогичное
    # значение. Тем самым обеспечивается сквозная трансляция имени компьютера, где
    # находится сетевая папка, по конвейеру для последующей записи
    $AddInfo = New-Object System.Management.Automation.PSObject
    $AddInfo | Add-Member NoteProperty Computer  ([PSObject]$null)
    $AddInfo | Add-Member NoteProperty Name  ([PSObject]$null)
    $AddInfo | Add-Member NoteProperty Path  ([PSObject]$null)
    $AddInfo | Add-Member NoteProperty Description  ([PSObject]$null)
    $AddInfo | Add-Member NoteProperty AccessMask  ([uint32]$null)
    $AddInfo | Add-Member NoteProperty AceFlags  ([uint32]$null)
    $AddInfo | Add-Member NoteProperty AceType  ([uint32]$null)
    $AddInfo | Add-Member NoteProperty User  ([PSObject]$null)
    $AddInfo | Add-Member NoteProperty Domain  ([PSObject]$null)
    $AddInfo | Add-Member NoteProperty SID  ([PSObject]$null)
    # заполнение объекта данными, которые были указаны в качестве аргументов вызова функции и возврат
    # объекта в вызывающую функцию
    $AddInfo.Name = $name
    $AddInfo.User = $user
    $AddInfo.SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])
    $AddInfo.AccessMask = $masks.$AccessMask
    $AddInfo.AceType = $types.$AceType
    $AddInfo
}

function Set-SharePermission ($user, $AceType, $AccessMask) {
    # принимаются данные с конвейера
    $ShareInfo = @($input)
    $AddInfo = _Create-SDObject $user $AceType $AccessMask
    # в этом цикле перебираются по именам все имена расшаренных папок и для каждой из них
    # записывается указанный в аргументах пользователь с удалением текущих ACE из ACL шары
    # это видно по тому, что никакая часть $ShareInfo не передаётся по конвейеру на запись
    foreach ($share in ($ShareInfo | select -Unique Computer, Name)) {
        $AddInfo.Computer = $share.Computer
        $AddInfo.Name = $share.name
        $AddInfo.Description = $Share.Description
        $AddInfo | Set-Share
    }
}

# просто добавляет нового участника безопасности к текущему DACL расшаренной папки.
# NTFS Acl не изменяется.
function Add-SharePermission ($user, $AceType, $AccessMask) {
    $ShareInfo = @($input); $ShareInfoNew = @()
    $AddInfo = _Create-SDObject $user $AceType $AccessMask
    foreach ($Share in ($ShareInfo | select -Unique Computer, Name)) {
        $AddInfo.Name = $Share.name
        $AddInfo.Computer = $Share.Computer
        $AddInfo.Description = $Share.Description
        # вот этой строкой мы из списка всех сетевых папок итеративно перебираем каждую шару
        $ShareInfoNew = @($ShareInfo | ?{$_.name -eq $Share.name})
        # в хвост списка ACL каждой сетевой шары добавляем новый ACE
        $ShareInfoNew += $AddInfo
        # и подаём на запись
        $ShareInfoNew | Set-Share
    }
}

# основная функция для удаления единичного ACE из ACL сетевой папки. Процесс сводится к извлечению
# текущего списка (или списков) ACL и фильтрации ACE в этом списке по методу Not Equal. Всё, что не подпадает под
# это действие записываются обратно в переменную, а всё, что подпало (указанный пользователь) обратно
# в переменную $ShareInfo не записывается.
function Remove-SharePermission ($user) {
    $shares = @($input)
    # просто берём списки ACL, которые пришли по конвейеру и выкидываем оттуда все ACE,
    # в которых фигурирует указанный в аргументах пользователь/группа и записывем ACE обратно в ACL
    $shares | ? {$_.user -ne $user} | Set-Share
}

# основная функция для создания новых сетевых папок на локальном компьютере. Здесь я использую упрощённый
# вариант создания сетевой папки, но учитывая один большой нюанс я добавил одно действие. Суть проблемы
# изложена тут: http://vpodans.spaces.live.com/blog/cns!BB1419A2CFC1E008!170.entry# поэтому при создании новой сетевой папки я вручную создаю с нуля список ACL, который содержит
# только группу Everyone и с правом Allow Read.
function New-Share ($computer = $env:COMPUTERNAME, $name, $path, $Description) {
    $user = (new-object security.principal.securityidentifier "S-1-1-0").translate([security.principal.ntaccount])
    $AddInfo = _Create-SDObject $user.Value Allow Read
    $AddInfo.Computer = $computer
    $AddInfo.Path = $path
    $AddInfo.Description = $Description
    $AddInfo | Set-Share
}

# отменяет расшаривание сетевой папки. Сама же физическая папка не изменяется.
function Remove-Share ($computer = ".", $name) {
    $share = gwmi Win32_Share -ComputerName $computer -Filter "name = '$name'"
    if (!$share) {
        Write-Warning "Specified network share doesn't exist!"
    } else {
        $write = $share.delete()
        Write-Host "Deleting network share $name on computer $computer:"
        _ShareUtils_Get-Code $write
    }
}
PowerShell |  ACL |  Shares |  WMI
Wednesday, March 04, 2009 4:22:45 PM (FLE Standard Time, UTC+02:00)   Comments [0]    

 

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.

Примечание: существует обновлённый вариант этого поста с модернизированным скриптом: Управление безопасностью общих папок (сетевых шар) в PowerShell (часть 5)


Ну что ж, настало время подвести итоги по материалу управления сетевыми шарами и управлению доступа к ним. Как и обещал, я написал скрипт, который выполнен в виде функций при помощи которого можно действительно легко и просто управлять самими сетевыми папками и их безопасностью из PowerShell. Интеграция данного скрипта в профиль PowerShell позволяет использовать уже готовые функции как простые командлеты. Я считаю, это действительно большим плюсом, т.к. до этого администратору для решения этих задач приходилось писать длиннющий код в каждом скрипте, который касался безопасности сетевых шар. Итак, какой же функционал заложен в данный скрипт:

  1. создание сетевой папки;
  2. удаление сетевой папки;
  3. получения перечня всех сетевых папок на сервере с выводом необходимой информации о них;
  4. установка ACL сетевой папки;
  5. добавление ACE к существующему ACL сетевой папки;
  6. удаление единичных ACE изи ACL сетевой папки;
  7. просмотр текущих списков ACL сетевой папки;
  8. экспорт всех сведений (включая списки ACL) сетевых папок в CSV файл;
  9. импорт всех сведений (включая списки ACL) сетевых папок из CSV файла.

Касательно последнего пункта, то хочу отметить, что импорт при отсутствии наличия папки для расшаривания создаст папку и расшрарит с данными из CSV файла. Сначала я приведу список команд, которые доступны при использовании скрипта и их синтаксис:

  1. New-Share Name Path Description
    где Name - сетевое имя для папки;
    Path - путь к физической папке;
    Description описание к сетевой папке. При наличии пробелов -  заключить в кавычки (не обязательный параметр);
  2. Remove-Share Name
    где Name - сетевое имя папки;
  3. Get-Share Name
    где Name - имя сетевой папки (не обязательный параметр);
  4. Set-SharePermission Name User AccessMask AceType
    где Name - имя сетевой папки;
    User - имя пользователя/группы, которой предоставляется доступ;
    AccessMask - маска доступа. Этот параметр должен иметь одно из значений FullControl/Change/Read;
    AceType - тип доступа. Этот параметр должен иметь одно из значений Allow/Deny;
  5. Add-SharePermission Name User AccessMask AceType
    где Name - имя сетевой папки;
    User - имя пользователя/группы, которой предоставляется доступ;
    AccessMask - маска доступа. Этот параметр должен иметь одно из значений FullControl/Change/Read;
    AceType - тип доступа. Этот параметр должен иметь одно из значений Allow/Deny;
  6. Remove-SharePermission User
    где User - имя пользователя/группы, которого следует удалить из ACL сетевой папки;
  7. Get-SharePermission Name
    где Name - имя сетевой папки (не обязательный параметр);
  8. Export-ShareInfo Path
    где Path - путь к CSV файлу (включая имя файла). Если в пути присутствуют пробелы, то путь заключить в кавычки;
  9. Import-ShareInfo Path
    где Path - путь к CSV файлу (включая имя файла). Если в пути присутствуют пробелы, то путь заключить в кавычки.

Ну и собственно сам скрипт с некоторыми комментариями по работе самих функций. Для желающих подробно изучить скрипт я не делал особо комментариев, т.к. построение кода описано в предыдущих частях по управлению безопасностью сетевых папок. Ссылки на предыдущие части:

  1. Управление общими сетевыми ресурсами (шарами) в PowerShell
  2. Управление безопасностью общих папок (сетевых шар) в PowerShell (часть 1)
  3. Управление безопасностью общих папок (сетевых шар) в PowerShell (часть 2)
  4. Управление безопасностью общих папок (сетевых шар) в PowerShell (часть 3)
######################################################## 
# ShareUtils.ps1 
# Version 0.0.0.5 
# 
# Functions for advanced share management 
# 
# Vadims Podans (c) 2008 
# http://vpodans.spaces.live.com/ 
######################################################## 

Write-Host "Vadims Podans's ShareUtils are installed"


# внутренняя функция, которая преобразовывает числовой код возврата операции записи ACL 
# в текстовое значение. 
function _ShareUtils_Get-Code ($share) { 
    switch ($Share.ReturnValue) { 
        "0" {"Успешно"} 
        "2" {"Отказано в доступе"} 
        "8" {"Неизвестная ошибка"} 
        "9" {"Указано недопустимое имя шары"} 
        "21" {"Указан неправильный параметр"} 
        "22" {"Сетевая шара уже существует"} 
        "23" {"Путь перенаправлен"} 
        "24" {"Указан неверный путь"} 
        "25" {"Сетевое имя не найдено"} 
    } 
} 

# основная функция экспорта сведений о сетевых папках в CSV файл. 
function Export-ShareInfo ($path, $name) {
    # если переменная $name пустая, то функция вовзращает все сетевые папки с типом DiskDrive 
    if ($name -ne $null) {
        $shares = Get-WmiObject Win32_Share -filter "name = '$name'" 
    } Else {$shares = Get-WmiObject Win32_Share -filter 'type = 0'} 
    $Shareinfo = @() 
    # цикл извлечения сведений о каждой сетевой папке в переменную $ShareInfo 
    foreach ($share in $shares) {
        $ShareSec = Get-WmiObject Win32_LogicalShareSecuritySetting  -filter "name='$($share.name)'"
        if($shareSec) {
            $sd = $sharesec.GetSecurityDescriptor()
            $ShareInfo += $SD.Descriptor.DACL | % {
                $_ | select @{e={$share.name};n='Name'},
                @{e={$share.Path};n='Path'},
                @{e={$share.Description};n='Description'},
                AccessMask,
                AceFlags,
                AceType,
                @{e={$_.trustee.Name};n='User'},
                @{e={$_.trustee.Domain};n='Domain'},
                @{e={$_.trustee.SIDString};n='SID'}
            }
        }
    } 
    # если переменная $path не передана, то сведения о сетевых папках передаётся в вызывющую 
    # функцию для последующей обработки, в частности добавления и удаления ACE из ACL 
    # списка сетевой папки 
    if ($path -eq $null) {$shareinfo}
    else { 
        # собственно сам экспорт содержимого $ShareInfo в CSV файл 
        $ShareInfo | select Name, Path, Description, User, Domain, SID, AccessMask, AceFlags, AceType | export-csv -noType $path 
        # если указан путь к CSV файлу, то после экспорта данных в файл проверяется, что файл действительно был создан 
        if (Test-Path $path) {Write-Host "Выполнено!"}
        else {Write-Warning "Не удалось создать файл $path. Возможно у вас не хватает прав или путь недоступен."}
    }
} 

# внутренняя функция для записи уже сформированной переменной $ShareInfo в ACL сетевой папки 
function _ShareUtils_WriteShare ($ShareInfo, $shares, $param) {
    $ShareInfo | select -unique name, Path, Description | ForEach-Object {
        $name = $_.name
        $path = $_.Path
        $description = $_.Description
        $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance()
        $ace = ([WMIClass] "Win32_Ace").CreateInstance()
        $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance()
        $sd.DACL = @()
        $ShareInfo | where {$_.name -eq $name} | ForEach-Object {
            $SID = new-object security.principal.securityidentifier($_.SID)
            [byte[]] $SIDArray = ,0 * $SID.BinaryLength
            $SID.GetBinaryForm($SIDArray,0)
            $Trustee.Name = $_.user
            $Trustee.SID = $SIDArray
            $ace.AccessMask = $_.AccessMask
            $ace.AceType = $_.AceType
            $ace.AceFlags = $_.AceFlags
            $ace.trustee = $Trustee
            $sd.DACL += $ACE.psObject.baseobject
        }
        # здесь проверяется наличие промежуточного параметра $param, который после сборки определяет 
        # тип записи. Если $param пустой, то производится запись только в конкретную сетевую папку. Если 
        # же $param не пустой, то при записи и отсутствии сетевой папки она будет создана и в неё будут записаны 
        # данные из CSV файла. Конструкция после Else используется только при импорте данных о сетевых папках 
        # включая Access из заранее подготовленного CSV файла. 
        if ($param -eq $null) {
            $inParams = $shares.psbase.GetMethodParameters("SetShareInfo") 
            $inParams.Access = $SD 
            $write = $shares.psbase.invokemethod("setshareinfo", $inParams, $null) 
            Write-Host "Запись DACL сетевой папки:"
        _ShareUtils_Get-Code $write
        } else {
            $shares = ([WMIClass] "Win32_Share") 
            $inParams = $shares.psbase.GetMethodParameters("Create") 
            $inParams["Name"] = $_.name 
            $inParams["Type"] = 0 
            $inParams["Path"] = $_.Path 
            $inParams["Description"] = $_.Description 
            $inParams["Access"] = $SD.PsObject.BaseObject 
            $write = $shares.psbase.invokemethod("Create", $inParams, $null) 
            Write-Host "Обработка сетевой папки $name по пути $path:" 
            _ShareUtils_Get-Code $write 
        }
    }
} 

# основная функция для импорта данных о сетевых папках из CSV файла. Переменная $path 
# должна содержать путь к CSV файлу. Внутри функции проверяется, чтобы был указан 
# верный путь к CSV файлу. 
function Import-ShareInfo ($path) {
    if (Test-Path $path) {
        $param = "param" 
        $ShareInfo = Import-Csv $path 
        _ShareUtils_WriteShare $ShareInfo -param $param
    } else {Write-Warning "путь к CSV файлу указан неверный!"}
} 

# основная функция для компоновки объекта $AddInfo параметрами безопасности, которые 
# включают в себя как имя сетевой папки, имени пользователя, который должен иметь к ней 
# доступ, и типах доступа, как чтение/запись и действие разрешено/запрещено. Переменная 
# $param определяет действие с готовым объектом - отправить на запись сразу (при этом все 
# существующие разрешения будут удалены и заменены только данными из текущего объекта) 
# или вернуть обратно в вызывющую функцию, для присоединения этого объекта к уже имеющимся, 
# для окончательной компоновки объекта с полным списком ACL. 
function Set-SharePermission ($name, $user, $AceType, $AccessMask, $param) {
    $shares = gwmi Win32_share -Filter "name = '$name'"
    if ($shares -eq $null) {Write-Warning "Указанная сетевая шара не найдена"}
    else {
        # здесь я использовал хэш-таблицы для преобразования текстовых значений маски и типа
        # доступа, которые вводит пользователь в числовые значения, которые затем транслируются и
        # и помещаются в текущий объект с параметрами безопасности.
        $masks = @{FullControl = 2032127; Change = 1245631; Read = 1179817}
        $types = @{Allow = 0; Deny = 1}
        $AddInfo = New-Object System.Management.Automation.PSObject
        # здесь происходит инициализация свойств объекта. Значение каждого параметра приравнял к $null
        # для того, чтобы при отсутствии каких-либо данных они либо оставались пустыми, либо заполнялись
        # системой автоматически.
        $AddInfo | Add-Member NoteProperty Name  ([PSObject]$null)
        $AddInfo | Add-Member NoteProperty Path  ([PSObject]$null)
        $AddInfo | Add-Member NoteProperty Description  ([PSObject]$null)
        $AddInfo | Add-Member NoteProperty AccessMask  ([uint32]$null)
        $AddInfo | Add-Member NoteProperty AceFlags  ([uint32]$null)
        $AddInfo | Add-Member NoteProperty AceType  ([uint32]$null)
        $AddInfo | Add-Member NoteProperty User  ([PSObject]$null)
        $AddInfo | Add-Member NoteProperty Domain  ([PSObject]$null)
        $AddInfo | Add-Member NoteProperty SID  ([PSObject]$null)
        # собственно заполнение свойств созданного объекта данными, которые были переданы из вызывющей 
        # функции.
        $AddInfo.Name = $name
        $AddInfo.Path = $shares.Path
        $AddInfo.Description = $Shares.Description
        $AddInfo.User = $user
        $AddInfo.SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])
        $AddInfo.AccessMask = $masks.$AccessMask
        $AddInfo.AceType = $types.$AceType
        # тут так же использовалась временная переменная $param, которая определяет дальнейшее действие
        # с данным объектом - отправка объекта на запись (только при использовании функции Set-SharePermission),
        # либо возврат в вызываемую функцию (только при использовании функции Add-SharePermission).
        if ($param -ne $null) {
        $AddInfo} else {
            _ShareUtils_WriteShare $AddInfo $shares
        }
    }
}

# основная функция для добавления участников безопасности к имеющимуся списку ACL. Данная функция 
# сперва использует функцию экспорта для извлечения сведений об указанной сетевой папке, после чего 
# вызывается функция Set-SharePermission в качестве промежуточной функции, т.к. в неё передаётся перменная 
# $param, то вызываемая функция не будет записывать новый ACL, а вернёт скомпонованный объект $AddInfo. 
function Add-SharePermission ($name, $user, $AceType, $AccessMask) {
    $shares = gwmi Win32_share -Filter "name = '$name'"
    if ($shares -eq $null) {Write-Warning "Указанная сетевая шара не найдена"}
    else {
        # здесь нужно быть внимательным, т.к. нужно обязательно использовать обозначение массива @() для того,
        # чтобы переменная $ShareInfo смогла бы содержать массив объектов с параметрами безопасности. Один объект
        # содержит один ACE для каждого пользователя/группы. Если не использовать обозначение массива, то данная
        # переменная сможет содержать только один объект (т.е. только одного участника безопасности).
        $ShareInfo = @(Export-ShareInfo -name $name)
        $param = "param"
        $ShareInfoNew = Set-SharePermission $name $user $AceType $AccessMask $param
        # вот здесь происходит присоединение с нуля созданного объекта (ACE) к имеющемуся массиву текущих
        # ACE. Таким образом мы можем добавлять участников безопасности к ACL сетевой папки без удаления
        # текущих ACE.
        $ShareInfo += $ShareInfoNew
        _ShareUtils_WriteShare $ShareInfo $shares
    }
}

# основная функция для удаления единичного ACE из ACL сетевой папки. Процесс сводится к извлечению 
# текущего списка ACL и фильтрации ACE в этом списке по методу Not Equal. Всё, что не подпадает под 
# это действие записываются обратно в переменную, а всё, что подпало (указанный пользователь) обратно 
# в переменную $ShareInfo не записывается. 
function Remove-SharePermission ($name, $user) { 
    $shares = gwmi Win32_share -Filter "name = '$name'" 
    if ($shares -eq $null) {Write-Warning "Указанная сетевая шара не найдена"} 
    else {
        $ShareInfo = Export-ShareInfo -name $name 
        $ShareInfo = $shareInfo | where {$_.name -eq "$name" -and $_.user -ne "$user"} 
        _ShareUtils_WriteShare $ShareInfo $shares
    }
} 

# основная функция для создания новых сетевых папок на локальном компьютере. Здесь я использую упрощённый 
# вариант создания сетевой папки, но учитывая один большой нюанс я добавил одно действие. Суть проблемы 
# изложена тут: http://vpodans.spaces.live.com/blog/cns!BB1419A2CFC1E008!170.entry 
# поэтому при создании новой сетевой папки я вручную создаю с нуля список ACL, который содержит 
# только группу Everyone и с правом Allow Read. 
function New-Share ($name, $path, $Description) { 
    $Share = ([wmiClass] 'Win32_share').Create($path, $name, 0, $null, $Description) 
    Write-Host "Создание сетевой шары $name :" 
    $Return = _ShareUtils_Get-Code $share 
    $Return 
    if ($Return -eq "Успешно") { 
        # для использования скрипта в мультиязычных системах без лишних правок в скрипте я вместо именования 
        # группы Everyone я использовал трансляцию её уникального для всех систем SID в строковое значение, 
        # которое может отличаться в зависимости от языка системы. 
        $user = (new-object security.principal.securityidentifier "S-1-1-0").translate([security.principal.ntaccount]) 
        Set-SharePermission $name $user.value "Allow" "Read"
    } 
} 

# основная функция для удаления сетевой шары (равносильно Stop Sharing в консоли Shares). Сама папка 
# и её содержимое не удаляется. 
function Remove-Share ($name) { 
    $share = gwmi Win32_share -Filter "name = '$name'" 
    if ($share -eq $null) {Write-Warning "Указанная сетевая шара не найдена"} else { 
        $share.delete($null) 
        Write-Host "Удаление сетевой шары $name :" 
        _ShareUtils_Get-Code $share
    }
} 

# функция, которая возвращает на экран пользователю список всех сетевых папок на локальном компьютере. 
# можно так же получить сведения только об одной сетевой папке, которую нужно указать при вызове. 
function Get-Share ($name) { 
    if ($name -eq $null) {gwmi Win32_Share -Filter 'type = 0'}    else {gwmi Win32_Share -Filter "name='$name'"} 
} 

# основная функция для вывода на экран сведений о безопасности (содержимого списка ACL) как для всех 
# сетевых папок (если вызывается функция без параметров), так и для конкретной сетевой папки. Т.к. маски и типы 
# доступа приводятся в числовых значениях после вывода сведений выводится краткая справка по трансляции 
# данных значений. Считаю, что нету смысла писать транслятор, который перед выводом информации на экран 
# данных сам автоматически переводил бы в понятные текстовые значения. 
function Get-SharePermission ($name) { 
    Export-ShareInfo -name $name | select name, user, AccessMask, AceType | ft -a -group name 
    Write-Host "Данные колонки AccessMask имеют следующие значения: 
    2032127 - FullControl 
    1245631 - Change 
    1179817 - Read `n 
    Данные колонки AceType имеют следующие значения: 
    0 - Allow 
    1 - Deny 
    2- SystemAudit (группы Administrators и System имеют право Allow FullControl" -foregroundcolor "Yellow"
}

Вот так это всё выглядит. На первый взгляд много и страшно, но если прочитать все предыдушие статьи по данной теме, то данный код уже будет обретать некий смысл. На этом я предлагаю поставить жирную точку в вопросе управления сетевыми папками и безопасностью (Share Permissions) сетевых папок в PowerShell.

И на последок добавлю, что принимаются любые замечания, поправки предложения по данному скрипту, т.к. это лишь мой первый пробный многофункциональный скрипт по ACL и что-то может быть упущено или неоптимизировано. Вобщем, если есть что сказать, то отписывайтесь в комментариях.

PowerShell |  ACL |  Shares |  WMI
Wednesday, July 16, 2008 2:26:00 PM (FLE Daylight Time, UTC+03:00)   Comments [0]    

 

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.


В предыдущей части мы рассмотрели чтение Share Permissions, их редактирование и удаление ACE из полного списка ACL. Здесь осталось рассмотреть вопрос добавления участников безопасности в DACL сетевой шары. Этот процесс, к сожалению, не такой и простой, как может показаться, но тем не менее его тоже нужно решать. Для решения этой задачи нам нужно создать такой же объект с такими же свойствами как и содержимое $ShareInfo. Давайте посмотрим, какими свойствами обладают элементы массива $ShareInfo:

[C:\] $Shareinfo[0] | gm TypeName: Selected.System.Management.ManagementBaseObject Name MemberType Definition ---- ---------- ---------- Equals Method bool Equals(System.Object obj) GetHashCode Method int GetHashCode() GetType Method type GetType() ToString Method string ToString() AccessMask NoteProperty System.Int32 AccessMask=1179817 AceFlags NoteProperty System.UInt32 AceFlags=0 AceType NoteProperty System.UInt32 AceType=0 Description NoteProperty System.String Description= Domain NoteProperty System.String Domain=CONTOSO Name NoteProperty System.String Name=UserShare Path NoteProperty System.String Path=C:\Test SID NoteProperty System.String SID=S-1-5-21-3709200118-438321133-4282490648-513 User NoteProperty System.String User=Domain Users

Нас тут будут интересовать только NoteProperty. Давайте теперь исходя из этих данных создадим свой объект, который будет обладать вот этими свойствами. Тип объекта будет такой же - System.Management.Automation.PSObject  (без Custom). Новый объект создаётся командной New-Object, а члены объекта создаются командой Add-Member:

# создаём новый объект с типом System.Management.Automation.PSObject 
$AddInfo = new-object System.Management.Automation.PSObject 
# добавляем по очереди членов NoteProperty объекта как и в исходном варианте 
$AddInfo | add-member NoteProperty Name  ([PSObject]$null) 
$AddInfo | add-member NoteProperty Path  ([PSObject]$null) 
$AddInfo | add-member NoteProperty Description  ([PSObject]$null) 
$AddInfo | add-member NoteProperty AccessMask  ([uint32]$null) 
$AddInfo | add-member NoteProperty AceFlags  ([uint32]$null) 
$AddInfo | add-member NoteProperty AceType  ([uint32]$null) 
$AddInfo | add-member NoteProperty User  ([PSObject]$null) 
$AddInfo | add-member NoteProperty Domain  ([PSObject]$null) 
$AddInfo | add-member NoteProperty SID  ([PSObject]$null)

Теперь можно посмотреть на результаты нашей работы:

[C:\] $AddInfo Name : Path : Description : AccessMask : 0 AceFlags : 0 AceType : 0 User : Domain : SID :

Ну что ж, уже лучше, теперь можно заполнять эти поля в соответствии с нашими требованиями. Но чтобы не заполнять все поля вручную, предполагается, что для добавления нового участника безопасности в Share Permissions пользователь укажет только имя сетевой шары, имя пользователя, маску доступа и тип доступа (Allow/Deny). Поэтому нам потребуется вытащить информацию о текущей шаре (которая общая для всей шары, как имя, путь, описание и т.д.) и передать эти значения в новую переменную $AddInfo. Остальную часть информации мы обработаем на основании уже переданных параметров и запишем оставшиеся поля переменной $AddInfo, которая в конечном итоге будет содержать всю необходимую информацию. Т.к. уже неоднократно говорилось в предыдущих частях, что метод SetShareInfo перезаписывает полностью информацию о сетевой шаре, поэтому для сохранения существующих ACE мы произведём уже известным способом чтение существующих DACL и сделаем инкремент (добавим к существующим DACL нами созданный DACL). Когда все данные будут скомпонованы мы произведём запись обновлённого списка DACL в ACL шары. Итак, поехали:

# принимаем вводные параметры от пользователя из командной строки 
param ($share, $user, $AccessMask, $AceType) 
# предполагается, что данный скрипт выполняет только добавление участников безопасности 
# поэтому сразу создаём новый объект с необходимыми членами и указанием типа принимаемых 
# данных 
$AddInfo = New-Object System.Management.Automation.PSObject 
$AddInfo | Add-Member NoteProperty Name  ([PSObject]) 
$AddInfo | Add-Member NoteProperty Path  ([PSObject]) 
$AddInfo | Add-Member NoteProperty Description  ([PSObject]) 
$AddInfo | Add-Member NoteProperty AccessMask  ([uint32]) 
$AddInfo | Add-Member NoteProperty AceFlags  ([uint32]) 
$AddInfo | Add-Member NoteProperty AceType  ([uint32]) 
$AddInfo | Add-Member NoteProperty User  ([PSObject]) 
$AddInfo | Add-Member NoteProperty Domain  ([PSObject]) 
$AddInfo | Add-Member NoteProperty SID  ([PSObject]) 
# зная имя сетевой шары делаем её поиск и копируем информацию о имени, пути 
# и описании (поле Description) и выставим прочие параметры 
$CustomShare = Get-WmiObject Win32_Share -filter "name = '$share'" 
$AddInfo.Name = $share 
$AddInfo.Path = $CustomShare.Path 
$AddInfo.Description = $CustomShare.Description 
$AddInfo.Domain = $null 
$AddInfo.AceFlags = 3 
# далее заполняется информация о пользователе и его доступе, поэтому 
# дальше мы ничего не копируем, а обрабатываем уже переданные параметры: 
$AddInfo.User = $user 
# преобразовываем маску доступа из текстовой в численный формат с использованием 
# конструкции Switch.
switch ($AccessMask) {
    "Full"   {$AddInfo.AccessMask = 2032127}
    "Change" {$AddInfo.AccessMask = 1245631}
    "Read"   {$AddInfo.AccessMask = 1179817}
} 
# таким же образом обрабатываем и переменную $AceType: 
switch ($AceType) {
    "Allow"   {$AddInfo.AceType = 0}
    "Deny" {$AddInfo.AceType = 1}
}
# заполняем последнее поле SID путём трансляции имени пользователя/группы в его SID
$AddInfo.SID = (new-object security.principal.ntaccount $user).translate([security.principal.securityidentifier])
# теперь считываем текущий список DACL с указанной сетевой шары в переменную $ShareInfo
$shares = Get-WmiObject Win32_Share -filter "name='$share'"
$Shareinfo = @()
foreach ($share in $shares) {
    $shareSec = Get-WmiObject Win32_LogicalShareSecuritySetting  -filter "name='$($share.name)'"
    if($shareSec) {
        $sd = $sharesec.GetSecurityDescriptor()
        $ShareInfo += $sd.Descriptor.DACL | ForEach-Object {
            $_ | select @{e={$share.name};n='Name'},
            @{e={$share.Path};n='Path'},
            @{e={$share.Description};n='Description'},
            AccessMask,
            AceFlags,
            AceType,
            @{e={$_.trustee.Name};n='User'},
            @{e={$_.trustee.Domain};n='Domain'},
            @{e={$_.trustee.SIDString};n='SID'}
        }
    }
}
# теперь делаем добавление (инкремент) созданного нами массива объектов с зполненными полями к 
# существующему массиву объектов $ShareInfo 
$ShareInfo += $AddInfo 
# Можно для верности убедиться, что $ShareInfo обладает всей необходимой информацией, которую 
# теперь можно записать в шару. В принципе, эта строчка несёт в себе лишь отладочную информацию 
# и когда отладка будет завершена эту строчку можно будет удалить или закомментировать для 
# отладки скрипта в будущем. 
$ShareInfo 
# Если всё в порядке, то можно перезаписывать эти данные в DACL указанной шары: 
$ShareInfo | select -unique name, Path, Description | ForEach-Object { 
    $name = $_.name 
    $path = $_.Path 
    $description = $_.Description 
    "Processing : $name $path $description" 
    $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() 
    $ace = ([WMIClass] "Win32_Ace").CreateInstance() 
    $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() 
    $sd.DACL = @() 
    $ShareInfo | where {$_.name -eq $name} | ForEach-Object { 
        $SID = new-object security.principal.securityidentifier($_.SID)
        [byte[]] $SIDArray = ,0 * $SID.BinaryLength
        $SID.GetBinaryForm($SIDArray,0)
        $Trustee.Name = $_.user
        $Trustee.SID = $SIDArray
        $ace.AccessMask = $_.AccessMask
        $ace.AceType = $_.AceType
        $ace.AceFlags = $_.AceFlags
        $ace.trustee = $Trustee
        $sd.DACL += $ACE.psObject.baseobject
    } 
    $inParams = $CustomShare.psbase.GetMethodParameters("SetShareInfo") 
    $inParams.Access = $SD 
    $CustomShare.psbase.invokemethod("setshareinfo", $inParams, $null) 
}

Формат запуска данного скрипта из командной строки CMD или меню Run будет следующим:

powershell %path%\AddUser.ps1 -share "Имя сетевой шары" -user "имя добавляемой группы" -mask "маска доступа, Full/Change/Read" -type "тип доступа, Allow/Deny"

эту команду следует выполнять в одну строчку. В качестве переменной %path% нужно указать путь к папке со скриптом, если он заранее не добавлен в системную переменную %path%. В качестве маски доступа нужно указать одно из 3-х значений, которое может быть Full, Change или Read. Более одного параметра указывать нельзя. Ну и в качестве типа доступа указать либо Allow, что даст доступ, либо Deny, что явно запретит доступ.

Ну вот как бы и всё на данном этапе. Здесь я много чего не пояснял, т.к. достаточно (в моём понимании) разобрал в предыдущих 3-х частях о работе с сетевыми шарами в PowerShell. Но это ещё не всё. Главный девиз PowerShell - быть удобным для использования и кратким для написания (это я сам придумал :) ), однако при работе с сетевыми шарами это совершенно не прослеживается и даже может создаться впечатление громоздкости (хотя тот, кто считает этот код громоздким может написать скрипт короче на VBS с использованием только WMI/.NET :) ), поэтому в следующей части я постараюсь исправить сей момент путём написания единого (относительно компактного по возможности) и представить его как готовое решение, которое в работе будет действительно удобным. Не отключайтесь, продолжение обязательно будет :)

p.s. Данный скрипт не обязательно является самым простым решением, т.к. возможно, что данную операцию можно провести более удобным и изящным способом (хотя, после чтения документации на MSDN мне так не кажется, что это возможно), но в любом случае адекватные замечания/поправки/дополнения к этому скрипту всячески приветствуются.

PowerShell |  ACL |  Shares |  WMI
Tuesday, July 08, 2008 2:12:00 PM (FLE Daylight Time, UTC+03:00)   Comments [0]    

 

Примечание: данный пост перепечатан в связи с закрытием бложиков на spaces.live.com, как имеющий какую-то ценность для автора и/или читателей.


В первой части мы рассмотрели использование PowerShell для добавления DACL (Discretionary Access Control List) к сетевой шаре как для создания списка ACL и получения возможности в дальнейшем работать с этим списком из PowerShell. Данный метод полностью заменяет текущий список DACL сетевой папки, т.е. все текущие участники безопасности будут удалены и заменены теми, которые были указаны в теле скрипта. Теперь стоит поговорить об извлечении и чтении DACL для сетевых папок как для анализа, так и для выборочного добавления/удаления участников безопасности в списке ACL. Класс Win32_Share имеет лишь один метод для добавления ACL списка - SetShareInfo, который полностью заменяет текущий список DACL и не имеет нативного метода добавления частичного DACL к имеющемуся списку DACL. Поэтому для добавления или удаления участников безопасности из этого списка нам потребуется сначала считать этот список, проанализировать, внести необходимые изменения и записать этот список с внесёнными изменениями в ACL сетевой папки.

Процесс извлечения DACL из ACL сетевой шары будет происходить примерно в обратном порядке записи. В предыдущей части я говорил про процесс упаковывания ("инкапсуляции") массива в массив, и сейчас нам придётся обратно расшивать (извлекать) массивы из массивов. Как уже говорилось в первой части, для чтения DACL сетевой папки используется класс Win32_LogicalShareSecuritySettings:

Get-WmiObject Win32_LogicalShareSecuritySetting

Так мы получим все ShareSecuritySettnigs для всех расшаренных папок. Давайте отфильтруем только ту, конкретно с которой будем работать и выберем её в переменную:

$ShareSec = Get-WmiObject Win32_LogicalShareSecuritySetting  -filter "name='UserShare'"

Если теперь теперь посмотреть содержимое переменной, то ничего интересного там мы не увидим:

[C:\] Get-WmiObject Win32_LogicalShareSecuritySetting -filter "name='UserShare'" | Format-List [a-z]* Caption : Security settings of UserShare ControlFlags : 32772 Description : Security settings of UserShare Name : UserShare SettingID :

Давайте покопаем поглубже. В процессе создания DACL для шары мы записывали уже готовый SecurityDescriptor, в котором хранится DACL и внутри которого уже хранятся ACE и Trustee - вот эти объекты нам и нужны. Для извлечения этого класс Win32_LogicalShareSecuritySettings имеет метод GetSecurityDescriptor

$SD = $ShareSec.GetSecurityDescriptor()

И мы увидим две строчки (я специально отфильтровал вывод ненужной для нас в данный момент информации, которая начинается с символа подчёркивания "_"):

[C:\] $SD Descriptor : System.Management.ManagementBaseObject ReturnValue : 0

Вот здесь нас будет интересовать параметр Descriptor:

[C:\] $SD.Descriptor | Format-List [a-z]* ControlFlags : 32772 DACL : {System.Management.ManagementBaseObject} Group : System.Management.ManagementBaseObject Owner : System.Management.ManagementBaseObject SACL :

Вот мы уже добрались до DACL:

[C:\] $SD.Descriptor.DACL | Format-List [a-z]* AccessMask : 1179817 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : Trustee : System.Management.ManagementBaseObject AccessMask : 1245631 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : Trustee : System.Management.ManagementBaseObject AccessMask : 2032127 AceFlags : 0 AceType : 0 GuidInheritedObjectType : GuidObjectType : Trustee : System.Management.ManagementBaseObject

Вот здесь мы видим 3 ACE с разными AccessMask. Но имён почему-то не видно..а не видно, потому что имена участников безопасности запрятаны ещё глубже, а именно в Trustee (вы помните, как мы записывали имя участника безопасности в класс Trustee). Давайте посмотрим первый элемент:

[C:\] $SD.Descriptor.DACL[0].Trustee | Format-List [a-z]* Domain : Name : Everyone SID : {1, 1, 0, 0...} SidLength : 12 SIDString : S-1-1-0

И команда нам вернёт имя пользователя. У меня это Everyone. AccessMask = 1179817 означает Read&Execute + Synchronize. Узнать это очень легко, достаточно набрать в консоли:

[C:\] [System.Security.AccessControl.FileSystemRights]1179817 ReadAndExecute, Synchronize [C:\] [System.Security.AccessControl.FileSystemRights]1245631 Modify, Synchronize [C:\] [System.Security.AccessControl.FileSystemRights]2032127 FullControl

Теперь посмотрим имя второго участника безопасности, который имеет маску доступа 1245631 (Change):

[C:\] $SD.Descriptor.DACL[1].Trustee | Format-List [a-z]* Domain : CONTOSO Name : Domain Users SID : {1, 5, 0, 0...} SidLength : 28 SIDString : S-1-5-21-3709200118-438321133-4282490648-513

И т.д. можно перебирать все элементы массива. Давайте для начала выведем весь этот список в CSV. Здесь я не буду изобретать велосипед, а уже буду использовать готовое решение от /\/\o\/\/:

$filename = 'C:\ShareInfo.csv'
$shares = Get-WmiObject Win32_Share -filter 'type=0'
$Shareinfo = @()
foreach ($share in $shares) {
    $shareSec = gwmi Win32_LogicalShareSecuritySetting  -filter "name='$($share.name)'"
    if($shareSec) {
        $sd = $sharesec.GetSecurityDescriptor() 
        $ShareInfo += $SD.Descriptor.DACL |% {
            $_ | select @{e={$share.name};n='Name'},
            @{e={$share.Path};n='Path'},
            @{e={$share.Description};n='Description'},
            AccessMask, 
            AceFlags,
            AceType,
            @{e={$_.trustee.Name};n='User'},
            @{e={$_.trustee.Domain};n='Domain'},
            @{e={$_.trustee.SIDString};n='SID'}
        }
    }
}
$ShareInfo | select Name,Path,Description,User,Domain,SID, AccessMask,AceFlags,AceType | export-csv -noType $filename

На выходе мы получим CSV файл, где в простеньком (но вполне удобочитаемом) формате есть вся информация о имеющихся сетевых шарах на локальном компьютере. К слову говоря, этот CSV файл потом можно будет импортировать обратно для восстановления Share Permissions и другой информации о шарах. Давайте посмотрим на содержимое переменной $ShareInfo:

[C:\] $Shareinfo Name : UserShare Path : C:\Test Description : AccessMask : 1179817 AceFlags : 0 AceType : 0 User : Everyone Domain : SID : S-1-1-0 Name : UserShare Path : C:\Test Description : AccessMask : 1245631 AceFlags : 0 AceType : 0 User : Domain Users Domain : CONTOSO SID : S-1-5-21-3709200118-438321133-4282490648-513 Name : UserShare Path : C:\Test Description : AccessMask : 2032127 AceFlags : 0 AceType : 0 User : Administrators Domain : BUILTIN SID : S-1-5-32-544 Name : CertEnroll Path : C:\WINDOWS\system32\certsrv\CertEnroll Description : AccessMask : 2032127 AceFlags : 0 AceType : 0 User : Everyone Domain : SID : S-1-1-0 <...>

Остальное я не стал показывать, т.к. будет содержать идентичную информацию для остальных ресурсов. Обладая этой информацией мы можем гибко изменять наши настройки, например добавлять или удалять выборочно единичных участников безопасности. Давайте начнём с удаления. К примеру, удалим из ACL шары UserShare группу Everyone. Не уверен, что этот метод является самым правильным, но мы сделаем переприсвоение массива с фильтрацией по имени шары и имени пользователя, которого будем удалять:

$ShareInfo = $shareInfo | where {$_.name -eq "UserShare" -and $_.user -ne "Everyone"}

Теперь можем посмотреть содержимое переменной $ShareInfo:

[C:\] $ShareInfo = $shareInfo | where {$_.name -eq "UserShare" -and $_.user -ne "Everyone"} [C:\] $Shareinfo Name : UserShare Path : C:\Test Description : AccessMask : 1245631 AceFlags : 0 AceType : 0 User : Domain Users Domain : CONTOSO SID : S-1-5-21-3709200118-438321133-4282490648-513 Name : UserShare Path : C:\Test Description : AccessMask : 2032127 AceFlags : 0 AceType : 0 User : Administrators Domain : BUILTIN SID : S-1-5-32-544

Как мы видим, переменная $ShareInfo уже не содержит ACE группы Everyone. Таким образом можно фильтровать нужные элементы массива по любым критериям, как группа пользователей, имя сетевой шары, тип доступа и т.д. Теперь можно импортировать эту переменную в нашу шару. Для импорта этой информации воспользуемся тем же методом, каким мы создавали Share Permissions с нуля. Разница будет лишь в том, что для создания нужных объектов (как User, SID, AccessMask) мы будем использовать значения из переменной $ShareInfo:

$ShareInfo | select -unique name, Path, Description | ForEach-Object { 
    $name = $_.name 
    $path = $_.Path 
    $description = $_.Description 
    "Processing : $name $path $description" 
    $SD = ([WMIClass] "Win32_SecurityDescriptor").CreateInstance() 
    $ace = ([WMIClass] "Win32_Ace").CreateInstance() 
    $Trustee = ([WMIClass] "Win32_Trustee").CreateInstance() 
    $SD.DACL = @() 
    $ShareInfo | where {$_.name -eq $name} | Foreach-Object { 
        $SID = new-object security.principal.securityidentifier($_.SID) 
        [byte[]] $SIDArray = ,0 * $SID.BinaryLength 
        $SID.GetBinaryForm($SIDArray,0) 
        $Trustee.Name = $_.user 
        $Trustee.SID = $SIDArray 
        $ace.AccessMask = $_.AccessMask 
        $ace.AceType = $_.AceType 
        $ace.AceFlags = $_.AceFlags 
        $ace.trustee = $Trustee 
        $SD.DACL += $ACE.psObject.baseobject
    } 
    $Share = Get-WmiObject win32_share -filter "name='UserShare'" 
    $inParams = $share.psbase.GetMethodParameters("SetShareInfo") 
    $inParams.Access = $SD 
    $share.psbase.invokemethod("SetShareInfo", $inParams, $null)
}

Если посмотреть на скрипт из предыдущей статьи, то можно проследить практически идентичную процедуру записи новых SharePermissions. Вот так мы получили готовый шаблон для изменения SharePermissions, который включает 3 этапа:

  1. чтение текущих SharePermissions (и прочей информации) в переменную;
  2. изменение необходимых параметров внутри переменной;
  3. запись новой переменной с обновлёнными Share Permissions обратно в ACL сетевой папки.

Кстати говоря, для изменения одного конкретного ACE (без удаления) можно использовать следующий метод. Он заключается в определении местоположения необходимого элмента в массиве и редактировании конкретно этого элемента. Делается это следующим образом, пишем функцию (за функцию отдельное спасибо Васе Гусеву):

function findinarr ($array, $value) {for ($i=0; $i -lt $array.count;$i++){if($array[$i].user -eq $value){$i}}}

Теперь определяем порядковый номер элемента в массиве, который содержит группу Domain Users и вместо Change дадим этой группе право только Read:

[C:\] function findinarr ($array, $value) {for ($i=0; $i -lt $array.count;$i++){if($array[$i].user -eq $value){$i}}} [C:\] $count = findinarr $shareInfo "Domain Users" [C:\] $ShareInfo[$count].AccessMask = 1179817 [C:\] $ShareInfo Name : UserShare Path : C:\Test Description : AccessMask : 1179817 AceFlags : 0 AceType : 0 User : Domain Users Domain : CONTOSO SID : S-1-5-21-3709200118-438321133-4282490648-513 Name : UserShare Path : C:\Test Description : AccessMask : 2032127 AceFlags : 0 AceType : 0 User : Administrators Domain : BUILTIN SID : S-1-5-32-544

Вот теперь Группа Domain Users имеет маску доступа не Change, а Read. Теперь осталось только записать изменённые данные в ACL шары по вышеприведённому примеру, где мы удаляли группу Everyone из ACL.

В этой части мы рассмотрели чтение информации о сетевых шарах, в частности чтение Share Permissions, экспорт этих данных в CSV файл, а так же рассмотрели вопросы удаления единичных ACE из списка ACL и их редактирования. В следующей части я расскажу, как добавлять участников безопасности к существующему списку ACL и в качестве итогового резюме мы приведём в порядок весь материал, который изучили, чтобы его можно было удобно использовать в производственной среде. Так что продолжение следует.

PowerShell |  ACL |  Shares |  WMI
Monday, July 07, 2008 1:24:00 PM (FLE Daylight Time, UTC+03:00)   Comments [2]    

 

Page 1 of 2 in the PowerShellShares category Next Page
 · 

All content © 2008 - 2012, Vadims Podāns
"Spaces" Theme provided by: Vadims Podāns
About


E-mail - Send mail to the author(s)
Live Messenger -
For english language visitors
Библиотека
Календарик
<February 2012>
SunMonTueWedThuFriSat
2930311234
567891011
12131415161718
19202122232425
26272829123
45678910

Карта расположения посетителей
Favorites





Fan list



Disclaimer
Вся информация на сайте предоставляется на условиях «как есть», без предоставления каких-либо гарантий и прав.

При использовании материалов c данного сайта ссылка на оригинальный источник обязательна.
Protected by Copyscape Online Plagiarism Scanner