Feeds:
Записи
Комментарии

В серверных операционных системах Microsoft по умолчанию отсутствует служба WebClient. Данный функционал включается установкой дополнительного компонента, который зависит от версии OS.

Windows Server 2008 R2*,2012,2012 R2 (компонент Desktop-Experience)**:

  Install-WindowsFeature Desktop-Experience

* Для Windows Server 2008 R2 командлет   Install-WindowsFeature отсутствует, вместо него используйте Add-WindowsFeature .

de211116

Windows Server 2016(компонент WebDAV-Redirector)**:

Install-WindowsFeature WebDAV-Redirector –Restart
wd211116

** Требуется обязательная перезагрузка

В систему добавляется две новые службы(WebClient&MRxDAV):

s211116 

Настройка службы WebClient производится через реестр. Подробнее про параметры, можно прочитать —  WebDAV Redirector Registry Settings

Основной параметр BasicAuthLevel имеет значение:

  • 0 — Basic authentication disabled
  • 1 — Basic authentication enabled for SSL shares only
  • 2 or greater — Basic authentication enabled for SSL shares and for non-SSL shares

В более младших версиях, параметр по умолчанию: 2

reg211116

 

Для проверки работы:

nd211116

 

Рассмотрим, как изменить расширенное свойство файлов на примере Comments.

ep10112016

Для получения свойств, можно воспользоваться Com-классом Shell.Application. Подробнее — Retrieving Extended File Properties

# Отобразить расширенные свойства            
$folder = "С:\files"            
$file = "Document"            
$shell = New-Object -ComObject Shell.Application            
$ns = $shell.NameSpace($folder)            
$fn = $ns.Items()| Where {$_.Name -eq $file}            
            
0..60 | Select-Object @{n="Name";e={$ns.GetDetailsOf($ns,$_)}},            
    @{n="Value";e={$ns.GetDetailsOf($fn,$_)}}

Выведем отдельное свойство Comments:

sp101116

Для изменения расширенных свойств Shell.Application не подходит, воспользуемся другими методами.

1.  Office.Application

Разберем на примере Word.Application для других классов отличия лишь в имени класса.

Param(            
 $Path  = "D:\mydoc.docx",            
 $PropertyName  = "Comments",            
 $Value = "$(Get-Date): $env:COMPUTERNAME - $env:USERNAME",            
 [switch]$Show            
)            
            
# Создаем экземпляр класса            
$App = New-Object -ComObject word.application            
$App.Visible = $false            
$Document = $App.Documents.Open($Path)            
$BuiltIn = $Document.BuiltInDocumentProperties             
            
# Список свойств            
$Property = @(             
 @{n="Name";e={$_.GetType().InvokeMember("Name", "GetProperty",$null,$_,$null)}},             
 @{n="Value";e={$_.GetType().InvokeMember("Value", "GetProperty",$null,$_,$null)}}            
)            
            
if($Show)            
{            
 $BuiltIn | Select-Object -Property $Property | Out-Default            
}            
else             
{            
 # Свойство            
 $PP = $BuiltIn.GetType().InvokeMember("Item", "GetProperty",$null,$BuiltIn,$PropertyName)              
 $PP | Select-Object -Property $Property | Out-Default            
            
 # Изменим свойство            
 $PP.GetType().InvokeMember("Value", "SetProperty",$null,$PP,$Value)            
            
 $PP = $BuiltIn.GetType().InvokeMember("Item", "GetProperty",$null,$BuiltIn,$PropertyName)              
 $PP | Select-Object -Property $Property | Out-Default            
             
    # Сохраняем            
 $Document.Saved = $false            
 $Document.Save()            
}            
            
# Освобождаем ресурсы            
$App.Quit()            
[Runtime.InteropServices.Marshal]::ReleaseComObject($App) | Out-Null            
$App = $null            
[GC]::Collect()            
[GC]::WaitForPendingFinalizers()

Для получения свойств, параметр Show:

wep101116

Для изменения Comments:

wcc101116

2. Библиотека Dsofile.dll

Скачаем и установим библиотеку – https://www.microsoft.com/en-us/download/confirmation.aspx?id=8422.

Зарегистрируем библиотеку:

regsvr32 "C:\Program Files (x86)\DsoFile\dsofile.dll"

reg101116

Если система у Вас x-64, то запустите x-86 версию PowerShell.

Add-Type -Path "C:\Program Files (x86)\DsoFile\Demo\Interop.Dsofile.dll"            
$file = "D:\mydoc.docx"            
$op = New-Object DsoFile.OleDocumentPropertiesClass            
# Режим редактирования            
$op.Open($file,$false)            
            
# Получение свойств            
$op.SummaryProperties            
            
# Комментарий            
$op.SummaryProperties.Comments            
            
# Изменим комментарий            
$op.SummaryProperties.Comments = Get-Date            
            
# Сохраняем            
$op.Save()            

3.  OpenXmlSDK

Скачиваем и устанавливаем — https://www.microsoft.com/en-us/download/details.aspx?id=30425

Add-Type -Path "C:\Program Files (x86)\Open XML SDK\V2.5\lib\DocumentFormat.OpenXml.dll"            
$file = "D:\mydoc.docx"            
$file = [DocumentFormat.OpenXml.Packaging.WordprocessingDocument]::Open($file,$true)            
$file.PackageProperties.Description = Get-Date            
$file.Close()            

4. WindowsAPICodePack

Для работы с PackageManagement есть хорошая документация с подробными примерами — https://msdn.microsoft.com/ru-ru/powershell/wmf/5.0/oneget_cmdlets

# Найдем пакеты для установки            
$package = "WindowsAPICodePack-Shell","WindowsAPICodePack-Core"            
Find-Package -Name $package -Provider NuGet -Source http://www.nuget.org/api/v2            
            
pk101116
# Установим            
$package = "WindowsAPICodePack-Shell","WindowsAPICodePack-Core"            
Find-Package -Name $package -Provider NuGet -Source http://www.nuget.org/api/v2 | Install-Package            
            
# Проверим установку            
Get-Package $package | Format-List Name,Source            

gp101116

Внесем изменения в Comments:
Add-Type -Path "C:\Program Files\NuGet\Packages\WindowsAPICodePack-Core.1.1.2\lib\Microsoft.WindowsAPICodePack.dll"            
Add-Type -Path "C:\Program Files\NuGet\Packages\WindowsAPICodePack-Shell.1.1.1\lib\Microsoft.WindowsAPICodePack.Shell.dll"            
            
$file = "D:\mydoc.docx"            
$sh = [Microsoft.WindowsAPICodePack.Shell.ShellFile]::FromFilePath($file)                       
$sh.Properties.System.Comment.Value = Get-Date

Задача: Получить адрес клиента, который подключается через VPN к RRAS серверу с помощью PowerShell.

В нашей лабе:

  1. SRV-DC01  — Контроллер домена (ОС 2012+) с роль шлюза Windows PowerShell Web Access
  2. SRV-VPN    — Сервер с ролью RRAS (ОС 2012+)
  3. W10-CL1   — Клиент (ОС 2012+)

Пример схемы:

Windows PowerShell Web Access diagram

1. Установка  Windows PowerShell Web Access

Данная процедура подробно описана в Install and Use Windows PowerShell Web Access ,

поэтому лишь выполним основные действия на SRV-DC01.

# Установка роли            
Install-WindowsFeature –Name WindowsPowerShellWebAccess -IncludeManagementTools -Restart            
            
# После перезагрузки            
# Установка и настройка web приложения с self-signed сертификатом(            
# рекомендуется использовать только в тестовых средах)            
# Path: /pswa            
# ApplicationPool: pswa_pool            
# EnabledProtocols: http            
# PhysicalPath: %windir%/Web/PowerShellWebAccess/wwwroot            
            
Install-PswaWebApplicationUseTestCertificate
ipswa08112016

Осталось добавить только правила доступа для PSWA. Лучше создавать правила для групп, а не отдельных пользователей.

Для нашего примера, создадим группу helpdesk_vpn в которую будет входить пользователь contoso\user1.

# Создадим группу            
New-ADGroup -Name helpdesk_vpn -GroupCategory Security -GroupScope Universal            
            
# Добавим пользователя в нее            
Add-ADGroupMember -Identity helpdesk_vpn -Members User1

После создания группы, создадим правило для доступа с параметрами: подключение ведется к SRV-VPN, кому разрешено contoso\helpdesk, constrained endpoints с именем VPN.

# Правило доступа                      
$param = @{            
    RuleName              = "Helpdesk VPN"             
    UserGroupName    = "contoso\helpdesk_vpn"             
    ComputerName      =  "srv-vpn"            
    ConfigurationName = "VPN"            
    Force                     = $true            
}            
            
Add-PswaAuthorizationRule @param            

PS > Add-PswaAuthorizationRule @param

Id    RuleName         User

—    ———         —-

0     Helpdesk VPN     contoso\helpdesk_vpn

2. Перейдем к созданию constrained endpoints на сервере SRV-VPN

Требуемый функция Get-RemoteAccessConnectionStatistics находится в модуле RemoteAccess.

В этом можно убедиться:

grac08112016 

Т.к. у helpdesk_vpn права на выполнения данного функции — нет, то нужно  создать отдельный аккаунт от которого будет запускаться функция или добавить пользователя в группу у которой есть право на выполнение(например Администраторы). Начиная с PowerShell v5+  у командлета

New-PSSessionConfigurationFile появился параметр  -RunAsVirtualAccount , позволяя обойтись без создания дополнительных групп и пользователей. Т.к. данный аккаунт по умолчанию входит в локальную группу Администраторов в ОС начиная с 2008 R2. При конфигурировании надо быть очень осторожным, т.к. неверное конфигурирования даст пользователю возможность запускать команды от более привилегированного пользователя.

PSv5+: 
# Создание constrained endpoints            
# Данные командлеты требуются, если пользовать захочит сделать Enter-PsSession            
$Cmdlets = @(            
    'Get-Command', 'Out-Default',            
    'Exit-PSSession', 'Measure-Object',            
    'Select-Object' , 'Get-FormatData'            
)            
 
# Параметры                        
$param = @{                        
    Path                          = ".\VisibleCmdlets.pssc"                        
    VisibleCmdlets          = $Cmdlets                        
    VisibleFunctions        = "RemoteAccess\Get-RemoteAccessConnectionStatistics"            
    SessionType              = "RestrictedRemoteServer"                           
    LanguageMode          = "NoLanguage"                        
    RunAsVirtualAccount = $true                                   
}

# Конфигурирование и назначение прав
New-PSSessionConfigurationFile  @param
Register-PSSessionConfiguration -Path .\VisibleCmdlets.pssc -Name VPN -Force
Get-PSSessionConfiguration VPN | Set-PSSessionConfiguration -ShowSecurityDescriptorUI

Для PSv4+:

Тут указываем учетную запись обладающую правами локального администратора

(отвечает параметр -RunAsCredential «Contoso\Administrator») .

# Создание constrained endpoints            
# Данные командлеты требуются, если пользовать захочит сделать Enter-PsSession            
$Cmdlets = @(            
    'Get-Command', 'Out-Default',            
    'Exit-PSSession', 'Measure-Object',            
    'Select-Object' , 'Get-FormatData'            
)            
            
# Параметры            
$param = @{            
    Path = ".\VisibleCmdlets.pssc"            
    VisibleCmdlets = $Cmdlets            
    VisibleFunctions = "Get-RemoteAccessConnectionStatistics"            
    ModulesToImport = "RemoteAccess"            
}            
            
# Конфигурирование и назначение права            
New-PSSessionConfigurationFile  @param            
Register-PSSessionConfiguration -Path .\VisibleCmdlets.pssc -Name VPN -RunAsCredential "Contoso\Administrator" -Force            
Get-PSSessionConfiguration VPN | Set-PSSessionConfiguration -ShowSecurityDescriptorUI            

perm08112016

Если все прошло без ошибок, то у Вас должно быть примерно следущее:

gpc08112016

3. Осталось сделать тест и убедиться, что все отрабатывает хорошо.

Переходим по адресу https://mypswa.ru/pswa и заполняем поля

User Name, Password, Computer Name,Configuration name и нажимаем Sign In.

pswa08112016

Выполняем функцию:

pswac08112016

Доступные нам команды в сессии:

comm08112016

 

По умолчанию PowerShell обладает довольно слабой поддержкой  командлетов для гибкого управления правами NTFS. Зачастую Get-Acl/Set-Acl не справляются ,даже, с базовыми задачами. При использовании .Net  / WMI (Win32_Trustee, Win32_ACE, Win32_SecurityDescriptor) API позволяет расширить функционал при этом не добавляя гибкости и простоты, с значительным увеличением кодовой базы. Поставляемые по умолчанию  утилиты cacls/icacls/takeown –  справляются со своими задачами, но имеют ограничения и сложность в добавлении расширенного функционала. 

