Posts on this page:
Навеяно множеством мотивов:
Как мне кажется, с Write-Progress вряд ли получится что-то хорошее, поэтому немного сориентировался и нашёл вот это: PowerShell Script: Copy-FilePlus. Именно этот скрипт взят за основу визуального окна. А за основу логики был взят мой простенький скрипт копирования файлов с сохранением структуры каталогов:Лёгкая разминка. Приведённый по ссылке на Copy-FilePlus вариант Хала Роттенберга является достаточно базовым, поскольку не позволяет копировать за раз множество файлов, плюс требуется вводить имя конечного файла. Я решил его немного расширить и добавить следующий функционал:
заранее оговорюсь, что скрипт обладает одним недостатком: не будет единого прогресс-бара для всех файлов, а только для каждого файла свой (издержки .NET). Зато хоть что-то и весьма актуально при копировании больших файлов. Код получился несколько солидным, но я его постарался снабдить комментариями о коде и о логике, на которой он работает. Причём следуя примеру Роттенберга я скрипт тоже оформил в Advanced Function. По advanced functions я в скрипте вложил ссылки, как почитать о них во встроенной справке PowerShell. И, собственно, сам код:
######################################################## # Copy files with GUI.ps1 # Version 1.3 # # Copies single or couple files with GUI progressbar # # Original idea: Oisín Grehan # First edition: Hal Rottenberg # Second edition: Vadims Podans # # Vadims Podans (c) 2009 # http://www.sysadmins.lv/ ######################################################## # сразу после названия идёт описание к функции. После загрузки функции в консоль # её справка будет доступна в консоли. Достаточно будет набрать: # Get-Help Copy-FilesPlus # вобщем, как в настоящих командлетах function Copy-FilesPlus { <# .Synopsis Copies files and folders displaying GUI progress bar. .Description This is a script, that demonstrates how PowerShell can use useful .NET types and PowerShell V2 capabilities. .Parameter Path Specifies the filename or FileInfo object representing file to be copied. Objects can be passed through a pipeline. .Parameter Destination Specifies the path for resulting copy operation .Parameter Recurse Gets the items in the specified locations and in all child items of the locations. Used only when source directory passed through argument list. .Parameter Force Creates directory structure in destination folder and copies files to their source respective folders (Tree copy). .EXAMPLE PS > Copy-FilesPlus -Path C:\tmp -Destination e:\Users This will copy only files from C:\tmp to E:\Users .EXAMPLE PS > Get-Item C:\tmp\windows7.iso | Copy-FilesPlus -Destination E:\Users This will copy specified file from C:\tmp folder to e:\Users .EXAMPLE PS > Get-Childitem D:\Shared | Copy-FilesPlus -Destination E:\ This will copy all files from Shared folders to E: drive root directory .EXAMPLE PS > Get-Childitem D:\Shared -Recurse | Copy-FilesPlus -Destination E:\ -Force This will copy all files in Shared folder and subfolders. Shared folder will be a tree root point. All directory structure will be copied with files to destination folder. .EXAMPLE PS > Copy-FilesPlus C:\Users\User E:\ -Recurse This will copy all files from User folder and subfolders to destination directory without copying source folders tree .EXAMPLE PS > Copy-FilesPlus C:\Users\User E:\ -Recurse -Force This will copy all files in User folder and subfolders. User folder will be a tree root point. All directory structure will be copied with files to destination folder. .ReturnValue Genrally, script don't return anything, except errors! .Link about_functions about_functions_advanced about_functions_advanced_methods about_functions_advanced_parameters #Requires -Version 2.0 #> # ну и теперь фишки от advanced functions в V2. CmdletBinding делает # подстановку передаваемых аргументов в функцию. Если аргумент не передан # то PowerShell попросит его ввести, а не вывалится с ошибкой [CmdletBinding()] param ( # первый аргумент. Он является обязательным и он может принимать значения # из конвейера. Причём, внутри блока Process {} для обозначения текущего элемента # можно использовать, как переменную $path, так и $_. [Parameter(Mandatory = $true,ValueFromPipeline = $true)] $Path, [Parameter(Mandatory = $true)] [string]$Destination, [switch]$Recurse, [switch]$Force ) begin { # пробуем создать папку назначения, куда будут копироваться файлы. [void](md $Destination -Force -ea 0) # вот тут я сделал переменную для счётчика. Счётчик мне потребуется для того, # чтобы при использовании ключа -Force и если файлы передаются по конвейеру # можно было брать точку начала дерева структуры, которая будет копироваться. $n = 0 # временная функция, которая выполняет само копирование. Тут нужно учесть то, # что путь назначения должен указываться в полном формате с указанием имени # конечного файла. Относительные пути тут не поддерживаются. Поэтому дальше # в коде я буду сохранять имя оригинального файла. т.е. переименовывание файлов # на лету не поддерживается function _routinecopy_ ([string]$Destination) { process { Add-Type -AssemblyName microsoft.visualbasic [Microsoft.VisualBasic.FileIO.FileSystem]::CopyFile($_, $Destination, [Microsoft.VisualBasic.FileIO.UIOption]::AllDialogs, [Microsoft.VisualBasic.FileIO.UICancelOption]::ThrowException) } } } process { try { # вот здесь я проверяю, откуда пришли файлы - через аргументы или через конвейер # если данные пришли из обоих путей, то приоритет за конвейером if ($_) { # проверяем, что объект существует и что это объект файловой системы $File = gi $Path.FullName -ea stop | ?{$_.PsProvider -match "FileSystem$"} if ($File) { # если объект в порядке и выполняется только первая итерация конвейера # то мы задаём точку начала дерева. Весь путь от этой точки до имени файла # будет копироваться в папку назначения if ($n -eq 0) { # здесь отрезаем от файла структуру папок, которая будет являться границей дерева $RootPoint = $Path.FullName -replace $([regex]::Escape($Path.Name)) # заодно на основе этой структуры делаем регулярное выражение. Этим регулярным # выражением будем у всех последующих файлов отрезать начало и оставлять необходимую # часть дерева $RootRegEx = [regex]::Escape($RootPoint.Substring(0,$RootPoint.Length -1)) # важно, что эту операцию нужно проделать единожды, чтобы точка монтирования дерева # больше не менялась в процессе. Поэтому увеличиваем счётчик и тогда в течении текущего # процесса копирования код сюда не вернётся $n++ } # проверяем, что нужно ли копировать дерево или нет. if ($Force) { # если копируем дерево, то выбрасываем папки и работаем только с файлами $File = $File | ?{!$_.PsIsContainer} if ($File) { # если есть файлы для копирования, то выбираем весь путь папок до текущего файла # и заранее приготовленным регэкспом отрезаем начало. В переменную $rep мы запишем # дерево папок от точки монтирования дерева до имени файла $rep = $Path.Directory.ToString() -replace $RootRegEx # а теперь к папке назначения пристыковываем дерево папок от точки монтирования до имени файла $DestFolder = Join-Path $Destination $rep # заранее создаём начальный хвостик папок в целевой папке и подавляем вывод на экран [void](md $DestFolder -Force -ea 0) # а теперь к новому конечному пути пристыковываем имя файла $Dest = Join-Path $DestFolder $Path.Name # и теперь подаём текущий файл в функцию копирования. Вот тут мы и увидим прогресс-бар. $Path.FullName | _routinecopy_ $Dest } } else { # если структуру папок копировать не надо, то все файлы, что пришли с конвейера будут копироваться # в папку назначения без создания структуры папок. if (!$_.PsIsContainer) { $Dest = Join-Path $Destination $File.Name $File | _routinecopy_ $Dest } } # если объект не существует или это не объект файловой системы (защита от дураков, да-да :)), то ругаемся } else {throw "Input object does not represent any applicable FileSystem object"} } else { # если данные об источнике копирования переданы через аргументы, то проверяем, что заданный путь допустим # и объект, который мы получим после Get-Item является объектом файловой системы $File = gi $Path -ea stop | ?{$_.PsProvider -match "FileSystem$"} if ($File) { # если всё хорошо, то указанный файл или папка становятся точкой монтирования дерева $RootPoint = Resolve-Path $Path # если ключи -Force -Recurse не указаны, то копируется либо указанный файл или все файлы в указанной # папке в папку назначения if (!$Recurse) { dir $RootPoint | ?{!$_.PsIsContainer} | %{$Dest = Join-Path $Destination $_.Name $_.FullName | _routinecopy_ $Dest} # хитрый режим, когда рекурсивно выбираются все файлы в указанной папке и всех подпапках и копируются # в папку назначения без сохранения структуры (т.е. в папке назначения будет большая куча файлов). } elseif ($Recurse -and !$Force) { dir $RootPoint -Recurse | ?{!$_.PsIsContainer} | %{$Dest = Join-Path $Destination $_.Name $_.FullName | _routinecopy_ $Dest} # если указаны оба ключа, то мы повторяем структуру исходных папок относительно точки монтирования дерева # в папке назначения } elseif ($Recurse -and $Force) { dir $RootPoint -Recurse | ?{!$_.PsIsContainer} | %{ # тут мы делаем то же самое, что и в случае, когда файлы пришли с конвейера $RootRegEx = [regex]::Escape($RootPoint) $rep = $_.Directory.ToString() -replace $RootRegEx $DestFolder = Join-Path $Destination $rep [void](md $DestFolder -Force -ea 0) $Dest = Join-Path $DestFolder $_.Name $_.FullName | _routinecopy_ $Dest } } } else {throw "Input object does not represent any applicable FileSystem object"} } } catch {$_} } }Вот такой скриптик у меня получился. Местами даже очень умный, почти как я :-). Как мне кажется, на этом коде тоже можно чему-то поучиться. Если будут вопросы – то welcome в комментарии. :-)
Сегодня самый главный PowerShell Guy – Marc van Orsouw, он же MoW, он же /\/\o\/\/ выпустил очередную версию PowerTab, в которой исправлены баги, которые были замечены в работе с PowerShell V2 CTP3, плюс добавлена поддержка Windows 7 и Windows Server 2008 R2. Один из наиболее значимых багов – зависание окна автозавершения. Это выглядело вот так:
[vPodans] dir -include *.log
[vPodans] ╔═ - ══════════════╗
║ -Debug ║
║ -ErrorAction ║
║ -ErrorVariable ║
║ -Exclude ║
║ -Filter ║
║ -Force ║
║ -Include ║
║ -LiteralPath ║
║ -Name ║
║ -OutBuffer ║
║ -OutVariable ║
║ -Path ║
║ -Recurse ║
║ -UseTransaction ║
║ -Verbose ║
║ -WarningAction ║
║ -WarningVariable ║
╚═[4] 1-17 [17]════╝
т.е. по этому меню можно было перемещаться вниз. Но при любом нажатии стрелки вверх – оно намертво прилипало к экрану:
[vPodans] dir -include *.log
[vPodans] bla-bla-bla═════════════╗
The term 'bla-bla-bla' is not recognized as a cmdlet, function, operable program, or script file. Verify the term and t
ry again. ║ -ErrorAction ║
At line:1 char:12-ErrorVariable ║
+ bla-bla-bla <<<< xclude ║
+ CategoryInfo : ObjectNotFound: (bla-bla-bla:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
║ -Include ║
[vPodans] ║ -LiteralPath ║
║ -Name ║
║ -OutBuffer ║
║ -OutVariable ║
║ -Path ║
║ -Recurse ║
║ -UseTransaction ║
║ -Verbose ║
║ -WarningAction ║
║ -WarningVariable ║
╚═[4] 1-17 [17]════╝
а учитывая, что я частенько промахиваюсь со стрелками, то вот такую картину видел тоже часто. И убрать это можно было только через Clear-Host, он же CLS. Сейчас установил новую версию PowerTab – проблема исчезла :rock:
Ну и поддержка новых систем тоже будет многим по душе.
Собственно PowerTab взять можно тут (смотреть аттачменты посте):
http://thepowershellguy.com/blogs/posh/archive/2009/05/15/powertab-0-99b2-ctp3-fix.aspx
Update 04.09.2009: для защиты от атаки на SRP путём подмены сертификатов цифровой подписи обязательно прочтите обновлённый материал: Защищаем Software Restriction Policies. Т.е. вместо отключения возможности добавления сертификатов в Trusted Publishers, вы можете запрещать пользователям добавлять свои сертификаты в контейнер Trusted Root Certification Authorities.
Update 20.12.2009: пофиксено правило запрета для папки Temp. Вместо переменной %systemroot% используется путь из реестра.
Update 22.04.2010: пофиксен путь реестра для принтеров.
Хорошие новости – сегодня раскроем очередную партию секретов Software Restriction Policies.
Плохие новости – буду срывать покровы и показывать, как ещё можно злонамеренно обходить политику.
Жизнь такая интересная штука, которая любит преподносить сюрпризы, как приятные, так и не очень. Вот и сейчас, казалось бы, считал, что разобрался с вопросом SRP, куда уж дальше? А вот и нет. Давайте по порядку.
1) Возьмём пост: Секреты Software Restriction Policies (часть 2) и список стандартных правил из него. Ни в коем случае в исключениях нельзя использовать переменные окружения, типа %systemroot%, %programfiles%, %userprofile%, etc, поскольку это таит в себе угрозу:
Start –> Run… –> set programfiles=c:\users\username\desktop
и эта строчка перепишет переменную окружения %programfiles% на новое значение. Как можно догадаться, что теперь это исключение в политике будет отрабатывать не на настоящую папку Program Files, а на десктоп пользователя и пользователь сможет запускать оттуда что угодно! И вы ничего с этим не сделаете. Следовательно, эти 2 переменные следует заменить на оригинальные значения (т.е. ключи реестра), если вы использовали переменные окружения, вместо ключей реестра, которые показывают реальный путь до этих папок:
Unrestricted - %HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot%
Unrestricted - %HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ProgramFilesDir%
Но эти 2 переменные – не единственные, которые мы используем. Если у нас доменная сеть, то пользователям нужно разрешать запуск логонных скриптов, которые хранятся в папке NetLogon контроллера домена. Общий вид исключения выглядит как:
Unrestricted - %logonserver%\Netlogon\*.bat
Поскольку папка Netlogon реплицируется между контроллерами домена, то переменная %logonserver% позволяет гарантированно запустить логонный скрипт, даже если остальные контроллеры домена временно недоступны. Но, как я уже показал, переменную %logonserver% можно перенаправить куда угодно и используя это исключение может запускать свои приложения. Чтобы устранить этот недостаток можно пойти двумя путями:
Так же не следует заменять %logonserver% на \\domain.com\netlogon\*.bat, поскольку при разрешении имени домена далеко не факт, что пользователь получит имя и адрес работающего контроллера. В принципе, такой формат будет возвращать имя нужного контроллера, но я не готов ручаться, что это будет работать всегда.
Стало быть, утверждение из предыдущего поста: “следует предельно максимально использовать переменные окружения и ключи реестра вместо абсолютных путей” следует считать частично верным. Т.е. переменные окружения использовать не рекомендуется использовать вообще. А так же не рекомендуется использовать ключи реестра из ветки HKCU, поскольку пользователь может их менять на своё усмотрение.
2) с подсказки коллеги с форума SysAdmins.SU WindowsNT (который тоже активно применяет SRP в своих организациях и занимается исследованием этой темы). Пользователи могут шедулить задания, которые будут исполняться через каждую минуту и ждать, когда администратор временно отключит политику SRP и задание, таки, выполнится! Вот тут я не знаю как быть. Как вариант – дать пользователям Read Only на C:\Windows\Tasks через командную строку (например, через icacls), что запретит пользователям создавать задания. На сколько это хорошо или плохо уже судить не мне, поэтому здесь ничего категорично советовать не буду.
3) SRP бессмысленна с обработкой расширения LNK, поскольку тут таится другая угроза. Я думаю, что многие смотрели на эти исключения, но не видели лазейки. Например, исключение:
Unrestricted - %HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Desktop%*.lnk
Вы думаете, оно разрешит нам запускать только ярлыки с рабочего стола? Наивняк! Я тоже так думал, до вчерашнего дня, когда я отлаживал один скрипт на PowerShell и понял одну вещь. SRP не отличает файл от папки. Создаёте на десктопе папку, например, 1.LNK и из этой папки запускаете что хотите! SRP не отличит, что 1.LNK это папка, а не ярлык.
Я создавал исключения для .LNK по причине, что я не знаю, что это такое. Я знаю, что .LNK только ссылка. А может ли LNK самостоятельно исполнять какой-то код? Мне этого неизвестно. Поэтому я сначала использовал исключения для LNK.
4) так же WindowsNT подсказал другую проблему. Я уже неоднократно говорил об опасностях папки C:\Windows\Temp и папки спулера, а именно – что пользователи имеют право записи и исполнения в этих папках. Но эти папки разрешаются общим правилом SystemRoot, поэтому мы использовали отдельные запреты:
Dissalowed - %HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Print\Printers\DefaultSpoolDirectory%
Dissalowed - %HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\SystemRoot%Temp
и для установки приложений и драйверов мы использовали REG файлы (ссылка на тему – в самом начале поста). Однако, как выяснилось, значение PolicyScope начинает действовать только после перелогона, что усложняет нам жизнь.
Поэтому было принято решение рекомендовать переносить спулер и системный темп за пределы системного каталога. Как вы это сделаете – выбирайте на свой вкус. Самое простое:
Подменить его можно или вручную или стартапным скриптом.
Следовательно REG файлы для временного отключения и включения политики на локальном компьютере нужно отредактировать, а именно – убрать параметры Policy Scope и оставить только Default Level.
5) а теперь самый главный бонус для самых терпеливых, кто дочитал до сюда :-) . Внимание, на экран:
по умолчанию Trusted Publisher Management в SRP выставлен в All administrators and end users (в Windows Vista и Windows Server 2008) или End users в Windows XP/Windows Server 2003. Это поле отвечает за возможность добавления сертификатов в секцию Trusted Publishers пользовательского certificate store. И мало кто обращает на него внимания, поскольку значение этой настройки весьма неоднозначна в интернете и точную формулировку мало кто может дать и эту опцию почти никто не трогает.
А теперь делаем финт ушами:
потребуется .NET Framework SDK или любой инструмент для генерации сертификата. Самое простое – утилита makecert.exe.
открываем командную строку, перемещаемся в папку, где хранится утилита makecert.exe и выполняем команду:
makecert.exe -n "cn=srp" -ss my -eku 1.3.6.1.5.5.7.3.3
этой командой сгенерируется сертификат с OID равным Code Signing. Сертификат хранится в хранилище Current User\Personal.
Открываем оснастку certmgr.msc, переходим в Personal и экспортируем этот сертификат в файл под именем, например, siging.cer. Далее открываем сертификат, переходим на вкладку Certification Path, выделяем Root Agency сертификат, жмём View Certificate –> Details –> Copy to file. Экспортируем корневой сертификат в .CER файл, например, root.cer. Эти сертификаты нам потребуются для обхода SRP.
открываем блокнот и в нём набираем:
msgbox “Hello World!”
сохраняем как script.vbs.
для подписи потребуется утилита signcode.exe из того же SDK. Открываем командную строку, переходим в ней в папку, где хранится signcode.exe и выполняем команду:
signcode.exe -cn "srp" script.vbs
или
signcode.exe -cn "srp" -t http://timestamp.verisign.com/scripts/timstamp.dll script.vbs
эту часть пользователь может выполнить у себя дома. Теперь пользователю нужно доставить оба файла сертификатов и скрипт на рабочий компьютер как угодно. На рабочем компьютере (который защищён SRP) пользователь извлекает на рабочий стол (в любое место, куда ему разрешена запись) VBS файл и открывает оснастку certmgr.msc. В ней он импортирует:
пользователь дважды щёлкает на VBS файле и:
он запускается! Чтобы это сработало важно только добавить сертификат, который использовался при подписи скрипта в Trusted Publishers.
Бороться с этим можно только одним способом. Переставить переключатель в Allow only all administrators to manage Trusted Publishers. Если так сделать, то такой финт ушами уже не получится. Но тут мы сразу потеряем автоматическую установку Windows Update в Windows XP/2003. На сколько я понимаю Windows Update использует эту же лазейку. Т.е. при поступлении обновлений некая служба (вероятно Windows Update) с системными правами добавляет сертификат подписи в Trusted Publishers и инициирует запуск самих апдейтов, которые подписаны этим сертификатом. А апдейты в Windows XP/2003 сначала разжимаются в папку с рандомным именем в корне рандомного диска и устанавливаются. После чего сертификат удаляется из store. В Windows VIsta и выше файлы обновлений уже имеют расширение .MSU и не мониторятся политикой по умолчанию, поэтому в этих системах можно запретить пользователям добавлять сертификаты в Trusted Publishers. Но (не буду утвержать на 100%, но скорее всего это так) мы ещё потеряем возможность использования правил по сертификатам, которые настроены в User Configuration групповой политики, поскольку сертификат из той политики добавляется именно в User Store.
Вот такие дела, вобщем.
В предыдущей части мы поговорили об основных этапах настройки OCSP на сервере CA. Науонец-то мне удалось восстановить работу виртуальных машин и можно продолжить разговор. И сейчас предлагаю поговорить уже о базовой настройке OCSP Responder.
Настройка Online Responder очень проста: Start –> Administrative Tools –> Online Responder Management. И правой кнопкой по Revocation Configuration –> Add Revocation Configuration. Мастер очень простой и понятный, интересно будет на стадии Select Signing Certificate:
fig.1
именно тут нужно ставить галочку Auto-Enroll for an OCSP signing certificate, вместо использования Certificate Autoenrollment. С этой галочкой OCSP будет для себя каждые две недели (по умолчанию) запрашивать новый сертификат. В последнем шаге указываются адреса CRL'ов, по которым OCSP будет сверять сертификаты, а так же период обновления CRL'ов. После этой несложной процедуры, нужно этот сервер указать как Array Controller. Дело в том, что в сети может быть несколько онлайн респондеров для одного CA и они будут образовывать массив респондеров. Но один из них должен стать главным в массиве и остальные члены этого массива будут сверять свою конфигурацию именно с контроллером. Для этого в той же оснастке нужно перейти в Array Configuration, правой кнопкой на вновь созданном сервере и выбрать Set As Array Controller.
В принципе, теперь можно проверять конфигурацию OCSP. Если встать в самый верх дерева консоли (Online Responer: servername), то в центральной части оснастки должна появиться зелёная галочка:
fig.2
и в списке Array Members выделяя каждый сервер внизу должны увидеть сообщение о том, что член массива имеет рабочую конфигурацию и действительный сертификат:
fig.3
Там же вы можете посмотреть сам сертификат, который будет использоваться для подписи OCSP ответов. Если ваша картина соответствует тому, что отображено на скриншотах, то это значит, что вы успешно настроили OCSP. Теперь все издаваемые сертификаты в поле Authority Information Access будут содержать адрес OCSP респондера и клиенты Windows Vista и выше смогут через него проверять статус сертификата. Собственно, как это выглядит:
fig.4
Как видите, там прописан адрес, куда будут направляться OCSP запросы. В качестве бонуса прилагаю трассировку Network Monitor ответа OCSP Responder:
Frame: Number = 10, Captured Frame Length = 2974, MediaType = ETHERNET + Ethernet: Etype = Internet IP (IPv4),DestinationAddress:[00-15-5D-01-02-05],SourceAddress:[00-15-5D-01-02-01] + Ipv4: Src = 192.168.2.11, Dest = 192.168.1.2, Next Protocol = TCP, Packet ID = 11241, Total IP Length = 2960 + Tcp: Flags=...A...., SrcPort=HTTPS(443), DstPort=49800, PayloadLen=2920, Seq=2068515486 - 2068518406, Ack=1096717416, Win=513 (scale factor 0x8) = 131328 - Ssl: Server Hello. Certificate. Certificate Status. - TlsRecordLayer: ContentType: HandShake + Version: TLS 1.0 Length: 4139 (0x102B) - SSLHandshake: SSL HandShake TLS 1.0 Encrypted Handshake Message HandShakeType: ServerHello(0x02) Length: 76 (0x4C) + ServerHello: 0x1 HandShakeType: Certificate(0x0B) Length: 2556 (0x9FC) - Cert: 0x1 CertOffset: 2553 (0x9F9) - Certificates: CertificateLength: 1088 (0x440) - X509Cert: Issuer: contoso-DC2-CA,contoso,com, Subject: dc2.contoso.com,OU,Contoso,Riga,Riga,LV + SequenceHeader: - TbsCertificate: Issuer: contoso-DC2-CA,contoso,com, Subject: dc2.contoso.com,OU,Contoso,Riga,Riga,LV + SequenceHeader: + Tag0: + Version: v3 (2) + SerialNumber: 0x110c0b52000000000013 + Signature: Sha1WithRSAEncryption (1.2.840.113549.1.1.5) + Issuer: contoso-DC2-CA,contoso,com + Validity: From: 05/11/09 17:24:32 UTC To: 03/30/11 14:06:53 UTC + Subject: dc2.contoso.com,OU,Contoso,Riga,Riga,LV + SubjectPublicKeyInfo: RsaEncryption (1.2.840.113549.1.1.1) + Tag3: + Extensions: + SignatureAlgorithm: Sha1WithRSAEncryption (1.2.840.113549.1.1.5) + Signature: - Certificates: CertificateLength: 1459 (0x5B3) + X509Cert: Issuer: Contoso CA,contoso,com, Subject: contoso-DC2-CA,contoso,com HandShakeType: Certificate Status(0x16) Length: 1491 (0x5D3) - CertStatus: 0x1 CertificateStatusType: OCSP Response(0x01) - OcspResponse: OCSPResponseLength: 1487 (0x5CF) + OCSPResponseData: Response has valid confirmations (0); Cert Status = Good; SignatureAlgorithm: Sha1WithRSAEncryption (1.2.840.113549.1.1.5)
Если смотреть в Network Monitor, то запрос клиента в графе протокол будет - SSL, а в графе Description – SSL: Client Hello. В ответе OCSP в графе Description будет – SSL: Server Hello. Certificate. Certificate Status. Эту часть я выделил синим цветом в начале трассировки. Далее, красным я выделил часть, в которой содержится полная информация о проверяемом сертификате. Чуть ниже синим выделил часть, которая содержит всю необходимую информацию о сертификате издателя для проверяемого сертификата (там по сути будет та же информация, что и в красной части, поэтому свёрнуто). Но наиболее полезным для нас будет именно часть, которая выделена зелёным цветом, поскольку именно там будет храниться ответ OCSP. В данном случае сертификат имеет статус Good, т.е. валидный. В противном случае там будет отображено следующее:
+ OCSPResponseData: Response has valid confirmations (0); Cert Status = Revoked; SignatureAlgorithm: Sha1WithRSAEncryption (1.2.840.113549.1.1.5)
я отозвал сертификат, опубликовал Delta CRL и снова промониторил трафик. Браузер, в свою очередь, вежливо предложил покинуть этот сомнительный ресурс.
Как мы успели рассмотреть, конфигурирование OCSP в Windows Server 2008 достаточно простое, хотя и требует от администраторов определённых навыков и умений. Зато в ответ мы получаем достаточно простую схему проверки сертификатов без необходимости скачивания каждый раз списков CRL. Безусловно, я не ставил перед собой задачу полного раскрытия всех аспектов конфигурирования OCSP (читай, срывания покровов), но показать основные ключевые этапы, которые придётся пройти каждому, кто будет настраивать OCSP в своих сетях. Поэтому в конце прилагаю несколько ссылок на более полное и глубокое исследование этого вопроса:
Setting Up Online Responder Services in a Network
Online Responder Installation, Configuration, and Troubleshooting Guide
А знаете ли вы, что скрипты PowerShell можно очень легко и удобно использовать в качестве startup/shutdown и logon/logoff скриптов в GPO?
В обычной жизни при двойном клике на .ps1 файл – он откроется в редакторе, но не будет исполнен. Это было сделано в целях безопасности, что у PS1 файлов PerceivedType выставлен как Text и расширение PS1 отсутствует в переменной %pathext%. Но это совсем не значит, что мы не можем использовать эти скрипты в GPO или Task Sheduler. Ларчик открывается очень просто:
Суть сводится к тому, что в Script Name указывается путь к исполняемому модулю PowerShell. А вот уже в Script Parameters уже указываете путь к скрипту. Причём тут следует обратить внимание, что если путь задаёте через переменные (например, если у вас несколько контроллеров домена, то целесообразно запускать скрипт из папки NetLogon того контроллера, который вас аутентифицирует), то переменные нужно указывать в формате CMD, т.е. %variable%. В результате вы получите вот такой вид настроенного логон-скрипта:
Т.е. реализуется это всё очень просто. Однако, здесь есть одно большое “НО” – для реализации логон-скриптов в среде Windows Server 2003/2008 у вас должна быть реализована политика подписанных скриптов. В противном случае скрипт просто не исполнится, даже если у вас политика запуска скриптов выставлена в Unrestricted. Это обусловлено тем, что скрипт исполняется не с локального диска, а с сетевого. Это можно очень легко проверить:
[vPodans] Set-ExecutionPolicy unrestricted
[vPodans] Get-ExecutionPolicy
Unrestricted
[vPodans] & $env:logonserver\netlogon\get.ps1
Security Warning
Run only scripts that you trust. While scripts from the Internet can be useful, this script can
potentially harm your computer. Do you want to run \\DC1\netlogon\get.ps1?
[D] Do not run [R] Run once [S] Suspend [?] Help (default is "D"):
У вас каждый раз будет спрашиваться разрешение на запуск скрипта. Т.к. логонные скрипты выполняются в фоне и не взаимодействуют с пользователем, то вы просто не сможете никак нажать кнопку R. Тем более, как видно из снимка, у нас нету возможности сделать Run always. Именно по этой причине требуются только подписанные скрипты. Но это не проблема, учитывая, что я у себя в блоге написал 2 поста по практической реализации инфраструктуры подписанных скриптов, тем более, это наоборот повышает безопасность запуска скриптов PowerShell.
Но если очень хочется выполнять логонные и стартапные скрипты без внедрения цифровых подписей, то есть один workaround - узел, на котором размещены скрипты в сети (обычно это сам контроллер домена) нужно добавить в интернет-зону Local Intranet. Тогда скрипты из сети будут равноценны локальным и политика RemoteSigned спокойно разрешит такой запуск.
Пока что Windows Server 2008 R2 и Windows 7 не RTM, но уже известно, что в них уже нативно поддерживаются скрипты PowerShell в качестве логонных и стартапных, поскольку в этих системах PowerShell установлен и включен по умолчанию. И выглядит это вот так:
В табе Scripts располагаются классические скрипты как .BAT, .CMD, .VBS, .JS и в комментарии не нуждаются. Но в новых системах добавлен ещё один таб PowerShell scripts. Вы можете прямо указывать на .PS1 файлы без указания программы, которая будет их отрабатывать. Иными словами эти скрипты теперь ничем не отличаются от тех же скриптов CMD/WSH. Но в проводнике PS1 файлы всё равно не будут исполняться, а открываться в редакторе (ISE/Notepad/PowerGUI). Ну и ещё одна заметка:
Вы можете выбирать в каком порядке эти скрипты будут исполняться – до или после классических скриптов в первом табе. На практике есть один небольшой недостаток – при логоне частенько проскакивает консоль PowerShell, что есть не очень хорошо. Правда, следует учитывать, что новые системы ещё только Release Candidate (скриншоты сделаны с беты), поэтому есть надежда, что это будет исправлено. В отличии от предыдущего варианта, когда скрипты PowerShell адаптируются под классические – здесь не обязательно подписывать скрипты, хотя для этого придётся выставить политику запуска в Unrestricted, что не есть безопасно. Поэтому я бы посоветовал везде, где это возможно – использовать цифровые подписи для скриптов. И ещё раз напомню, что данная вкладка в GPO доступна только в Windows Server 2008 R2/Windows 7 и, скорее всего, в последующих версиях и применяться будет тоже только к ним. Если у вас домен под управлением Windows Server 2008 R2, а клиенты – Windows Vista, то эти логонные скрипты работать не будут, даже если на последних всеми правдами и неправдами :-) установлен PowerShell.
As always enjoy the automation of tools within powershell.exe! © Flowering Weeds