Может быть, это не самый удачный пример и не самая лучшая реализация, но для моих нужд сгодилось. Основная идея, если не прошел пинг на компьютер, попробовать разрешить его имя используя DNS.Для этого нам потребуется класс System.Net.Dns и два его метода:
GetHostByAddress(IPAddress) – разрешает имя в Ip Address.
GetHostByAddress(String) – разрешает Ip Address в имя.
Основное назначение proxy function это использование удаленного взаимодействия(WinRM).В удаленной сессии мы можем запрещать или разрешать любые компоненты PowerShell(cmdlet parameters,providers и т.д).Например можно удалить у всех cmdlets параметр ComputerName или добавить параметры –FileVersion –Module для Get-Process(оба эти параметра доступны в PowerShell 2.0 RTM) .
Пример использование можно посмотреть в статье Дона Джонса MVP по PowerShell — Неявное удаленное взаимодействие. Создается модуль во временной директории temp модуль и импортируются все команды из удаленного сеанса уже конвертированные в proxy functions.Когда вы выполняете команду локально, она будет перенаправлена на удаленный сервер, что очень удобно, когда нет возможности использовать модули на локальной машине(пример модулей Active Directory,Exchange).
Процесс создания proxy function состоит из трех команд.
$cmdlet = Get-Command -Name Test-Connection –CommandType Cmdlet
$CommandMetadata= New-Object System.Management.Automation.CommandMetadata -ArgumentList $cmdlet
[System.Management.Automation.ProxyCommand]::Create($CommandMetadata)
С помощью Get-Command мы получаем cmdlet Test-Connection,второй создаем метаданные,третьей,генерируем код.
[CmdletBinding(DefaultParameterSetName='Default')]
param(
[Parameter(ParameterSetName='Default')]
[Switch]
${AsJob},
[System.Management.AuthenticationLevel]
${Authentication},
[Alias('Size','Bytes','BS')]
[ValidateRange(0, 65500)]
[System.Int32]
${BufferSize},
[Parameter(Mandatory=$true, Position=0, ValueFromPipelineByPropertyName=$true)]
[Alias('CN','IPAddress','__SERVER','Destination')]
[ValidateNotNullOrEmpty()]
[System.String[]]
${ComputerName},
[ValidateRange(1, 4294967295)]
[System.Int32]
${Count},
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]
${Credential},
[Parameter(Position=1)]
[Alias('FCN','SRC')]
[ValidateNotNullOrEmpty()]
[System.String[]]
${Source},
[System.Management.ImpersonationLevel]
${Impersonation},
[Parameter(ParameterSetName='Default')]
[ValidateRange(-2147483648, 1000)]
[System.Int32]
${ThrottleLimit},
[Alias('TTL')]
[ValidateRange(1, 255)]
[System.Int32]
${TimeToLive},
[ValidateRange(1, 60)]
[System.Int32]
${Delay},
[Parameter(ParameterSetName='Quiet')]
[Switch]
${Quiet})
begin
{
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Test-Connection', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
} catch {
throw
}
}
<#
.ForwardHelpTargetName Test-Connection
.ForwardHelpCategory Cmdlet
#>
В начале блока Begin происходит получение cmdlet Test- Connection и передача параметров с использованием переменной @PSBoundParameters, далее идет инициализация переменной $steppablePipeline,которая будет выполнять команду $scriptCmd(которая является cmdlet Test-Connection и переданными нами параметрами, через @PSBoundParameters).В конце кода мы видим многострочный комментарий, который является инструкцией для cmdlet Get-Help(Get-Help proxyfunction).
В блок param() ,я добавил лишь один параметр [String[]]${DnsHostName}.В переменной $DnsHostName – содержатся имена или ip address для разрешения. В блоке Begin,мы должны удалить ($null = $PSBoundParameters.Remove(‘DnsHostName’)) этот параметр, т.к cmdlet Test-Connection не знает этот параметр, следовательно вызовет ошибку при выполнении. Для передачи параметров ,как уже упоминалось выше используется переменная @PSBoundParameters.
$PSBoundParameters
Содержит словарь активных параметров и их текущих значений.
Значение этой переменной действительно только в области объявления
параметров, включая скрипт или функцию. Можно использовать эту
переменную для отображения или изменения текущий значений параметров
или для передачи значений параметров другому скрипту или функции.
Т.к параметр ComputerName является обязательным,при использовании с параметром DnsHostName,мы присваиваем значения из DnsHostName ComputerName,используя метод Add ($PSBoundParameters.Add(‘ComputerName’,$DnsHostName))
Основная работа заключается в блоке End,где мы проверяем наличие параметра DnsHostName и производим разрешение имен.
function Test-Ping
{
[CmdletBinding(DefaultParameterSetName='Default')]
param(
[Parameter(ParameterSetName='Default')]
[Switch]
${AsJob},
[System.Management.AuthenticationLevel]
${Authentication},
[Alias('Size','Bytes','BS')]
[ValidateRange(0, 65500)]
[System.Int32]
${BufferSize},
[Parameter(Mandatory=$false, Position=0, ValueFromPipelineByPropertyName=$true)]
[Alias('CN','IPAddress','__SERVER','Destination')]
[ValidateNotNullOrEmpty()]
[System.String[]]
${ComputerName},
[ValidateRange(1, 4294967295)]
[System.Int32]
${Count},
[ValidateNotNullOrEmpty()]
[System.Management.Automation.PSCredential]
${Credential},
[Parameter(Position=1)]
[Alias('FCN','SRC')]
[ValidateNotNullOrEmpty()]
[System.String[]]
${Source},
[System.Management.ImpersonationLevel]
${Impersonation},
[Parameter(ParameterSetName='Default')]
[ValidateRange(-2147483648, 1000)]
[System.Int32]
${ThrottleLimit},
[Alias('TTL')]
[ValidateRange(1, 255)]
[System.Int32]
${TimeToLive},
[ValidateRange(1, 60)]
[System.Int32]
${Delay},
[Parameter(ParameterSetName='Quiet')]
[Switch]
${Quiet},
[String[]]${DnsHostName}
)
begin
{
try {
$outBuffer = $null
if ($PSBoundParameters.TryGetValue('OutBuffer', [ref]$outBuffer))
{
$PSBoundParameters['OutBuffer'] = 1
}
if ($PSBoundParameters['DnsHostName'])
{
$null = $PSBoundParameters.Remove('DnsHostName')
$PSBoundParameters.Add('ComputerName',$DnsHostName)
}
$wrappedCmd = $ExecutionContext.InvokeCommand.GetCommand('Test-Connection', [System.Management.Automation.CommandTypes]::Cmdlet)
$scriptCmd = {& $wrappedCmd @PSBoundParameters }
$steppablePipeline = $scriptCmd.GetSteppablePipeline($myInvocation.CommandOrigin)
$steppablePipeline.Begin($PSCmdlet)
} catch {
throw
}
}
process
{
try {
$steppablePipeline.Process($_)
} catch {
throw
}
}
end
{
try {
$steppablePipeline.End()
if ($DnsHostName)
{
$DnsHostName | foreach {
$arr = @()
$name = $_
switch($name)
{
{[System.Net.IPAddress]::TryParse($_,[ref]$null)} {
try {
[System.Net.Dns]::GetHostByAddress($_) | foreach {
$temp = "" | select HostName,IPAddress
$temp.IPAddress = $name
$temp.HostName = $_.HostName
$arr += $temp
}
}
catch {"`nCan't resolve ip $($name)"}
break
}
default {
try{
[System.Net.Dns]::GetHostByName($_).AddressList | foreach {
$temp = "" | select HostName,IPAddress
$temp.HostName = $name
$temp.IPAddress = $_.IPAddressToString
$arr += $temp
}
}
catch {"`nCan't resolve $($name)"}
}
}
$arr
}
}
} catch {
throw
}
}
<#
.ForwardHelpTargetName Test-Connection
.ForwardHelpCategory Cmdlet
#>
}
Вывод:
PS > Test-Ping ya.ru -Count 1 -Quiet
True
PS > Test-Ping -DnsHostName ya.ru -Count 1 -Quiet
True
HostName IPAddress
-------- ---------
ya.ru 87.250.250.3
ya.ru 93.158.134.203
ya.ru 213.180.204.3
ya.ru 87.250.250.203
ya.ru 77.88.21.3
ya.ru 93.158.134.3
ya.ru 87.250.251.3
PS > Test-Ping -DnsHostName ya.ru,microsoft.com -Count 1 -Quiet
True
False
HostName IPAddress
-------- ---------
ya.ru 87.250.251.3
ya.ru 87.250.250.3
ya.ru 87.250.250.203
ya.ru 93.158.134.203
ya.ru 93.158.134.3
ya.ru 213.180.204.3
ya.ru 77.88.21.3
microsoft.com 207.46.197.32
microsoft.com 207.46.232.182
PS > Test-Ping -DnsHostName ya.ru,207.46.197.32 -Count 1 -Quiet
True
False
HostName IPAddress
-------- ---------
ya.ru 93.158.134.203
ya.ru 87.250.250.203
ya.ru 93.158.134.3
ya.ru 87.250.251.3
ya.ru 213.180.204.3
ya.ru 87.250.250.3
ya.ru 77.88.21.3
windowsvistaupdate.org 207.46.197.32
PS > Test-Ping -DnsHostName 207.46.197.32 -Count 1 -Quiet
False
HostName IPAddress
-------- ---------
windowsvistaupdate.org 207.46.197.32
PS > Test-Ping -DnsHostName ff -Count 1 -Quiet
False
Can't resolve ff
Что почитать:
http://blogs.msdn.com/b/powershell/archive/2009/01/04/extending-and-or-modifing-commands-with-proxies.aspx
http://get-powershell.com/post/2009/01/05/Using-Proxy-Commands-in-PowerShell.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2011/03/01/proxy-functions-spice-up-your-powershell-core-cmdlets.aspx
http://blogs.technet.com/b/heyscriptingguy/archive/2011/04/29/expert-solution-for-2011-scripting-games-advanced-event-10-use-a-powershell-proxy-function-to-create-temporary-files.aspx
https://dmitrysotnikov.wordpress.com/category/proxy-functions/
Read Full Post »