суббота, 25 февраля 2012 г.

PowerShell: CTP или RTM?

Оригинал статьи (на английском) находится здесь.
Не так давно, когда я проводил обучение в группе корпоративных администраторов, ко мне поступил вопрос: "Почему в PowerShell не работает удалённое взаимодействие на Windows XP?". Но ведь я точно знаю, что он делает это (т.е. работает удалённо)! Как выяснилось в последствии - администраторы загрузили "неправильную" версию PowerShell. Как такое могло произойти?
Когда вы ищете в Интернете PowerShell Version 2, то находите тонны статей и ссылок на скачивание. Однако лишь некоторые из них указывают на корректную, финальную "RTM" версию продукта. Многие люди до сих пор пишут в своих блогах о версиях "CTP", которые будучи бета версиями, предшествовали финальной "RTM" версии, обладая при этом ограниченным функционалом. Ситуация усугубляется тем, что в центре загрузки Microsoft Download до сих пор имеются ссылки на "CTP" версии продукта. Т.о. переходя по "неправильной" ссылке, пользователь скачивает версию "CTP", будучи уверенным, что это на самом деле финальная "RTM" версия.
Эта тема была поднята в нашем PowerShell MVP чате и, как следствие, мы стараемся сделать все ссылки на "CTP" версии нерабочими. В то же самое время, мы совместно подкидываем идеи, которые помогут вам идентифицировать, какая же версия PowerShell установлена у вас на самом деле. Этими результатами, объединёнными усилиями MVP, я хотел бы поделиться с вами сегодня.
Версии PowerShell - Напряженное ожидание!
По существу, на сегодняшний день существует две "RTM" версии PowerShell: PowerShell V1, выпущенный в 2006-м году, и PowerShell V2, финальная версия которого была представлена в октябре 2009-го. PowerShell V2 обладает обратной совместимостью по отношению к V1, т.е. код, написанный для версии V1 будет работать и в V2. В дополнении к этому PowerShell V2 предоставляет тонны важнейших новых возможностей, таких, как возможность удалённой работы (запуск программного кода на удалённо размещённой машине), модули ("новая" возможность загружать дополнительные команды), фоновые потоки (асинхронный запуск кода в отдельных потоках) и многое другое. Т.о. переход с V1 на V2 является прекрасной идеей. Обе указанные версии работают в Windows XP и более поздних версиях операционной системы Windows. V1 и V2 не работают совместно, т.о. вы должны установить V2 вместо V1 (если V1 была установлена на вашей машине).
Один очень простой способ узнать, какая версия PowerShell у вас установлена, это посмотреть в PowerShell значение переменной $psversiontable. Если такая переменная не определена, значит вы используете V1. Если переменная присутствует - вы используете V2. Проверить версию можно не прибегая к помощи самого PowerShell, посмотрев в реестре значение параметра HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\PowerShell\1\PowerShellEngine\PowerShellVer.
Обращаем ваше внимание, что PowerShell часто бывает установлен как пакет обновления, т.о. вы не увидите его в списке установленных приложений. Вы увидите его в перечне установленных обновлений. К счастью, финальная версия V2 может быть установлена поверх V1, не требуя, чтобы вы предварительно выполнили деинсталляцию V1. Только устаревшие "CTP" версии продукта потребуют, чтобы вы самостоятельно выполнили предварительное удаление V1, прежде чем приступите к установке V2. Т.о. если при установке V2 вы получаете сообщение о том, что вам сначала требуется вручную удалить V1, то это скорее всего означает, что вы имеете "неправильный" пакет установки.
Начиная с Windows 7 / Server 2008 R2 вы находитесь на безопасной стороне, т.к. эти версии операционной системы уже имеют в своём составе PowerShell V2 версии "RTM".
"CTP"-версия PowerShell V2 является "неправильной"!
Группа разработчиков PowerShell долгое время предоставляла предварительную версию V2, прежде чем выпустила финальную. Предварительная версия значилась как "CTP" (Community Technology Preview). Вы до сих пор можете найти ссылки на CTP1, CTP2 и CTP3. Все эти версии устарели и не должны использоваться на вашей машине (разве что если этого требует бета-версия некоторой другой программы, так же установленной на вашем компьютере). Одна из причин, по которой вы не должны использовать версию "CTP", является то, что вы сможете воспользоваться некоторым функционалом, таким, к примеру, как удалённое взаимодействие в WindowsXP. В качестве других причин можно назвать то, что версии "CTP" не поддерживаются и по прежнему содержат в себе некоторые ошибки, а так же то, что скрипты, созданные на CTP1 могут не работать в финальной версии PowerShell (V2 или более новой).
К сожалению, это не тривиальная задача - определить, используете ли вы финальную версию PowerShell V2, или же одну из её предыдущих "CTP" версий, потому что в этих версиях так же определена переменная $psversiontable. Информация о версиях, возвращаемых переменной $psversiontable может отличаться от одной операционной системы до другой, а так же от одной версии "CTP" до другой. Т.о. если вы хотите получить ответ на основании значения $psversiontable, то вам следует убедиться в том, что значение 'BuildVersion' равно или больше чем 6.0.6002.18111.
Если вы желаете проверить локальную версию вашего PowerShell, то вы можете обернуть логику проверки в функцию, подобную такой:

function Test-PowerShellVersion {
 if (Test-Path variable:psversiontable) {
  $versionPresent = $psversiontable.buildversion
 
  if (($versionPresent.Major -ge 6) -and 
  ($versionPresent.Build -ge 6002) -and 
  ($versionPresent.Revision -ge 18111)) {
  "V2 RTM"
  } 
  else { 
  "V2 CTP Prerelease - Update to V2 RTM!"
  }
 } 
 else {
  "V1 - Update to V2 RTM!"
 }
}
Такой способ совершенно точно укажет вам, используете ли вы RTM версию PowerShell, или же его устаревшую CTP версию.
Подождите минутку - а как я смогу проверить это на всех машинах нашего предприятия?
Конечно, быстрое решение, продемонстрированное мною только что выше, не поможет вам в случае, когда нужно выполнить данную проверку на всех машинах вашей сети. Это поможет только в том случае, если вы будете запускать эту функцию на каждом компьютере. Что если у вас нет доступа к значению переменной $psversiontable, потому что вы не проверяете его скриптом PowerShell на каждой машине?
Оказывается, что 'BuildVersion', получаемое нами через $psversiontable, на самом деле является значением версии которое извлекается из сборки PowerShell. Вы можете получить эту информацию, используя другие языки программирования, путём создания экземпляра PS-объекта и последующего чтения с него значения версии. Такой подход годится для любого, кто захочет извлечь информацию о версии с помощью VB.NET или C#. Вот строка кода на PowerShell, демонстрирующая извлечение информации о версии, описанным нами только что способом:
([psobject].assembly.getcustomattributes(
[reflection.assemblyfileversionattribute], $false)
)[0].version
Если вы просто хотите проверить компьютеры вашей сети, то для этого можете использовать скрипт PowerShell. Т.к. возможность удалённой работы в PowerShell присутствует только начиная с PowerShell V2 RTM, но отсутствует в его CTP версиях и в V1, то для удалённого получение версии файла придётся воспользоваться WMI. Далее продемонстрирован скрипт Test-PSVersion, представляющий собой моё видение по решению данной задачи, а так же содержит множество отдельных вкладов, внесённых нашими MVP. Т.о. наличие этого скрипта не следует воспринимать, как мою единоличную заслугу, т.к. данный код - результат совместного усилия тех, кто присоединился к нашей группе MVP.
Если вы обнаружите ошибки в этом коде, то знайте, что это мои ошибки, т.к. я объединял воедино этот скрипт из многих источников. В таком случае я прошу вас оставить об этом комментарий ниже. Вы можете загрузить функцию отсюда:

function Test-PSVersion {
[CmdletBinding()]
param(
[parameter(Position=0,ValueFromPipeline=$true)]
[ValidateNotNullOrEmpty()]
[String[]]
$ComputerName = @('.'),
 
[Parameter()]
[ValidateNotNull()]
[System.Management.Automation.Credential()]
$Credential = [System.Management.Automation.PSCredential]::Empty
)
process {
 
if (Test-Connection -ComputerName $computername -Count 1 -ErrorAction SilentlyContinue) {
try {
$OS = Get-WmiObject -Namespace root\CIMV2 -Class Win32_OperatingSystem `
-ComputerName $computername -Credential $credential -ErrorAction SilentlyContinue
if ($OS) {
$path = "$($OS.SystemDirectory -replace '\\','\\')\\WindowsPowerShell\\v1.0\\powershell.exe"
$OSName = $OS.Name.Split('|')[0]
$query = "SELECT Version FROM CIM_DataFile WHERE Name = '$path'"
$PSEXE = Get-WmiObject -Query $query -ComputerName $computername -Credential $credential
if ($PSEXE.Version) {
$buildversion = $PSEXE.Version.Split()[0]
$versionPresent = [version]$buildversion
$versionRequired = [version]'6.0.6002.18111'
if ($versionPresent -ge $versionRequired) {
$psversion = "V2 RTM"
} elseif ($versionPresent.Major -ge 6) {
$psversion = "V2 CTP Prerelease - Update to V2 RTM!"
} else {
$psversion = "V1"
}
 
New-Object PSObject -Property @{
ComputerName=$OS.__SERVER;
BuildVersion=[version]$buildversion
Version=$psversion;
Status=$true;Description='OK';
OSName = $OSName
 
}
} else {
New-Object PSObject -Property @{
ComputerName=$computername[0];
BuildVersion=[version]$null;
Version='n/a';
Status=$false;
Description='Unable to access OS information via WMI.';
OSName = 'n/a'
}
}
}
} 
catch {
New-Object PSObject -Property @{
ComputerName=$computername[0];
BuildVersion=[version]$null;
Version='n/a';
Status=$false;
Description=($_.Exception.Message);
OSName='n/a'
}
continue
} 
 
} else {
New-Object PSObject -Property @{
ComputerName=$computername[0];
BuildVersion=[version]$null;
Version='n/a';
Status=$false;
Description='Computer did not respond to ping, skipped.';
OSName='n/a'
}
}
}
}
 
"localhost", "pc77", "localhost", "storage1" | 
Test-PSVersion

Вы можете запускать этот скрипт без конвейра, либо как конвейр, передавая в качестве исходных данных перечень компьютеров, подлежащих проверке. Вы можете запустить Get-Content и прочитать содержимое списка имён компьютеров и направить результат в Test-PSVersion.
В результате вы получите результат, подобный этому:

Version : V2 RTM
OSName : Microsoft Windows 7 Ultimate
Status : True
ComputerName : DEMO5
Description : OK
BuildVersion : 6.1.7600.16385
 
Version : n/a
OSName : n/a
Status : False
ComputerName : pc77
Description : Computer did not respond to ping, skipped.
BuildVersion :
 
Version : V2 RTM
OSName : Microsoft Windows 7 Ultimate
Status : True
ComputerName : DEMO5
Description : OK
BuildVersion : 6.1.7600.16385
 
Version : V2 RTM
OSName : Microsoft Windows Server 2003 for Small Business Server
Status : True
ComputerName : STORAGE1
Description : OK
BuildVersion : 6.0.6002.18139

Заключение
Настало время проверить вашу версию PowerShell! Убедитесь, что вы не используете CTP версию (если у вас нет объективных причин использовать именно её). И если вы обнаружите, что используете V1, подумайте об обновлении до V2 RTM.
От лица всех представителей MVP PowerShell я надеюсь, что кодом и примерами, приведёнными в данной статье, мы смогли предоставить вам полезные инструменты, которые вы сможете использовать. Существует множество ссылок, откуда вы можете скачать PowerShell V2 RTM. Например здесь вы можете прочитать о системных требованиях PowerShell V2 RTM и скачать ту версию, которая подходит для вашей машины. Я считаю эту информацию актуальной и полезной.
Развлекайтесь, и не упустите PowerShellPlus (прим. переводчика: сторонний, платный продукт)! Вы уже пробовали эту версию?

Комментариев нет: