Немного переименовал,может быть, не очень информативную название темы “Q&A”. В данной порции примеров приведу в основном о PowerShell V3,WMI,Active Directory и их применение.
-
Как определить время старта и окончания Job в PowerShell V3?
-
Как отправить почтовое сообщение на нестандартный порт в PowerShell V3?
-
Какое новое свойство добавлено ко всем WMI объектам в PowerShell V3?
-
Какие новые параметры появились у командлета Get-Command в PowerShell V3?
-
Какую новую область видимости добавили в PowerShell V3?
-
Как использовать удаленные Com объекты ?
-
Почему Invoke-WmiMethod и [wmiclass] ведут себя по разному?
-
Какой метод .Net используется в Set-WMIInstance для создания экземпляров?
-
Как создать отсортированный hashtable?
-
Как найти distinguishedname объекта по objectGuid?
1. Как определить время старта и окончания Job в PowerShell V3?
В версии PowerShell V3 добавились требуемые нам свойства,что облегчает определить продолжительность выполнения Job.
PS >$job = Start-Job {"Hello"}
PS >$job |Format-List *
PSBeginTime :3/28/2012 10:12:29 AM
PSEndTime :3/28/2012 10:12:31 AM
2. Как отправить почтовое сообщение на нестандартный порт в PowerShell V3?
В версии PowerShell V3 разработчики добавили параметр “Port“ для комадлета Send-MailMessage.
Пользователи,которые работают с Gmail указывают порт 587,т.к в PowerShell V2
не было параметра “Port“, требовалось использовать .Net функционал.
Send-MailMessage -SmtpServer smtp.test.com -From test@test.com -To user@user.com `
-Subject 'Test 587 Port' -Port 587 -Credential test@test.com -Body "Works" –UseSsl
Для версии PowerShell V2:
$EmailFrom = "test@test.com"
$EmailTo = "user@user.com"
$Subject = "Test 587 Port"
$SMTPServer = "smtp.test.com"
$SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer, 587)
$SMTPClient.EnableSsl = $true
$SMTPClient.Credentials = New-Object System.Net.NetworkCredential("username", "password");
$SMTPClient.Send($EmailFrom, $EmailTo, $Subject, $Body)
3. Какое новое свойство добавлено ко всем WMI объектам в PowerShell V3?
AliasProperty — свойство, определяющее новое имя существующего свойства
Здесь мы видим,что добавили новое свойство PSComputerName типа AliasProperty,
которое ссылается на значение __SERVER. Что удобно будет использовать в Advanced Functions.
PS > [wmi]"" | Get-Member
TypeName: System.Management.ManagementObject#\
Name MemberType Definition
---- ---------- ----------
PSComputerName AliasProperty PSComputerName = __SERVER
4. Какие новые параметры появились у командлета Get-Command в PowerShell V3?
В версии PowerShell V3 к командлету Get-Command добавились 4 новые параметра.
-CommandCapability<FlagsExpression<CommandCapability>>
Получает только команды с указанными возможностями. Допустимыми значениями являются Cmdlet, Script, Workflow, CIM, ScriptFile, Application, and Unknown.
Свойство Capability команды указывает, что команда может сделать и как это можно использовать.Например, простые функции обладают возможностями Script, принимая во внимание, что расширенные функции имеют возможности Script и Cmdlet.
-ListImported
Получает только команды в текущей сессии.
Начиная с Windows PowerShell 3.0, по умолчанию, Get-Command получает все доступные команды, не ограничиваясь, только командами в текущей сессии.
-ParameterName<String[]>
Получает сведения только о командах в сессии с указанным именем параметра. Wildcard поддерживаются.
-ParameterType<PSTypeName[]>
Получает сведения только о командах в сессии с указанным типом параметра.Введите полное имя или часть имени типа параметра. Wildcard поддерживаются.
С параметром CommandCapability мне не очень пока ясно. В основном,за исключением Cmdlet(но не Cmdlet,Script) и Application, можно посмотреть исходный код, свойство ScriptBlock.
Значением Unknown, тоже не очевидно.
PS > Get-Command -CommandCapability Unknown
Capability Name ModuleName
---------- ---- ----------
Unknown Add-ProvisionedAppxPackage Dism
Unknown Apply-WindowsUnattend Dism
Unknown Begin-WebCommitDelay WebAdministration
Unknown End-WebCommitDelay WebAdministration
Unknown gcai -> CimCmdlets
Unknown gcim -> CimCmdlets
В основном это командлеты и альясы, но причем, как-то выборочно. Эти модули по умолчанию не импортированы в текущую сессию. После импортирования они уже будут корректно определяться. Так же видим, gcai –> (в данном случае это альяс из модуля CimCmdlets, но на что он ссылается, будет доступно только после импортирования модуля).
PS > Get-Command Add-ProvisionedAppxPackage
Capability Name ModuleName
---------- ---- ----------
Cmdlet Add-ProvisionedAppxPackage Dism
PS > Get-Command gcai
Capability Name ModuleName
---------- ---- ----------
Cmdlet gcai -> Get-CimAssociatedInstance
Примеры:
#Получить все команды у которых есть параметр Credential
Get-Command -ParameterName Credential
#Получить все команды у которых есть параметр Name типа String
Get-Command -ParameterName Name -ParameterType String
#Получить все команды в текущей сессии
Get-Command -ParameterName Credential
Для версии PowerShell V2 ,для поиска параметров с определенным именем, можно воспользоваться Get-Help или Get-Command.
Get-Help * -Parameter Name
Get-Command * -CommandType Cmdlet | Where {$_.Parameters["Name"]}
5. Какую новую область видимости добавили в PowerShell V3?
Using:
Указывает на локальную переменную. Используйте область видимости Using для удаленных команд, чтобы указать, что переменная находится в локальной сессии. По умолчанию, переменные в удаленных командах считаются определенными в удаленной сессии.
В версии PowerShell V2 для передачи параметра в scriptblock (можно локально ), приходилось использовать ключевое слово param.
# Получить все процессы s* на удаленном компьютере
Invoke-Command -ComputerName localhost -ScriptBlock { param($name) Get-Process $name } -Arg "s*"
Особенно часто ошибка возникает,когда функцию определяют в локальной сессии, а хотят использовать в удаленной.
#Ошибка
Function Get-ProcName
{
Get-Process | Foreach {$_.Name}
}
Invoke-Command -ComputerName localhost -ScriptBlock { Get-ProcName}
PS > Invoke-Command -ComputerName localhost -ScriptBlock { Get-ProcName}
The term 'Get-ProcName' is not recognized as the name of a cmdlet, function, script file, or operable program. Check
the spelling of the name, or if a path was included, verify that the path is correct and try again.
Т.к Function это тот же scriptblock, для избежание ошибки, можно использовать множество вариантов, приведу один из:
$sb = {
Function Get-ProcName
{
Get-Process | Foreach {$_.Name}
}
Get-ProcName
}
Invoke-Command -ComputerName localhost -ScriptBlock $sb
В версии PowerShell V3 для этого воспользуемся Using .
# Получить все процессы s* на удаленном компьютере
$name = “s*”
Invoke-Command -ComputerName localhost -ScriptBlock {Get-Process $using:name}
Using предназначено для переменных и нет смысла использовать для функций, т.к в конечном итоге будет исполняться scriptblock, а мы и так легко можем передать его командлету Invoke-Command.
Invoke-Command -ComputerName localhost -ScriptBlock {Invoke-Expression ${using:function:Get-ProcName}}
6. Как использовать удаленные Com объекты ?
Для создания удаленного экземпляра Com объекта воспользуемся .Net функционалом.
#ProgId например hnetcfg.fwpolicy2
[System.Activator]::CreateInstance([type]::GetTypeFromProgID("ProgId", "ComputerName"))
Зарегистрированные ProgId в системе,можно найти с помощью:
Get-WmiObject Win32_ClassicCOMClassSetting | Where {$_.ProgId} | Format-Table ProgId
7. Почему Invoke-WmiMethod и [wmiclass] ведут себя по разному?
Пример объяснения приведу на WMI классе MicrosoftDNS_ResourceRecord и методе CreateInstanceFromTextRepresentation.
Синтаксис метода CreateInstanceFromTextRepresentation:
void CreateInstanceFromTextRepresentation(
[in] string DnsServerName,
[in] string ContainerName,
[in] string TextRepresentation,
[out, ref] MicrosoftDNS_ResourceRecord &RR
);
Теперь создадим DNS запись типа TXT используя [wmiclass]:
#Имя Dns сервера
$DnsServerName = "dc1.contoso.com"
#Имя зоны , где создать запись
$ContainerName = "contoso.com"
#Текстовое представление записи, если значение содержит пробелы, заключить в двойные кавычки
$TextRepresentation = "testtxt.contoso.com IN TXT ""This is a text"""
#Создадим wmi объект
$wmi = [wmiclass]"root\MicrosoftDNS:MicrosoftDNS_ResourceRecord"
#Выполним метод CreateInstanceFromTextRepresentation
$wmi.CreateInstanceFromTextRepresentation(
$DnsServerName,
$ContainerName,
$TextRepresentation
)
Для определения,какие параметры принимает метод CreateInstanceFromTextRepresentation, можно воспользоваться:
PS > $wmi.CreateInstanceFromTextRepresentation.OverloadDefinitions
System.Management.ManagementBaseObject CreateInstanceFromTextRepresentation(
System.String DnsServerName,
System.String ContainerName, System.String TextRepresentation
)
С [wmiclass] проблем не возникает при создании записи. Попробуем использовать Invoke-WmiMethod и получаем ошибку.
PS > Invoke-WmiMethod -Namespace "root\MicrosoftDNS" -Class MicrosoftDNS_ResourceRecord `
>> -Name CreateInstanceFromTextRepresentation -argumentlist $DNSServer,$ContainerName,$TextRepresentation
Invoke-WmiMethod : Invalid parameter
At line:1 char:1
+ Invoke-WmiMethod -Namespace "root\MicrosoftDNS" -Class MicrosoftDNS_ResourceRec ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [Invoke-WmiMethod], ManagementException
+ FullyQualifiedErrorId : InvokeWMIManagementException,Microsoft.PowerShell.Commands.InvokeWmiMethod
Данная ошибка не очень информативная, синтаксис с виду правильный, но не работает. Проблема в том,что Invoke-WmiMethod используем свой порядок входных параметров и внутри использует .Net метод GetMethodParameters.
PS > $wmi.GetMethodParameters("CreateInstanceFromTextRepresentation")
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 3
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
ContainerName :
DnsServerName :
TextRepresentation :
Здесь хорошо видно,что порядок входных параметров должен быть – ContainerName,DnsServerName,TextRepresentation. Что отличается от синтаксиса,который в msdn или при CreateInstanceFromTextRepresentation.OverloadDefinitions .
Выполним Invoke-WmiMethod с корректным порядком входных параметров:
PS > invoke-wmimethod -Namespace "root\MicrosoftDNS" -Class MicrosoftDNS_ResourceRecord `
>> -Name CreateInstanceFromTextRepresentation -argumentlist $ContainerName,$DNSServer,$TextRepresentation
__GENUS : 2
__CLASS : __PARAMETERS
__SUPERCLASS :
__DYNASTY : __PARAMETERS
__RELPATH :
__PROPERTY_COUNT : 1
__DERIVATION : {}
__SERVER :
__NAMESPACE :
__PATH :
RR : MicrosoftDNS_TXTType.RecordData="\"This is a text\"",RecordClass=1,DnsServerName="DC1.contoso.
com",ContainerName="contoso.com",DomainName="contoso.com",OwnerName="testtxt.contoso.com"
Командлет Invoke-WmiMethod, отработал, как полагается.
8. Какой метод .Net используется в Set-WMIInstance для создания экземпляров?
Данный командлет использует .Net метод CreateInstance — ((ManagementClass) instance.InputObject).CreateInstance();. Не все классы поддерживают создание экземпляра, хотя с виду и создают его.
Приведу пример с WMI классом MicrosoftDNS_ResourceRecord
# Получим ошибку,т.к данный класс не поддерживает создания записей таким способом, используйте метод CreateInstanceFromTextRepresentation
Set-WMIInstance -Namespace root\MicrosoftDNS -class MicrosoftDNS_ResourceRecord -argument @{
DnsServerName = $DNSServer;
ContainerName = $Domain;
DomainName = $Domain;
OwnerName = $CN;
RecordClass=1;
RecordData = $TXT;
TTL = 3600;
TextRepresentation = $TextRepresentation;
Timestamp = 0
}
PS > $wmi.CreateInstance()
__GENUS : 2
__CLASS : MicrosoftDNS_ResourceRecord
__SUPERCLASS : CIM_LogicalElement
__DYNASTY : CIM_ManagedSystemElement
__RELPATH :
__PROPERTY_COUNT : 14
__DERIVATION : {CIM_LogicalElement, CIM_ManagedSystemElement}
__SERVER :
__NAMESPACE :
__PATH :
Caption :
ContainerName :
Description :
DnsServerName :
DomainName :
InstallDate :
Name :
OwnerName :
RecordClass : 1
RecordData :
Status :
TextRepresentation :
Timestamp :
TTL :
PSComputerName :
С классом MicrosoftDNS_TXTType , таких проблем не возникает :
Set-WMIInstance -Namespace root\MicrosoftDNS -class MicrosoftDNS_TXTType -argument @{
DnsServerName = $DNSServer;
ContainerName = $Domain;
DomainName = $Domain;
OwnerName = $CN;
RecordClass=1;
RecordData = $TXT;
TTL = 3600;
}
9. Как создать отсортированный hashtable?
В версии PowerShell V3 мы можем воспользоваться атрибутом [ordered].
[ordered]@{a=1;b=2;c=3}
Для версии PowerShell V2, можно воспользоваться:
1) $hast.GetEnumerator() | Sort name
2) [collections.sortedlist]$hash
3) $OrderedList = New-Object System.Collections.Specialized.OrderedDictionary
$OrderedList.Add("a","1")
$OrderedList.Add("b","2")
$OrderedList.Add("c","3")
10. Как найти distinguishedname объекта по objectGuid?
Практический пример применения это использование для определения DN из событий журнала Security.Возьмем для примера событие под номером 566(4662).
PS > Get-EventLog -LogName security -InstanceId 4662 | select -First 1 -ExpandProperty message
An operation was performed on an object.
Object:
Object Server: DS
Object Type: %{19195a5b-6da0-11d0-afd3-00c04fd930c9}
Object Name: %{7ac689ea-20ed-48eb-93c7-c97d5ae20fd4}
Handle ID: 0x0
Вместо DN здесь представлен objectGuid, в оснастке EventLog отображается DN объекта.Для поиска Dn по ObjectGuid:
$guid = "7ac689ea-20ed-48eb-93c7-c97d5ae20fd4"
$bguid = -join (([GUID]$guid).ToByteArray() |% {"\{0:x}" -f $_})
$dn = ([adsisearcher]"(objectguid=$bguid)").FindOne().Properties.distinguishedname
Более наглядный пример, найдем все события с EventId 4662 и добавим новое свойство DNName к объекту:
Get-WinEvent -FilterHashtable @{LogName="Security";Id=4662} | Foreach {
$xevent = [xml]$_.ToXml()
[Guid]$guid = $xevent.Event.EventData.Data | Where {$_.name -eq "ObjectName"} | Foreach {$_."#text" -replace "\W"}
$bguid = -join ($guid.ToByteArray() |% {"\{0:x}" -f $_})
[string]$dn = ([adsisearcher]"(objectguid=$bguid)").FindOne().Properties.distinguishedname
$_ | Add-Member -Name DNName -Value $dn -MemberType NoteProperty -PassThru
}
Read Full Post »