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

Archive for Ноябрь 2012

  1. Создание ускорителей(Accelerators) в PowerShell V3
  2. Поддержка V3 в Windows Server Core 2008 R2
  3. Тип bool в WMI
  4. Не очень ясное поведение Uninstall-WindowsFeature
  5. Почему Get-ChildItem в PowerShell V3 стал еще медленнее
  6. Актуальные версии помощи
  7. Печать диапазона страниц в Word
  8. Изменение поведения Register-EngineEvent при использвании источника события Exiting
  9. Получить UUID компьютера
  10. Автоматическое сохранение в  PowerShell Ise
  11. Удаление System Restore Point
  12. Проверка пароля пользователя
  13. Получить путь родительского объекта symlink
  14. Одна из проблем с GUI скриптами при переходе c PowerShell V2 на PowerShell V3

1. Создание ускорителей(Accelerators) в PowerShell V3

В своей заметке “Новинки PowerShell V3 часть 3”,я описывал ,как получить и создать ускорители в PowerShell V3.С выходом RTM версии ситуация изменилась и теперь потребуется другая техника. в связи с изменением внутренней структуры.

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

[psobject].assembly.gettype("System.Management.Automation.TypeAccelerators")::Get

Для создания и удаления:

$acceleratorsType = [type]::gettype("System.Management.Automation.TypeAccelerators")
$acceleratorsType::Add("accelerators", $acceleratorsType)
$ArcSegment  = [type]::gettype("System.Windows.Media.ArcSegment")

# Создание
[accelerators]::Add(‘ArcSegment’,$ArcSegment)

# Убедимся,что ускоритель был добавлен
[accelerators]::get

# Удалить

[accelerators]::Remove(‘ArcSegment’)

Более подробно можно посмотреть модуль — Reflection Module 4.0 by Joel Bennett.

2. Поддержка V3 в Windows Server Core 2008 R2

Для этого требуется установить Service Pack 1 и .Net 4.0.

3. Тип bool в WMI

При использовании типа bool с WMI/CIM,можно заменить отличие от .Net.

“Boolean” в CIM / WMI может содержать 3 значения: bool:null, bool:true, bool:false.

“Boolean” в .NET содержит 2 значения: bool:true и bool:false.

4. Не очень ясное поведение Uninstall-WindowsFeature

Попробуем удалить несуществующую службу.

PS > Uninstall-WindowsFeature IamNotExists –Verbose
VERBOSE: Uninstallation started…
Uninstall-WindowsFeature : ArgumentNotValid: The role, role service, or feature name is not valid: ‘IamNotExists’. The name was not found.
At line:1 char:1
+ Uninstall-WindowsFeature IamNotExists –Verbose
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (IamNotExists:String) [Uninstall-WindowsFeature], Exception
    + FullyQualifiedErrorId : NameDoesNotExist,Microsoft.Windows.ServerManager.Commands.RemoveWindowsFeatureCommand

Success Restart Needed Exit Code      Feature Result
——- ————— ———      —————
False   No             InvalidArgs    {}
VERBOSE: Uninstallation succeeded.

Как видим получаем ошибку,но и "VERBOSE: Uninstallation succeeded",по словам разработчиков это  не очень красивы вывод,что будет исправлено в следующем релизе.

5. Почему Get-ChildItem в PowerShell V3 стал еще медленнее

Командлет Get-ChildItem всегда не радовал своей скоростью работы,но в PowerShell V3,скорость работы может упасть в разы. Поэтому во многих случаях используют .Net или команду из cmd:

  • cmd /c dir  /s /b
  • Скажем в случае получения только подпапок,часто встречаем конструкцию вида :

Get-ChildItem folder –Recurse | Foreach {!$_.PsIsContainer} ,для ускорения,можно воспользоваться .Net GetDirectories,с одним большим НО не должно быть ссылок и при возникновении исключения  Access Denied  возникает Terminate Error ,и исполнение останавливается  ,в случае ссылок  произойдет зацикливание,а в случае с хорошо знакомой нам конструкцией такого не возникает.

(gi C:\Windows).GetDirectories("*.*","AllDirectories")

В связи с изменением устройства командлета Get-ChildItem, мы можем получить падение производительности,но с другой стороны стало удобнее.

# В PowerShell V2 рекурсивный поиск не производится,только в текущей папке
PS >  Get-ChildItem 1.csv -recurse
    Directory: C:\Test
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        17.11.2012     11:50         70 1.csv