Сторонние утилиты обладающие более широким функционалом, наиболее известные:

SubInACL — https://www.microsoft.com/en-us/download/details.aspx?id=23510

SetACL(для скриптования есть поддержка COM-интерфейса) — https://helgeklein.com

На мой взгляд более удобная  — это SetACL, обладает отличным функционалом, хорошей документаций с большим обилием примеров, поддержка длинных путей 256+ и распространяется бесплатно.

Raimund Andrée написал прекрасный модуль NTFSSecurity для работы с NTFS, обладающий отличным функционал и легкостью управления,поддержка длинных путей 256+. Кто хочет более детально изучить работу модуля может ознакомится с исходными кодами проекта на C# — https://github.com/raandree/NTFSSecurity.

В качестве документации, настоятельно рекомендую прочитать:

NTFSSecurity Tutorial 1 — Getting, adding and removing permissions

NTFSSecurity Tutorial 2 — Managing NTFS Inheritance and Using Privileges

В нашем примере версия PowerShell 5.0 (или выше 5.1 в состоянии preview, 6.0 alpha) , который имеет поддержку Windows 7+.  Модуль NTFSSecurity  не поддерживает использование Linux/MacOS.

Установка модуля.

В PowerShell V3 была добавлена новая переменная среды — $env:PSModulePath.

Переменная среды PSModulePath содержит пути откуда можно импортировать модули, когда не указан полный путь к модулю. 

Дополнительные сведения:

Modifying the PSModulePath Installation Path — https://msdn.microsoft.com/en-us/library/dd878326(v=vs.85).aspx

Installing a PowerShell Module — https://msdn.microsoft.com/en-us/library/dd878350(v=vs.85).aspx

При изменении переменной PSModulePath , чтобы настройки вступили в силу, требуется отправить сообщение WM_SETTINGCHANGE с параметром Environment. Пример скрипта для отправки сообщения — Invoke-WMSettingsChange by Oisin Grehan

В PowerShell V4 PSModulePath  переменная содержит путь:

%ProgramFiles%\WindowsPowerShell\Modules

В моем случае:

PS > $env:PSModulePath.split(";")
C:\Users\Administrator\Documents\WindowsPowerShell\Modules
C:\Program Files\WindowsPowerShell\Modules
C:\Windows\system32\WindowsPowerShell\v1.0\Modules

В PowerShell v5 добавили замечательную возможность PowerShellGet(V3,V4 – данный модуль тоже доступен) для работы с онлайн репозитариями. Подробнее можно ознакомиться в документации — https://msdn.microsoft.com/en-us/powershell/gallery/readme

И выполняем команду:

Install-Module -Name NTFSSecurity -Scope AllUsers -Verbose -Force            

Где область AllUsers:

The AllUsers scope lets modules be installed in a location that is accessible to all users of the computer, that is

, %systemdrive%:\ProgramFiles\WindowsPowerShell\Modules.

Модуль содержит на момент написания 36 командлетов. Список можно посмотреть:

Get-Command -Module NTFSSecurity

Убедимся, что модуль находится в нужном месте:

PS > Get-Module NTFSSecurity | Format-List            
            
Name              : NTFSSecurity            
Path              : C:\Program Files\WindowsPowerShell\Modules\NTFSSecurity\4.2.3\NTFSSecurity.psm1            
Description       : Windows PowerShell Module for managing file and folder security on NTFS volumes


Использование привилегий

Зачастую разрешения даны только определенным группам пользователей. В редких случаях, некорректного назначения прав deny, удаления групп/пользователей являющихся владельцем объекта. Тем самым,лишая возможности, обладая даже полными правами Администратора системы, чтения ACL-объекта, получая -  access is denied. Администратор по умолчанию обладает привилегией Take ownership of files or other objects (SeTakeOwnershipPrivilege) , которая позволяет стать владельцем любых объектов. Но в этом случае, затираются существующие ACL объекта, что может привести к нежелательному результату и дополнительной работе для администратора.

В нашем примере, отметим только те привилегии, которые имеют отношения к файлам и папкам.

  • Back up files and directories:

Это право пользователя определяет, какие пользователи могут игнорировать разрешения  файлов и каталогов, реестра и другие  в целях резервного копирования системы.

Это право пользователя эквивалентно предоставлению следующих разрешений пользователя или группы, выбранных для всех файлов и папок в системе:

  • Traverse Folder/Execute File

  • List Folder/Read Data

  • Read Attributes

  • Read Extended Attributes

  • Read Permissions

По умолчанию: Administrators и Backup Operators

  • Restore files and directories:

Этот параметр безопасности определяет, какие пользователи могут игнорировать разрешения файлов, каталогов, реестра и другие  при их восстановления из резервной копии и определяет, какие пользователи могут устанавливать владельца для объекта.

Предоставление этого права пользователя учетной записи похож на предоставление учетной записи следующие разрешения для всех файлов и папок в системе:

  • Traverse Folder/Execute File
  • Write

По умолчанию: Administrators и Backup Operators

  • Take ownership of files or other objects:

Разрешает пользователю становиться вла­дельцем системных объектов, в том числе объектов Active Directory, файлов и папок, принтеров, разделов реестра, процессов и потоков.

По умолчанию: Administrators

Для просмотра текущих привилегий, в модуле есть командлет Get-Privileges или можно воспользоваться встроенной утилитой whoami /priv .

pr241016

Создадим простую структуру:
 
md E:\Doc | Out-Null            
Get-Process > E:\Doc\file1.txt            
Get-Service > E:\Doc\file2.txt            
 
Для получения разрешений командлет Get-NTFSAccess ,для получения владельца - Get-NTFSOwner.
 
dacl241016
 

Пример 1:

Уберем все права  и  назначим ‘NT SERVICE\TrustedInstaller’ владельцем.

Set-NTFSOwner E:\DOC -Account 'NT SERVICE\TrustedInstaller'            
Disable-NTFSAccessInheritance E:\DOC -RemoveInheritedAccessRules

Проверяем стандартными средствами:

acg241016

Оба способа возвращают ‘Access is denied’ под учетной записью администратора.

Если нам требуется только посмотреть список файлов, то можно использовать модуль PowerForensics.

Install-Module PowerForensics -Scope AllUsers -Force

Список файлов E:\Doc:

fm241016

Добавим пользователю, скажем Alexander, права на чтение папки без изменения владельца:

adaa241016

Проверим под пользователем:

ua241016

Пример 2:

С "осиротевшими" объектами. Структура папок из первого примера. Добавляем группу и пользователя, назначаем права, а потом удаляем.

ex2241016

Теперь у нас и в ACL, и владелец – только SID. Get-NTFSOrphanedAccess – позволяет получить список прав, только с "осиротевшими" объектами.

or241016

Т.к. структуру файлов мы знаем, позволим Alexander читать только файл file1.txt

fa241016

Get-NTFSOrphanedAccess  — выведет пусто, в отличие от Get-NTFSAccess

alco241016

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

  1. NTFSSecurity
  2. UserRights
  3. PowerForensics

Для моделей ZyXEL, которые не поддерживаю управление через протокол SSH , воспользуемся протоколом telnet( включен по умолчанию). Стандартная утилита telnet ,которая поставляется в комплекте (начиная с Windows Vista — включается через установку компонентов Windows *), сложно поддается автоматизации и многочисленные примеры ,связанны с отправкой команд, например с SendKeyshttp://www.maxtblog.com/2012/06/telnet-automation-with-powershell-made-simple/ .

*dism /online /Enable-Feature /FeatureName:TelnetClient

* — Install-WindowsFeature «Telnet-Client»

 

Для автоматизации воспользуемся библиотекой Telnet C# —  https://telnetcsharp.codeplex.com/ . Удобная и простая в управлении. Для работы с библиотекой, ее требуется скомпилировать или скопировать из папки ..\telnet\bin\Release\Telnet.dll.

Param(            
 $HostName     = "192.168.0.1",            
 $Port      = 23,            
 $TimeoutSeconds   = 10,            
 $VirtualScreenWidth  = 80,            
 $VirtualScreenHeight  = 40,            
 $UserName     = "admin",            
 $PassWord     = "admin",            
 $Command     = "show version"            
)            
            
Add-Type -Path "C:\Scripts\Telnet.dll"             
            
$tn = New-Object Telnet.Terminal (            
 $HostName,            
 $Port,             
 $TimeoutSeconds,             
 $VirtualScreenWidth,             
 $VirtualScreenHeight            
)            
            
if($tn.Connect())            
{            
 # Логин            
 $f = $tn.WaitForString("Login")            
 if (!$f) {            
        throw "No login possible"            
 }            
                
 $tn.SendResponse($UserName, $true) | Out-Null            
             
 # Пароль            
    $f = $tn.WaitForString("Password")            
    if (!$f) {            
        throw "No password prompt found"            
 }            
                
    $tn.SendResponse($PassWord, $true) | Out-Null            
                
 # Shell            
 $Command | Foreach-Object {            
  $f = $tn.WaitForString(">");            
  if (!$f) {            
   throw "No > prompt found"            
  }            
            
  # Команда            
  $tn.SendResponse($_, $true) | Out-Null            
  $tn.WaitForChangedScreen() | Out-Null            
    }            
            
    $tn.VirtualScreen.Hardcopy().TrimEnd()            
             
 # LogOut            
 $tn.SendLogout() | Out-Null            
             
 # Закрыть соединение            
 $tn.Close() | Out-Null            
}        
   
tn           

-Command «show ?»

stn

 

-Command «?»

htn

 

Файл: GetRealse.ps1

В проекте PSCX есть замечательная функция Show-Tree , которая послужит  основой в решении задачи.

function Show-ADTreeOU            
{            
    [CmdletBinding()]            
    param(            
        [Parameter(Position=0,             
                   ValueFromPipeline=$true,             
                   ValueFromPipelineByPropertyName=$true)]            
        [ValidateNotNullOrEmpty()]            
        [alias("DistinguishedName")]            
        [string]            
        $Path = (Get-ADDomain).DistinguishedName,            
                                
        [ValidateRange(0, 256)]            
        [int]            
        $Depth = [int]::MaxValue,             
                    
        [Parameter()]            
        [ValidateRange(1, 100)]            
        [int]            
        $IndentSize = 3,             
                    
        [Parameter()]            
        [ValidateRange(0, 2147483647)]            
        [int]            
        $Width,            
                    
        [Parameter()]            
        [switch]            
        $ShowLeafObject,            
            
                    
        [Parameter()]            
        [switch]            
        $UseAsciiLineArt            
    )            
            
    Begin            
    {            
        Set-StrictMode -Version Latest            
                    
                    
        if ($Width -eq 0)            
        {            
            $Width = $host.UI.RawUI.BufferSize.Width            
        }            
                    
        $asciiChars = @{            
            EndCap        = '\'            
            Junction      = '|'            
            HorizontalBar = '-'            
            VerticalBar   = '|'            
        }            
                    
        $cp437Chars = @{            
            EndCap        = '└'            
            Junction      = '├'            
            HorizontalBar = '─'            
            VerticalBar   = '│'            
        }            
                    
        if (($Host.CurrentCulture.TextInfo.OEMCodePage -eq 437) -and !$UseAsciiLineArt)            
        {            
            $lineChars = $cp437Chars            
        }            
        else            
        {            
            $lineChars = $asciiChars            
        }            
                           
        function GetIndentString([bool[]]$IsLast)            
        {            
            $str = ''            
            for ($i=0; $i -lt $IsLast.Count - 1; $i++)            
            {            
                $str += if ($IsLast[$i]) {' '} else {$lineChars.VerticalBar}            
                $str += " " * ($IndentSize - 1)            
            }            
            $str += if ($IsLast[-1]) {$lineChars.EndCap} else {$lineChars.Junction}            
            $str += $lineChars.HorizontalBar * ($IndentSize - 1)            
            $str            
        }            
                    
        function CompactString([string]$String, [int]$MaxWidth = $Width)            
        {            
            $updatedString = $String            
            if ($String.Length -ge $MaxWidth)            
            {            
                $ellipsis = '...'            
                $updatedString = $String.Substring(0, $MaxWidth - $ellipsis.Length - 1) + $ellipsis            
            }            
            $updatedString                
        }            
            
        function ShowItemText([string]$ItemPath, [string]$ItemName, [bool[]]$IsLast)            
        {            
            if ($IsLast.Count -eq 0)             
            {            
                $String = CompactString $ItemPath             
            }            
            else            
            {                     
                $String = CompactString "$(GetIndentString $IsLast)$ItemName "            
            }            
                        
            if($ShowLeafObject)             
            {            
                if($ItemPath)             
                {            
                    $Users = $Script:ADO[$ItemPath].Where({$_.ObjectClass -eq "user"}).Count            
     $Computers = $Script:ADO[$ItemPath].Where({$_.ObjectClass -eq "computer"}).Count            
                    $GR = $Script:ADO[$ItemPath].Where({$_.ObjectClass -eq "group"})            
                    $DL_GR_SEC = $GR.Where({$_.GroupScope -eq "DomainLocal" -and $_.GroupCategory -eq "Security"}).Count            
                    $GL_GR_SEC = $GR.Where({$_.GroupScope -eq "Global" -and $_.GroupCategory -eq "Security"}).Count            
                    $UN_GR_SEC = $GR.Where({$_.GroupScope -eq "Universal" -and $_.GroupCategory -eq "Security"}).Count            
                    $DL_GR_DIS = $GR.Where({$_.GroupScope -eq "DomainLocal" -and $_.GroupCategory -eq "Distribution"}).Count            
                    $GL_GR_DIS = $GR.Where({$_.GroupScope -eq "Global" -and $_.GroupCategory -eq "Distribution"}).Count            
                    $UN_GR_DIS = $GR.Where({$_.GroupScope -eq "Universal" -and $_.GroupCategory -eq "Distribution"}).Count            
            
                    [PSCustomObject]@{            
                        Name      = $String              
                        Users     = $Users            
      Computers = $Computers            
                        DL_GR_SEC = $DL_GR_SEC            
                        GL_GR_SEC = $GL_GR_SEC            
                        UN_GR_SEC = $UN_GR_SEC            
                        DL_GR_DIS = $DL_GR_DIS            
                        GL_GR_DIS = $GL_GR_DIS            
                        UN_GR_DIS = $UN_GR_DIS            
                    }            
                }            
            }             
            else             
            {            
               $String              
            }             
        }            
                    
                    
        function ShowItem([string]$ItemPath, [string]$ItemName='', [bool[]]$IsLast=@())            
        {                    
            # Show current item            
            ShowItemText $ItemPath $ItemName $IsLast            
                        
            # grab its children.  This let's us know if there            
            $childItems = @()            
            if ($IsLast.Count -lt $Depth)            
            {            
                $childItems = @(Get-ADOrganizationalUnit -Filter * -SearchBase $ItemPath -SearchScope OneLevel | Select DistinguishedName, Name)                   
            }            
            
            # Track parent's "last item" status to determine which level gets a vertical bar            
            $IsLast += @($false)            
                                    
            # Recurse through child items            
            for ($i=0; $i -lt $childItems.Count; $i++)            
            {            
                $childItemPath = $childItems[$i].DistinguishedName            
                $childItemName = $childItems[$i].Name            
                $IsLast[-1] = ($i -eq $childItems.Count - 1)            
                ShowItem $childItemPath $childItemName $IsLast            
            }            
        }            
    }            
            
    Process            
    {               
  if($ShowLeafObject)            
  {            
   $ADObjects = @()            
   $ADObjects += Get-ADObject -Filter "ObjectClass -eq 'user' -or ObjectClass -eq 'computers'" -SearchBase $Path            
   $ADObjects += Get-ADGroup -Filter * -SearchBase $Path            
               
   if($ADObjects)            
   {            
    $Script:ADO  = @{}            
    $ADO[$Path] = $ADObjects            
    $ADObjects | Group-Object {$_.DistinguishedName.Split(",",2)[1]} | Foreach-Object {            
     if($_.Name.StartsWith("OU="))            
     {            
      $ADO[$_.Name] = $_.Group            
     }                 
    }            
   }            
  }            
                    
  if($Path)             
  {                  
            ShowItem $Path             
        }             
    }                    
}

