Contents of this directory is archived and no longer updated.

Posts on this 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>

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

19

По просьбе читателей, а так же с учётом востребованности (судя по сообщениям форумов и ньюсгрупп) я нашёл время переписать скрипт 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
    }
}

Примечание: данный пост перепечатан в связи с закрытием бложиков на 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 файла. Сначала я приведу список команд, которые доступны при использовании скрипта и их синтаксис:


Read more →

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


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


Read more →

Примечание: данный пост перепечатан в связи с закрытием бложиков на 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:


Read more →