# В PowerShell V3 используется рекурсивный поиск
PS >  Get-ChildItem 1.csv -recurse
    Directory: C:\Test\1\2

Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        17.11.2012     11:50         70 1.csv

    Directory: C:\Test
Mode                LastWriteTime     Length Name
----                -------------     ------ ----
-a---        17.11.2012     11:50         70 1.csv

Для получения аналогичного результата в PowerShell V2  — Get-ChildItem . 1.csv –recurse

В PowerShell V3 происходит проверка, является ли элемент каталогом. Если так, получаем список содержимого в этом каталоге. Если это файл, получаем  этот файл. Если файл не существует, тогда  рекурсивно перечислим его родительский каталог в поисках файлов или дочерний каталог. Это  алгоритм рекурсии  используется в cmd.exe команда dir.

В связи с этим,будет наблюдаться падение производительности,если корневая папка отсутствует,пока не будет произведен поиск до конца.

Зато подобный синтаксис позволяет(на примере dir c:\*.txt –rec и dir C:\file.txt –rec)

  • Производить поиск в текущей папке и всех ее подпапок на наличие текстовых файлов
  • Производить поиск в конкретной папке и всех ее дочерних подпапок на наличие текстовых файлов
  • Аналогично для file.txt

Более наглядный пример с потерей производительности,можно посмотреть на — Serious Get-ChildItem performance degradation in v3 by Kirk Munro. В примере потеря скорости наблюдается в 1300 раз,если корневая папка отсутствует,пока не будет произведен поиск до конца. Поэтому рекомендуется сначала протестировать существование объекта с помощью Test-Path и уже воспользоваться Get-ChildItem.

6. Актуальные версии помощи

В связи с новой системой обновления помощи с использованием командлета Update-Help в ведено понятие версий(подробнее о обновлении about_Updatable_Help). На сайте technet можно посмотреть актуальные версии помощи — Updatable Help Status.

Updated: November 12, 2012

ModuleName Locales Version
AppLocker en-US 3.1.0.0
ClusterAwareUpdating en-US 3.1.0.0
Microsoft.WSMan.Management en-US 3.2.0.0
NetSwitchTeam en-US 3.0.0.0

Для сравнения можно воспользоваться функцикй Get-HelpInfo — PS V3 by Oisin Grehan.

PS >  get-helpinfo | ft -AutoSize

ModuleName        UICulture Installed Available
----------        --------- --------- ---------
CimCmdlets        en-US     3.0.0.0   3.0.0.0
ISE               en-US     3.0.0.0   3.0.0.0
PSScheduledJob    en-US     3.1.0.0   3.1.0.0
PSWorkflow        en-US     3.2.0.0   3.2.0.0
PSWorkflowUtility en-US     3.0.0.0   3.0.0.0

Как происходит обновление с использованием Update-Help:

  1. Finds all of the modules that are installed on your computer (in the value of the PSModulePath environment variable) plus those in the current session.
  2. Finds the online location of Help files for each module.
  3. Checks to see if you have the latest Help files for the module on your computer. 
  4. Downloads the newest Help files if you don’t have them.
  5. Unpacks the Help files (they’re in CAB files).
  6. Verifies the XML and file types for security.
  7. Installs them in the language-specific subdirectory of the module directory.

Теперь у модулей,которые можно обновить с использованием Update-Help есть свойство – HelpInfoUri,указывающее на внешний источник,который содержит требуемые файлы.

PS >  dir $pshome\*HelpInfo.xml | ft name

Name
----
Microsoft.PowerShell.Core_00000000-0000-0000-0000-000000000000_HelpInfo.xml
Microsoft.PowerShell.Diagnostics_ca046f10-ca64-4740-8ff9-2565dba61a4f_HelpInfo.xml
Microsoft.PowerShell.Host_56d66100-99a0-4ffc-a12d-eee9a6718aef_HelpInfo.xml
Microsoft.PowerShell.Management_eefcb906-b326-4e99-9f54-8b4bb6ef3c6d_HelpInfo.xml
Microsoft.PowerShell.Security_a94c8c7e-9810-47c0-b8af-65089c13a35a_HelpInfo.xml
Microsoft.PowerShell.Utility_1da87e53-152b-403e-98dc-74d7b4d63d59_HelpInfo.xml
Microsoft.WSMan.Management_766204a6-330e-4263-a7ab-46c87afc366c_HelpInfo.xml