shtree

 

Файл: show-adtreeou-ps1.doc

Рассмотрим отправку Post запроса, на примере сайта http://pr.nca.by/. Для этого можно воспользоваться двумя командлетами Invoke-WebRequest/Invoke-RestMethod, оба которые поддерживают параметр –Method.

Форма запроса на сайте выглядит:

form

 

Для получение параметров, которые требуется передать в теле post запроса , существует большое количество различных инструментов:

1. Встроенные средства браузеров, на примере IE/Google Chrome

Для запуска  Developer Tools в IE нажмите F12 или перейдите в меню

Tools –> F12 Developer Tools

IE_DV12

Переходим в раздел Network – нажимаем F5 и выполняем запрос:

IE_NET

 

Выбираем запрос и смотрим результаты:

IE_HR

IE_BODY

 

В Google Chrome для запуска инструментов разработчика нажмите F12 или перейдите в меню:

CH_DV12

CH_REQ

 

В Google Chrome удобно сделано копирование и можно сразу получить результат для утилиты curl.

CH_SV


curl "http://pr.nca.by/edc63526a304744e5976afdac72281a6.a_request.show_prices_count_test.xml" -H "Origin: http://pr.nca.by" -H "Accept-Encoding: gzip, deflate" -H "Accept-Language: ru-RU,ru;q=0.8,en-US;q=0.6,en;q=0.4" -H "User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36" -H "Content-type: application/x-www-form-urlencoded" -H "Accept: */*" -H "Referer: http://pr.nca.by/" -H "Cookie: atereq=edc63526a304744e5976afdac72281a6; __utmt=1; __utma=97320926.45800996.1472894768.1472894768.1472916142.2; __utmb=97320926.1.10.1472916142; __utmc=97320926; __utmz=97320926.1472894768.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)" -H "Connection: keep-alive" --data "v_param=3&v_objnum=17030&v_date_begin=1.7.2016&v_date_end=3.9.2016&v_sq_begin=20&v_sq_end=200&v_purpose=40101&v_soato=5000000000&v_typ=3&v_name=&v_pr_b=25000&v_pr_e=250000&v_cur=4&v_url=http//pr.nca.by/&v_room=&v_floor_beg=&v_floor_end=&v_floor_number_beg=&v_floor_number_end=&v_input_date_beg=&v_input_date_end=&v_purpose_KSforIP=-1&v_wallmat=" --compressed

 

2. Программа-анализатор трафика WireShark

Фильтр: http && ip.dst_host == 93.125.111.85 (по HTTP и IP адресу назначения)

http && http.host contains «nca.by» (по HTTP и содержанию в хосте шаблона)

wr

 

3. Прокси программа для работы с веб – Fiddler

f1

 

Тело запроса:

f2

Ответ, как в текстовой форме, так и в XML:

f3

 

Теперь когда у нас есть все данные, мы можем сформировать Post запрос в PowerShell.

Чтобы отправить запрос на сайт, нам надо получить url-адрес, для этого мы должны перейти на сайт http://pr.nca.by/ , сохранить сессию в переменную. В cookies мы получаем значение atereq, которое участвует в формировании запроса.  И url запроса, должен иметь вид:

http://pr.nca.by/{atereq}.a_request.show_prices_count_test.xml

 

f4

 

$url = "http://pr.nca.by/"
$ct  = "application/x-www-form-urlencoded"
$s = Invoke-WebRequest $url -SessionVariable sb
$val = $sb.Cookies.GetCookies($url).Value
$purl = "${url}$val.a_request.show_prices_count_test.xml"
$r = Invoke-WebRequest $purl -ContentType $ct -WebSession $sb -Method Post -Body @{
	"v_param"="3"
	"v_objnum"="17030"
	"v_date_begin"="1.7.2016"
	"v_date_end"="31.7.2016"
	"v_sq_begin"="20"
	"v_sq_end"="200"
	"v_purpose"="40101"
	"v_soato"="5000000000"
	"v_typ"="3"
	"v_name"=""
	"v_pr_b"="25000"
	"v_pr_e"="2500000"
	"v_cur"="4"
	"v_url"="http//pr.nca.by/"
	"v_room"=""
	"v_floor_beg"=""
	"v_floor_end"=""
	"v_floor_number_beg"=""
	"v_floor_number_end"=""
	"v_input_date_beg"=""
	"v_input_date_end"=""
	"v_purpose_KSforIP"="-1"
	"v_wallmat"=""
}
([xml]$r.Content).response.rowcount_all

Примерный вывод:
PS > $r.Content
375

PS > ([xml]$r.Content).response.rowcount_all
375

При использовании командлета Invoke-RestMethod мы получим готовый ответ  в xml:

$r = Invoke-RestMethod $purl -ContentType $ct -WebSession $sb -Method Post .....

PS > $r
xml                            response
---                            --------
version="1.0" encoding="utf-8" response


PS > $r.response
type            rowcount_all
----            ------------
show_info_count 375


PS > $r.response.rowcount_all
375