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

Archive for Май 2011

Тема была навеяна — http://social.technet.microsoft.com/Forums/ru-RU/scrlangru/thread/41b88ccd-b1a2-4227-bad5-0981f3a1d970 . Основная идея — это аналог утилиты net file /close.Для решения проблемы потребуется WinApi функция NetCloseFile и интерфейс IADsRescource(что позволяет гораздо сократить скрипт,вместо использования функции NetFileEnum и структуры FILE_INFO_3).

Основное преимущество скрипта  — это работа  с удаленным компьютером,как получение имен,так и закрытия файлов.

Function Get-OpenFiles
{
	<#
		Аналог утилиты net file.Запуск скрипта без параметров,выведет список открытых общих файлов,
		так же поддерживается функция закрытия файлов,как на локальном,там и на удаленном ПК.

		Требуются права администратора или соответсвующие.Сервис Server должен быть запущен.

		Пример:

		PS >  Get-OpenFiles
		PS >  Get-OpenFiles -Id 510
		PS >  "Server1","Server2" | Get-OpenFiles
	#>

	[CmdletBinding()]
	param (
			 [parameter(Position=0,ValueFromPipeline=$true,ValueFromPipelineByPropertyName=$true)]
			 [alias("CN")]
			 [String[]]$ComputerName = ".",
			 [parameter(ParameterSetName="Close")]
			 [int[]]$Id
		  )

	begin {
			#Объявляем функцию NetFileClose
			$signature = @"
			[DllImport("netapi32.dll", SetLastError=true, CharSet = CharSet.Unicode)]
			public static extern int NetFileClose(
			    string servername,
			    int id);
"@
			$type = Add-Type -MemberDefinition $signature -Name NetFile -Namespace Win32.Function -PassThru
		  }

	process {
			#Получаем список открытых файло
			foreach ($server in $ComputerName)
			{
				$netfile = [ADSI]"WinNT://$server/LanmanServer"
				#Получаем свойста интерфейса IADsResource
				$netfile.Invoke("Resources") | foreach {$collection = @()} {
					$collection += New-Object PsObject -Property @{
							Id = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
							Path = $_.GetType().InvokeMember("Path", 'GetProperty', $null, $_, $null)
							UserName = $_.GetType().InvokeMember("User", 'GetProperty', $null, $_, $null)
							LockCount = $_.GetType().InvokeMember("LockCount", 'GetProperty', $null, $_, $null)
							Server = $server
						}
				}
			}
		}

	end {
			#Если задан параметр -Id ,пытаемся закрыть доступ к файлу
			if ($pscmdlet.ParameterSetName -eq "Close"){
				foreach ($i in $Id)
				{
					$collection | Where-Object {$_.Id -eq $i} | Foreach {
								$type::NetFileClose($_.Server,$_.Id)
					}
				}
			}
			#Если параметр -Id не задан,выводим список открытых файлов.
			else {$collection}
		}
}
Реклама

Read Full Post »

Может быть, это не самый удачный пример и не самая лучшая реализация, но для моих нужд сгодилось. Основная идея, если  не прошел пинг на компьютер, попробовать разрешить его имя используя 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 »