Update-Help ищет на локальном комьютере файлы *HelpInfo.xml в которых содержится версия.

PS > gc $PSHOME\modules\PSScheduledJob\*helpinfo.xml

<?xml version="1.0" encoding="utf-8"?>
<HelpInfo xmlns="http://schemas.microsoft.com/powershell/help/2010/05">
  <HelpContentURI>http://go.microsoft.com/fwlink/?LinkID=223911</HelpContentURI>
  <SupportedUICultures>
    <UICulture>
      <UICultureName>en-US</UICultureName>
      <UICultureVersion>3.1.0.0</UICultureVersion>
    </UICulture>
  </SupportedUICultures>
</HelpInfo>

PS C:\ > dir $PSHOME\modules\PSScheduledJob\*helpinfo.xml | 
    select-xml -Namespace $HelpInfoNamespace -XPath "//helpInfo:UICulture" | foreach {$_.Node}

UICultureName                                               UICultureVersion
-------------                                               ----------------
en-US                                                       3.1.0.0

Более подробно:

7. Печать диапазона страниц в Word

Требуется распечатать диапазон страниц с 5 по 10. Основную работу выполняет метод printout с описанием параметров.Главное учесть,что требуется указать все значения до требуемого параметра(т.е в данном примере нам требуется параметр Pages,поэтому и указываем Background,Append,Range,OutputFileName,From,To,Item,Copies)

$BackGround = 1
$Append     = 0
$Range      = 4
$Item       = 0
$Copies     = 1
#5-10
$Pages      = "5-9"

$Missing = [System.Reflection.Missing]::Value
$wd = New-Object -ComObject Word.Application
$doc = $wd.Documents.Open("C:\Files\Document.docx")
$doc.printout([ref]$BackGround, [ref]$Append, [ref]$Range, [ref]$Missing,[ref]$Missing,
    [ref]$Missing,[ref]$Item,[ref]$Copies,[ref]$Pages)
$doc.Quit()

8. Изменение поведения Register-EngineEvent при использвании источника события Exiting

В PowerShell V2 появился командлет Register-EngineEvent,который создает подписку на события, создаваемые обработчиком Windows PowerShell. При задании источника событий –SourceIdentifier  Exiting, что при завершении Windows PowerShell выполнялась команда. В PowerShell V2 событие Exiting возникало,только при использовании ключевого слова exit, при нажатии на кнопку Close(“X”) событие не возникало. Данное поведение было исправлено в PowerShell V3.

Register-EngineEvent -sourceIdentifier PowerShell.Exiting -action {Get-Process | add-content processLog.txt }

9. Получить UUID компьютера

(Get-WmiObject Win32_ComputerSystemProduct).UUID

10. Автоматическое сохранение в PowerShell Ise

AutoSaveMinuteInterval

Этот параметр является новым в PowerShell ISE v3 и  используется для задания интервала для автоматического сохранения скриптов. Эта функция не сохраняет автоматически файл, но он позволяет автоматического восстановливать несохраненные файлы в случае отказа ISE или непредвиденных ошибок. Это свойство принимает значение Int16, в диапазоне -32768 до 32767. Следующий параметр установить интервал авто сохранения в одну минуту.

$psISE.Options.AutoSaveMinuteInterval = 1

Установка отрицательное значения отключит функцию автосохранения ISE и способность восстановить несохраненные файлы в случае аварии.

Подобный функционал реализуется через Restart Manager API.

Про другие опции и улучшения — PowerShell v3 ISE and ISE scripting model changes & improvements

11. Удаление System Restore Point

В PowerShell V2 появился набор командлетов для управления System Restore Point, но нет возможности удалять точки. Для этого потребуется WinApi функция SRRemoveRestorePoint.

Пример скрипта удаления точек старше 14 дней:

$point = Add-Type  -memberDefinition @"
                [DllImport("Srclient.dll")]
                public static extern int SRRemoveRestorePoint(int index);
"@ -Name Win32 -NameSpace System -PassThru

$w = (Get-Date).AddDays(-14)
$mdtc = [Management.ManagementDateTimeConverter] -as [type]

Get-ComputerRestorePoint | Where {$mdtc::ToDateTime($_.CreationTime) -lt $w} | 
    Foreach {$point::SRRemoveRestorePoint($_.SequenceNumber)

12. Проверка пароля пользователя

Проверка стандартного пароля у пользователя в Active Directory. В .Net 2.0 можем использовать:

# Запрос учетных данных
$cred = Get-Credential 
$username = $cred.username
$password = $cred.GetNetworkCredential().password

# Пробуем произвести подключение
$Domain = "LDAP://DC=contoso,DC=com"
$ds = New-Object System.DirectoryServices.DirectoryEntry($Domain,$UserName,$Password)

if ($ds.name){
    "Success"
}
else {
    "Failed"
}

В  .Net 3.5 появился метод PrincipalContext.ValidateCredentials:

$cred = Get-Credential
Add-Type -assemblyname system.DirectoryServices.accountmanagement
$DS = New-Object System.DirectoryServices.AccountManagement.PrincipalContext("Domain") 
$DS.ValidateCredentials($cred.UserName, $cred.GetNetworkCredential().password)

13. Получить путь родительского объекта symlink

Самый простой использовать команду dir в cmd.exe.

PS >  cmd /c dir D:\ /AL

Volume in drive D is Новый том

Volume Serial Number is 1AAB-1B76

Directory of D:\

18.11.2012  19:08    <SYMLINKD>     2 [D:\1]

Метод является не очень удобным,для решения воспользуемся функцией GetFinalPathNameByHandle ,код на C# заимствован у

http://chrisbensen.blogspot.ru/2010/06/getfinalpathnamebyhandle.html :

param (
    $path
)

Add-Type -MemberDefinition @"
private const int FILE_SHARE_READ = 1;
private const int FILE_SHARE_WRITE = 2;

private const int CREATION_DISPOSITION_OPEN_EXISTING = 3;
private const int FILE_FLAG_BACKUP_SEMANTICS = 0x02000000;

[DllImport("kernel32.dll", EntryPoint = "GetFinalPathNameByHandleW", 
    CharSet = CharSet.Unicode, SetLastError = true)]
public static extern int GetFinalPathNameByHandle(IntPtr handle, 
    [In, Out] StringBuilder path, int bufLen, int flags);

[DllImport("kernel32.dll", EntryPoint = "CreateFileW", 
    CharSet = CharSet.Unicode, SetLastError = true)]
public static extern SafeFileHandle CreateFile(string lpFileName, 
    int dwDesiredAccess, int dwShareMode,
IntPtr SecurityAttributes, int dwCreationDisposition, 
    int dwFlagsAndAttributes, IntPtr hTemplateFile);

public static string GetSymbolicLinkTarget(System.IO.DirectoryInfo symlink)
{
    SafeFileHandle directoryHandle = CreateFile(symlink.FullName, 
        0, 2, System.IntPtr.Zero, 
        CREATION_DISPOSITION_OPEN_EXISTING, 
        FILE_FLAG_BACKUP_SEMANTICS, System.IntPtr.Zero);
        
    if(directoryHandle.IsInvalid)
    throw new Win32Exception(Marshal.GetLastWin32Error());

    StringBuilder path = new StringBuilder(512);
    int size = GetFinalPathNameByHandle(directoryHandle.DangerousGetHandle(),
        path, path.Capacity, 0);
    if (size<0)
    throw new Win32Exception(Marshal.GetLastWin32Error());
    if (path[0] == '\\' && path[1] == '\\' && path[2] == '?' && path[3] == '\\')
    return path.ToString().Substring(4);
    else
    return path.ToString();
}
"@ -Name Win32 -NameSpace System -UsingNamespace System.Text,`
    Microsoft.Win32.SafeHandles,System.ComponentModel

$dir = Get-Item $path 
[System.Win32]::GetSymbolicLinkTarget($dir)

14. Одна из проблем с GUI скриптами при переходе c PowerShell V2 на PowerShell V3

Для примера возьмем скрипт  — http://technet.microsoft.com/en-us/library/ff730941.aspx . Данный скрипт  работает в V2,но V3 нет. Для этого явно надо задать область(script,global):

$OKButton.Add_Click({$global:x=$objTextBox.Text;$objForm.Close()})

PS. Является багом, т.к. нарушена обратная совместимость с предыдущими версиями.Подобные проблемы можно наблюдать и в использовании делегатов.

PS >  $i=0;[Regex]::Replace(‘A+B+C+D’,’\+’,{($global:i++)})

A0B1C2D

PS  >  $i=0;[Regex]::Replace(‘A+B+C+D’,’\+’,{($i++)})

A0B0C0D

 

Реклама

Read Full Post »