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

Q&A

1) Как программно отключить монитор?

$signature = @"
    [DllImport("User32.DLL")]
    public static extern int SendMessage(IntPtr hWnd, UInt32 Msg, Int32 wParam, Int32 lParam);
"@

$type = Add-Type -MemberDefinition $signature -Name Win32 -Namespace SendMessage -PassThru
$type::SendMessage(0xFFFF,0x0112,0xF170,2)

2) Какие ярлыки соответствуют данному exe?

Get-WmiObject Win32_ShortcutFile  -Filter "Target='C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe'"

3) Какой класс использовать для работы с большими целыми числами?

В .Net 4.0 есть структура BigInteger Structure для работы с большими числами. По умолчанию в PowerShell V2 не включена поддержка .Net 4.0, для включение – http://tfl09.blogspot.com/2010/08/using-newer-versions-of-net-with.html

4) Как сделать побитовый сдвиг?

V2 : Используйте скрипт http://huddledmasses.org/powershell-needs-shift-operators/

V3 : Появились встроенные операторы для побитового сдвига, -shl и -shr

5) Как просто сгенерировать пароль?

Function Get-Password {
        param($number=1,$length=10)
        $rand = New-Object System.Random
        for($i=0;$i -lt $number;$i++)
        {
                -join (1..$length | ForEach { [char]$rand.next(33,127) })
        }
}

PS > Get-Password -number 5 -length 15
1'K[jc_K8fLV4V:
,Y;u*r)u!9-,lr$
v$m6@`-I:gpY0yG
4~YC1MNlMe)0KB]
XrX4oIh|7X~0".9

6) Как работать с путями больше 256 символов?

Модуль – http://huddledmasses.org/long-path-module-experimental-io/

Также можно использовать часть возможностей cmd.exe используя префикс \\?\ – подробнее можно узнать в статье Naming Files, Paths, and Namespaces.

7) Как преобразовать пароль в Base64 для использование в атрибуте unicodepwd?

VBS – http://www.rlmueller.net/Programs/PwdToBase64.txt
Вручную – http://www.oszone.net/13669/Active-Directory-UnicodePwd-AD-LDS

И в одну строчку на PowerShell, двойные кавычки обязательные.

[convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes(‘”xZy$132#q!”‘))

1)      Использование ComObject – WMPlayer.OCX.7

$cds = (New-Object -ComObject "WMPlayer.OCX.7").cdromcollection
#Количество cd-rom's в системе
$cds.count
#Какой букве,соответсвует номер в коллекции
0..($cds.count-1) | select @{n="ItemCount";e={$_}},@{n="driveSpecifier";e={$cds.item($_).driveSpecifier}}
#Извлечь первый в номере коллекции
$cds.item(0).eject()
#Для закрытия 
$cds.item(0).eject()
#Извлечь по букве
$cds.getByDriveSpecifier("X").Eject()
#Для закрытия
$cds.getByDriveSpecifier("X").Eject()


Пример вывода
PS >  0..($cds.count-1) | select @{n="ItemCount";e={$_}},@{n="driveSpecifier";e={$cds.item($_).driveSpecifier}}

                                                 ItemCount driveSpecifier
                                                 --------- --------------
                                                         0 D:
                                                         1 I:

PS >  $cds.item(1).eject()
PS >  $cds.getByDriveSpecifier("I").Eject()

2)      Использование ComObject – Shell.Application

Данная библиотека хорошо документирована , подробнее можно прочитать на сайте – http://msdn.microsoft.com/en-us/library/bb774094(v=vs.85).aspx

Константы можно также посмотреть на сайте – ShellSpecialFolderConstants enumeration, нам потребуется только одна константа:

ssfDRIVES

0×11 (17). My Computer—the virtual folder that contains everything on the local computer: storage devices, printers, and Control Panel. This folder can also contain mapped network drives.

PS. Глагола для закрытия CD-ROM’a я не нашел.

$shellapp = New-Object -comObject Shell.Application
#Количество cd-rom's в системе
$shellapp.Namespace(17).Items() | Where {$_.Type -eq "CD Drive"}
#Какие действия можно выполнять над объектом,используя Verb
#Основная проблема,что зависит от локализации системы
$shellapp.Namespace(17).ParseName("X:").Verbs()
#Для англоязычной Windows - глагол Eject
$shellapp.Namespace(17).ParseName("X:").InvokeVerb("Eject")

Пример вывода:

PS > $shellapp.Namespace(17).Items() | Where {$_.Type -eq "CD Drive"}
Application  : System.__ComObject
Parent       : System.__ComObject
Name         : BD-ROM Drive (D:)
Path         : D:\
GetLink      : 
GetFolder    : System.__ComObject
IsLink       : False
IsFolder     : True
IsFileSystem : True
IsBrowsable  : False
ModifyDate   : 30.12.1899 0:00:00
Size         : 0
Type         : CD Drive

Application  : System.__ComObject
Parent       : System.__ComObject
Name         : DVD RW Drive (I:)
Path         : I:\
GetLink      : 
GetFolder    : System.__ComObject
IsLink       : False
IsFolder     : True
IsFileSystem : True
IsBrowsable  : False
ModifyDate   : 30.12.1899 0:00:00
Size         : 0
Type         : CD Drive


PS >  $shellapp.Namespace(17).ParseName("I:")


Application  : System.__ComObject
Parent       : System.__ComObject
Name         : DVD RW Drive (I:)
Path         : I:\
GetLink      :
GetFolder    : System.__ComObject
IsLink       : False
IsFolder     : True
IsFileSystem : True
IsBrowsable  : False
ModifyDate   : 30.12.1899 0:00:00
Size         : 0
Type         : CD Drive

PS > $shellapp.Namespace(17).ParseName("I:").Verbs() | Select Name

Name
----
&Open

Burn &to disc
Scan selected files with Anti&Vir
Form&at...
E&ject
&Copy
Create &shortcut
P&roperties

PS > $shellapp.Namespace(17).ParseName("I:").InvokeVerb("Eject")

3)      Использование WinAPI – mciSendString

Документация по функции, можно посмотреть на msdn – mciSendString , определение данной функции для C#, можно посмотреть на pInvoke – mciSendString.

#Количество cd-rom's в системе
Get-WmiObject Win32_CDROMDrive

$code = @"
[DllImport("winmm.dll")]
public static extern Int32 mciSendString(String command, StringBuilder buffer, Int32 bufferSize, IntPtr hwndCallback);
"@
$cdrom = Add-Type -MemberDefinition $code -Name System -Namespace CDROM -UsingNamespace System.Text -PassThru 
#OPEN
$cdrom::mciSendString("open X: type CDAudio alias driveX", $null, 0, [IntPtr]::Zero)
$cdrom::mciSendString("set driveX door open", $null, 0, [IntPtr]::Zero)
#CLOSE
$cdrom::mciSendString("open X: type CDAudio alias driveI", $null, 0, [IntPtr]::Zero)
$cdrom::mciSendString("set driveX door closed", $null, 0, [IntPtr]::Zero)


Пример вывода:

PS > Get-WmiObject Win32_CDROMDrive | Select Caption,Drive

Caption                                                     Drive
-------                                                     -----
Optiarc DVD RW AD-7203A ATA Device                          I:
WDKVYZW YJ85M3OT SCSI CdRom Device                          D:

PS > $drive = "I"
PS > $string = "open $drive`: type CDAudio alias drive$drive"
PS > $cdrom::mciSendString($string, $null, 0, [IntPtr]::Zero)
0
PS > $setstring = "set drive$drive door open"
PS > $cdrom::mciSendString($setstring, $null, 0, [IntPtr]::Zero)
0
PS > $clsstring = "set drive$drive door closed"
PS > $cdrom::mciSendString($clsstring, $null, 0, [IntPtr]::Zero)
0

4)      Использование других WinAPi функций

Пример класса для C# был взят с сайта – http://stackoverflow.com/questions/1449410/programatically-ejecting-and-retracting-the-cd-drive-in-vb-net-or-c-sharp за авторством C# гуру Jon Skeet. Здесь лишь небольшая косметическая правка и адаптировано для PowerShell.

$code = @"
using System; 
using System.IO; 
using System.Runtime.InteropServices; 

namespace  System
{
	public class CDROM
	{ 
	    const int OPEN_EXISTING = 3; 
	    const uint GENERIC_READ = 0x80000000; 
	    const uint GENERIC_WRITE = 0x40000000; 
	    const uint IOCTL_STORAGE_EJECT_MEDIA = 2967560; 
	 
	    [DllImport("kernel32")] 
	    private static extern IntPtr CreateFile 
	        (string filename, uint desiredAccess,  
	         uint shareMode, IntPtr securityAttributes, 
	         int creationDisposition, int flagsAndAttributes,  
	         IntPtr templateFile); 
	 
	    [DllImport("kernel32")] 
	    private static extern int DeviceIoControl 
	        (IntPtr deviceHandle, uint ioControlCode,  
	         IntPtr inBuffer, int inBufferSize, 
	         IntPtr outBuffer, int outBufferSize,  
	         ref int bytesReturned, IntPtr overlapped); 
	 
	    [DllImport("kernel32")] 
	    private static extern int CloseHandle(IntPtr handle); 
	 
	    public static void EjectMedia(char driveLetter) 
	    { 
	        string path = "\\\\.\\" + driveLetter + ":"; 
	        IntPtr handle = CreateFile(path, GENERIC_READ | GENERIC_WRITE, 0,  
	                                   IntPtr.Zero, OPEN_EXISTING, 0, 
	                                   IntPtr.Zero); 
	        if ((long) handle == -1) 
	        { 
	            throw new IOException("Unable to open drive " + driveLetter); 
	        } 
	        int dummy = 0; 
	        DeviceIoControl(handle, IOCTL_STORAGE_EJECT_MEDIA, IntPtr.Zero, 0,  
	                        IntPtr.Zero, 0, ref dummy, IntPtr.Zero); 
	        CloseHandle(handle); 
	    } 
	}
}
"@
Add-Type -TypeDefinition $code 

Пример вывода:

PS > Get-WmiObject Win32_CDROMDrive | Select Caption,Drive

Caption                                                     Drive
-------                                                     -----
Optiarc DVD RW AD-7203A ATA Device                          I:
WDKVYZW YJ85M3OT SCSI CdRom Device                          D:

PS >  [CDROM]::EjectMedia("I")

По умолчанию в Windows нет консольного приложения для управления ABE. Более подробно про ABE,можно узнать в блоге Алексея Горбунова и ABE Graphical User Interface , во второй ссылке подробно рассказывается, какие API используются для управления ABE.

Утилита командной строки для управления ABE(более подробно смотри во второй ссылке):

ABECMD – http://www.microsoft.com/download/en/details.aspx?displaylang=en&id=17510

В статье про “управление кэшированием общих папок”, весь функционал скрипта уже был реализован, поэтому достаточно было добавить только флаг FLAGS_ACCESS_BASED_DIRECTORY_ENUM, который равняется 0×0800.

$code = @"
public enum CacheType
{
	Manual    = 0x00,
	Documents = 0x10,
	Programs  = 0x20,
	None      = 0x30,
}

public const int FLAGS_ACCESS_BASED_DIRECTORY_ENUM = 0x0800;

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHARE_INFO_1005
{
    public uint shi1005_flags;
}

[DllImport("Netapi32", CharSet=CharSet.Auto)]
    public static extern int NetApiBufferFree(IntPtr Buffer);

[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetShareGetInfo(
    [MarshalAs(UnmanagedType.LPWStr)] string serverName,
    [MarshalAs(UnmanagedType.LPWStr)] string netName,
    Int32 level,
    out IntPtr bufPtr );

[DllImport("Netapi32.dll", CharSet = CharSet.Unicode)]
public static extern uint NetShareSetInfo(string servername, string netname,
    uint level, ref SHARE_INFO_1005 buf, out uint paramerror);
"@

Add-Type -MemberDefinition $code -name Share -namespace System

function Get-ShareABE
{
	param(
			[parameter(Mandatory=$true,ValueFromPipeline=$true,
			ValueFromPipelineByPropertyName=$true)]
			[Alias("Name")]
			[string]$ShareName
		)

	process {
		$bufptr = [IntPtr]::Zero
		$return = [Share]::NetShareGetInfo($null,$ShareName,1005,[ref]$bufptr)
		if($return -eq 0)
		{
			$Enable = "Disabled"
			$str1005 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($bufptr,[Share+SHARE_INFO_1005])
			$value = $str1005.shi1005_flags
			if ($value -band [Share]::FLAGS_ACCESS_BASED_DIRECTORY_ENUM)
			{
				$Enable = "Enabled"
			}
			Get-WmiObject Win32_Share -Filter "Name='$ShareName'" | Select-Object Name,`
				Path,Description,@{n="ABE";e={$Enable}},@{n="Flag";e={$value}}
		}
		else
		{
			Write-Host (net helpmsg $return)
		}
		[Share]::NetApiBufferFree($bufptr) | Out-Null
	}
}

function Set-ShareABE
{
	param(
		[parameter(Mandatory=$true,Position=0)]
		[string]$ShareName,
		[parameter(Mandatory=$true,Position=1)]
		[ValidateSet("Enable", "Disable")]
		[string]$Type
	)

	$paramerror = 0

	if ($Type -eq "Disable")
	{
		$flag = (Get-ShareABE -ShareName $ShareName).Flag -bxor [Share]::FLAGS_ACCESS_BASED_DIRECTORY_ENUM
	}
	else
	{
		$flag = [Share]::FLAGS_ACCESS_BASED_DIRECTORY_ENUM
	}
	$buf = New-Object Share+SHARE_INFO_1005 -Property @{shi1005_flags = $flag}
	$return = [Share]::NetShareSetInfo($null,$ShareName,1005,[ref]$buf,[ref]$paramerror)
	if ($return)
	{
		Write-Host (net helpmsg $return)
	}
}

Применение функции Get-ShareABE:

PS > Get-ShareABE doesnotexists
 This shared resource does not exist.
PS > Get-ShareABE Test

Name        : TEST
Path        : C:\TEST
Description :
ABE         : Disabled
Flag        : 0

PS > Get-WmiObject Win32_Share | Get-ShareABE

Name        : ADMIN$
Path        : C:\Windows
Description : Remote Admin
ABE         : Disabled
Flag        : 0

Name        : C$
Path        : C:\
Description : Default share
ABE         : Disabled
Flag        : 0

Name        : IPC$
Path        :
Description : Remote IPC
ABE         : Disabled
Flag        : 0

Name        : TEST
Path        : C:\TEST
Description :
ABE         : Disabled
Flag        : 0

Применение функции Set-ShareABE:

PS > Get-ShareABE Test

Name        : TEST
Path        : C:\TEST
Description :
ABE         : Disabled
Flag        : 0

PS > Set-ShareABE Test -Type Enable
PS > Get-ShareABE Test

Name        : TEST
Path        : C:\TEST
Description :
ABE         : Enabled
Flag        : 2048

PS > Set-ShareABE Test -Type Disable
PS > Get-ShareABE Test

Name        : TEST
Path        : C:\TEST
Description :
ABE         : Disabled
Flag        : 0

Q&A

1) Как получить номер недели в месяце (1-5)?

Function Get-WeekOfMonth    
{    
    param ([datetime]$date = (Get-Date)) 
    
    $beginningOfMonth = New-Object DateTime($date.Year,$date.Month,1)  
  
    while ($date.Date.AddDays(1).DayOfWeek -ne (Get-Culture).DateTimeFormat.FirstDayOfWeek)
    { 
        $date = $date.AddDays(1)    
    } 
    
    [int]([Math]::Truncate($date.Subtract($beginningOfMonth).TotalDays  / 7) + 1)   
}  

2) Как отключить “X” в консоли PowerShell?

$code = @"
[DllImport("user32.dll")] 
public static extern int DeleteMenu(IntPtr hMenu, int nPosition, int wFlags);
 
[DllImport("User32")]
public static extern IntPtr GetSystemMenu(IntPtr hWnd, bool bRevert);
"@

Add-Type -MemberDefinition $code -Name HideClose -Namespace System

$hMenu = [HideClose]::GetSystemMenu((gps -id $pid).MainWindowHandle, $false)
[HideClose]::DeleteMenu($hMenu,0xF060, 0)

3) Как используя метод XMLDocument.Save() сохранить данные в переменную?

$mem = New-Object IO.MemoryStream
$writer = New-Object IO.StreamWriter($mem)
$xml.Save($writer)
$var = [System.Text.Encoding]::Default.GetString($mem.toarray())
$var

Или
 
$xml.Save(($mem=New-Object IO.MemoryStream))
$var=[System.Text.Encoding]::Default.GetString($mem.toarray())

4) Какой метод класса System.Net.DNS лучше использовать?

Для разрешение имен в прямом и обратном направлении,лучше всего использовать статический метод GetHostEntry(IPAddress) и GetHostEntry(String).

5) Как отключить positional parameters?

V2:
param ($badparam,$i1,$i2)
if ($badparam) {“Вы не ввели обязательные параметры”}

V3: [CmdletBinding(PositionalBinding=$false)]

Текущие командлеты, не очень хорошо справляются с данной задачей, поэтому эффективным решением – использовать .Net. На одном из форумов, был найден скрипт на C#, который полностью решал эту задачу. Переводить скрипт полностью на PowerShell, я не вижу смысла, хотя код транслируется очень легко. Оригинал скрипта, можно посмотреть  – http://bit.ly/uR1bUL . Я сделал лишь небольшую обвязку в виде функции.


Function Get-EndTokenFile
{
	<#
	    .SYNOPSIS 
	    Читает последние N строк из файла.

	    .DESCRIPTION
	    Читаем последние N строк из файла с заданной кодировкой(по умолчанию ASCII)
		по заданному пути,который является обязательным параметром.
		
		.PARAMETER Path
		Путь к файлу(полное имя файла).Подстановочные знаки не разрешены.
		
		.PARAMETER Encoding
		Задает тип кодировки, используемой в файле. Пример: "Unicode", "UTF7", "UTF8", 
		"UTF32", "ASCII", "BigEndianUnicode", "Default","OEM","Windows-1251". 
		По умолчанию используется кодировка "ASCII".
		
		.PARAMETER ReadCount
		Количество выводимых строк.По умолчанию используется 1.
		
		.PARAMETER Separator
		Указывает разделитель для строк. По умолчанию используется разделитель `r`n.
		
		.PARAMETER Verbose
		Отображает подробные сведения о действиях, выполняемых командой.
		
		.PARAMETER WhatIf
		Описывает, что произойдет при выполнении команды, без ее фактического выполнения.

	     .EXAMPLE
	     C:\PS> Get-EndTokenFile -Path C:\file.txt
		 
		 .EXAMPLE
	     C:\PS> Get-EndTokenFile -Path C:\file.txt -WhatIf
		 
		 .EXAMPLE
	     C:\PS> Get-EndTokenFile -Path C:\file.txt -ReadCount 2
		 
		 .EXAMPLE
	     C:\PS> Get-EndTokenFile -Path C:\file.txt -Encoding Unicode
		 
		 .EXAMPLE
	     C:\PS> Get-ChildItem C:\Files\*.txt | Get-EndTokenFile 
	#>


	[CmdletBinding(SupportsShouldProcess=$true)]
	param (
			[Parameter(
					Mandatory=$true,
            		ValueFromPipeline=$true,
					ValueFromPipelineByPropertyName=$true
					)]
			[Alias("FullName")]
			[string]
			$Path,
			[string]$Encoding = "ASCII",
			[Int64]$ReadCount = 1,
			[string]$Separator = "`r`n"
		)
			
begin {
$code = @"
public static string ReadEndTokens(string path, Int64 numberOfTokens, Encoding encoding, string tokenSeparator) { 
 
    int sizeOfChar = encoding.GetByteCount("\n"); 
    byte[] buffer = encoding.GetBytes(tokenSeparator); 
 
 
    using (FileStream fs = new FileStream(path, FileMode.Open)) { 
        Int64 tokenCount = 0; 
        Int64 endPosition = fs.Length / sizeOfChar; 
 
        for (Int64 position = sizeOfChar; position < endPosition; position += sizeOfChar) { 
            fs.Seek(-position, SeekOrigin.End); 
            fs.Read(buffer, 0, buffer.Length); 
 
            if (encoding.GetString(buffer) == tokenSeparator) { 
                tokenCount++; 
                if (tokenCount == numberOfTokens) { 
                    byte[] returnBuffer = new byte[fs.Length - fs.Position]; 
                    fs.Read(returnBuffer, 0, returnBuffer.Length); 
                    return encoding.GetString(returnBuffer); 
                } 
            } 
        } 
 
        // handle case where number of tokens in file is less than numberOfTokens 
        fs.Seek(0, SeekOrigin.Begin); 
        buffer = new byte[fs.Length]; 
        fs.Read(buffer, 0, buffer.Length); 
        return encoding.GetString(buffer); 
    } 
} 
"@

	Add-Type -MemberDefinition $code -Name ReadLong -Namespace System -UsingNamespace System.Text,System.IO
}
process {
	if ($pscmdlet.ShouldProcess("Производим операцию чтения файла '$Path'."))
	{
		if (Test-Path $path)
		{
			[ReadLong]::ReadEndTokens($Path,$ReadCount,[System.Text.Encoding]::GetEncoding($Encoding),$Separator)
		}
		else
		{
			Write-Error "Файл $Path не найден."
		}
	}
	}
}


Управление процессом кэширования для общих папок с помощью PowerShell

Был задан вопрос: ”Как управлять процессом кэширования с помощью PowerShell?”. Для управления кэшированием в Windows, существует встроенная утилита net,у которой есть ключ /cache. Данный ключ принимает следующие параметры:

PS >  net share /?
	[/CACHE:Manual | Documents | Programs | BranchCache | None]

Для просмотра состояния кэширования для общей папки, можно воспользоваться, следующим синтаксисом:

Syntax: net share sharename

PS >  net share C$
Share name        C$
Path              C:\
Remark            Стандартный общий ресурс
Maximum users     No limit
Users
Caching           Manual caching of documents
Permission        Все, FULL

The command completed successfully.

На мой взгляд, утилита net,предоставляет простой и удобный способ управления – параметром кэширования. И именно его предпочтительней использовать в своих скриптах.

Попробуем реализовать данный функционал, используя стандартные WinApi функции. Для этого нам потребуется две функции и одна структура:

1)      NetShareGetInfo  – для получения состояние кэширования;

2)      NetShareSetInfo  – для установки параметра кэширования;
3)      _SHARE_INFO_1005– содержит информацию о кэшировании;

Структура _SHARE_INFO_1005 , поддерживает большое количество битовых флагов, но нам потребуется только флаг CSC_MASK, более подробно смотрите по ссылке выше. Определение данных функций для C#,можно посмотреть на сайтеPinvoke.
 

$code = @"
public enum CacheType
{
	Manual    = 0x00,
	Documents = 0x10,
	Programs  = 0x20,
	None      = 0x30,
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct SHARE_INFO_1005
{
    public uint shi1005_flags;
}

[DllImport("Netapi32", CharSet=CharSet.Auto)]
    public static extern int NetApiBufferFree(IntPtr Buffer);

[DllImport("Netapi32.dll", SetLastError=true)]
public static extern int NetShareGetInfo(
    [MarshalAs(UnmanagedType.LPWStr)] string serverName,
    [MarshalAs(UnmanagedType.LPWStr)] string netName,
    Int32 level,
    out IntPtr bufPtr );

[DllImport("Netapi32.dll", CharSet = CharSet.Unicode)]
public static extern uint NetShareSetInfo(string servername, string netname,
    uint level, ref SHARE_INFO_1005 buf, out uint paramerror);
"@

Add-Type -MemberDefinition $code -name Share -namespace System

function Get-ShareCache
{
	param(
			[parameter(Mandatory=$true,ValueFromPipeline=$true,
			ValueFromPipelineByPropertyName=$true)]
			[Alias("Name")]
			[string]$ShareName
		)

	process {
		$bufptr = [IntPtr]::Zero
		$return = [Share]::NetShareGetInfo($null,$ShareName,1005,[ref]$bufptr)
		if($return -eq 0)
		{
			$str1005 = [System.Runtime.InteropServices.Marshal]::PtrToStructure($bufptr,[Share+SHARE_INFO_1005])
			$value = $str1005.shi1005_flags
			Get-WmiObject Win32_Share -Filter "Name='$ShareName'" | Select-Object Name,`
				Path,Description,@{n="Caching";e={
				1,2,256,512,1024,2048,4096 | Foreach {
					if ($value -band $_)
					{
						$value -= $_
					}
				}
				$value -as [Share+CacheType]}}
		}
		else
		{
			Write-Host (net helpmsg $return)
		}
		[Share]::NetApiBufferFree($bufptr) | Out-Null
	}
}

function Set-ShareCache
{
	param(
		[parameter(Mandatory=$true,Position=0)]
		[string]$ShareName,
		[parameter(Mandatory=$true,Position=1)]
		[ValidateSet("Manual", "Documents", "Programs","None")]
		[string]$CacheType
	)

	$paramerror = 0
	$buf = New-Object Share+SHARE_INFO_1005 -Property @{shi1005_flags = [Share+CacheType]::$CacheType}
	$return = [Share]::NetShareSetInfo($null,$ShareName,1005,[ref]$buf,[ref]$paramerror)
	if ($return)
	{
		Write-Host (net helpmsg $return)
	}
}

Использование.

Применение функции Get-ShareCache:

PS >  Get-ShareCache doesnotexists
 This shared resource does not exist.

PS >  Get-ShareCache C$ | Format-Table -Auto

Name Path Description              Caching
---- ---- -----------              -------
C$   C:\  Стандартный общий ресурс  Manual

PS >  Get-WmiObject Win32_Share | Get-ShareCache | Format-Table -Auto

Name   Path                              Description               Caching
----   ----                              -----------               -------
ADMIN$ C:\Windows                        Удаленный Admin            Manual
C$     C:\                               Стандартный общий ресурс   Manual
IPC$                                     Удаленный IPC              Manual
print$ C:\Windows\system32\spool\drivers Драйверы принтеров         Manual

Применение функции Set-ShareCache:

PS >  Get-ShareCache test | Format-Table -Auto

Name Path    Description Caching
---- ----    ----------- -------
Test C:\Test              Manual

PS >  Set-ShareCache -ShareName Test -CacheType Documents
PS >  Get-ShareCache test | Format-Table -Auto

Name Path    Description   Caching
---- ----    -----------   -------
Test C:\Test             Documents

PS >  Set-ShareCache -ShareName Test -CacheType Programs
PS >  "Test" | Get-ShareCache | Format-Table -Auto

Name Path    Description  Caching
---- ----    -----------  -------
Test C:\Test             Programs

Новинки PowerShell V3 часть 6

Поговорим еще немного о новых возможностях:

1)      Возможность установки и обновления файлов помощи, используя  командлет Update-Help

До выпуска PowerShell V3 CTP1,для получения помощи, вы использовали командлет Get-Help. Когда в документации находили ошибки или прочие неточности, нельзя было обновить справку для получения последних изменений. Для этого, приходилось использовать Get-Help command -Online и возможно данный недочет будет исправлен. В версии V3,данную проблему решает командлет Update-Help.

В PowerShell V3 CTP1,по умолчанию отсутствует стандартная справка, но она есть в cab файле.

Требуемые операции для обновления:

  1. Скачать cab файл –  PowerShell V3 CTP1
  2. Распаковываем(expand,7-Zip,Winrar,etc)
  3. Update-Help –SourcePath C:\folderexpand\HelpContent -UICulture en-Us,ru-RU –Force

Более подробно, можно прочитать в блоге – http://tfl09.blogspot.com/2011/09/powershell-v3-and-updateable-help.html

2)      Появилась новая встроенная переменная – $PSDefaultParameterValues

Определяет значения по умолчанию для параметров и  расширенных функций. $PSDefaultParameterValues  -  это hash table, где ключ содержит  cmdlet:param и в поле value находится стандартное значение.

PS > $PSDefaultParameterValues | gm
   TypeName: System.Management.Automation.DefaultParameterDictionary

Name                 MemberType            Definition
----                 ----------            ----------
Add                  Method                System.Void Add(System.Object key, System.Object value)
ChangeSinceLastCheck Method                bool ChangeSinceLastCheck()
Clear                Method                System.Void Clear()
Clone                Method                System.Object Clone()
Contains             Method                bool Contains(System.Object key)
ContainsKey          Method                bool ContainsKey(System.Object key)
ContainsValue        Method                bool ContainsValue(System.Object value)
CopyTo               Method                System.Void CopyTo(array array, int arrayIndex), System.Void CopyTo(array...
Equals               Method                bool Equals(System.Object obj)
GetEnumerator        Method                System.Collections.IDictionaryEnumerator GetEnumerator(), System.Collecti...
GetHashCode          Method                int GetHashCode()
GetObjectData        Method                System.Void GetObjectData(System.Runtime.Serialization.SerializationInfo ...
GetType              Method                type GetType()
OnDeserialization    Method                System.Void OnDeserialization(System.Object sender)
Remove               Method                System.Void Remove(System.Object key)
ToString             Method                string ToString()
Item                 ParameterizedProperty System.Object Item(System.Object key) {get;set;}
Count                Property              System.Int32 Count {get;}
IsFixedSize          Property              System.Boolean IsFixedSize {get;}
IsReadOnly           Property              System.Boolean IsReadOnly {get;}
IsSynchronized       Property              System.Boolean IsSynchronized {get;}
Keys                 Property              System.Collections.ICollection Keys {get;}
SyncRoot             Property              System.Object SyncRoot {get;}
Values               Property              System.Collections.ICollection Values {get;}

Синтаксис:

$PSDefaultParameterValues["Disabled"]=$true | $false
$PSDefaultParameterValues=@{"<CmdletName>:<ParameterName>"="<Value>"}
$PSDefaultParameterValues=@{"<CmdletName>:<ParameterName>"={<ScriptBlock>}}

$PSDefaultParameterValues включена по умолчанию (Disabled=$false).

Подстановочные знаки разрешены в <CmdletName> и <ParameterName>.

Значение по умолчанию может быть объект или script block. В случае если передается script block:

  1. (script block) – сначала PowerShell вычисляет значение выражения и используется, как параметр.
  2. {script block} – если требуется передать script block,напрямую, заключается в {}.

Примеры использования:

#Отключить использование $PSDefaultParameterValues
PS > $PSDefaultParameterValues["Disabled"]=$true

#Перезапишем стандартное значение -Path="." командлета Get-ChildItem

PS > $PSDefaultParameterValues=@{"Get-ChildItem:Path"="C:\"}
PS > Get-ChildItem


    Directory: C:\


Mode                LastWriteTime     Length Name
----                -------------     ------ ----
d----         9/19/2011   8:16 PM            PerfLogs
d----         10/5/2011   2:19 AM            poshv3
d-r--         9/20/2011   9:48 PM            Program Files
d----         8/25/2011   1:00 PM            Program Files (x86)
d-r--         9/19/2011   8:14 PM            Users
d----         9/19/2011   8:16 PM            Windows

#Передадим script block,без вычисления выражения,используя двойные {}
PS >  $PSDefaultParameterValues=@{ "Invoke-Command:ScriptBlock"={{Get-Service | Where Status -EQ Running}} }
PS > Invoke-Command

Status   Name               DisplayName
------   ----               -----------
Running  BFE                Base Filtering Engine
Running  CryptSvc           Cryptographic Services
Running  DcomLaunch         DCOM Server Process Launcher
Running  DeviceAssociati... Device Association Service
Running  Dhcp               DHCP Client
Running  DPS                Diagnostic Policy Service
Running  EventLog           Windows Event Log
Running  EventSystem        COM+ Event System
Running  FontCache          Windows Font Cache Service
Running  gpsvc              Group Policy Client
Running  iphlpsvc           IP Helper
Running  LanmanServer       Server
Running  LanmanWorkstation  Workstation
Running  lmhosts            TCP/IP NetBIOS Helper
Running  LSM                Local Session Manager
Running  MpsSvc             Windows Firewall
Running  MSDTC              Distributed Transaction Coordinator

При обновлении справки, более подробно, можно узнать:

Get-Help about_preference_variables

http://powertoe.wordpress.com/2011/09/15/powershell-default-parameters-in-v-3-0/

Так же для работы, можно воспользоваться парой функций – http://poshcode.org/2990

Введение подобного функционала, может создать проблемы в безопасности и осложнение в отладке скриптов. Так что, аккуратнее, используйте данный функционал.

3)      Использование атрибутов.

Я не буду переписывать материал книги, а приведу ссылку на книгу Mastering PowerShell под авторством Tobias Weltner  и конкретно раздел, где рассказывается про данный функционал – Variable Management: Behind the Scenes. После прочтение, вам станет понятным, как использовать свойство Attributes – и как его применять для V1 и V2. Так же в разделе даны, какие  классы атрибутов бывают и , какие параметры они принимают.

Один из MVP по PowerShell Joel Bennett,написал функцию, где облегчается добавления данных атрибутов, к переменным. Приведу исходный код функции (http://poshcode.org/2991) :

function Protect-Variable {
param(
[Parameter(Mandatory=$true,Position=0)][String]$Name, [Int]$Scope = 1,
[Parameter(ParameterSetName="ValidateScriptBlock")][ScriptBlock]$ScriptBlock,
[Parameter(ParameterSetName="ValidateCount")][Int]$MinCount,
[Parameter(ParameterSetName="ValidateCount")][Int]$MaxCount,
[Parameter(ParameterSetName="ValidateLength")][Int]$MinLength,
[Parameter(ParameterSetName="ValidateLength")][Int]$MaxLength,
[Parameter(ParameterSetName="ValidatePattern")][Regex]$Pattern,
[Parameter(ParameterSetName="ValidateRange")][Int]$MinValue,
[Parameter(ParameterSetName="ValidateRange")][Int]$MaxValue,
[Parameter(ParameterSetName="ValidateSet")][String[]]$Set,
[Parameter(ParameterSetName="ValidateNotNull")][Switch]$NotNull,
[Parameter(ParameterSetName="ValidateNotNullOrEmpty")][Switch]$NotEmpty
)
   $Variable = Get-Variable $Name -Scope 1

   if($ScriptBlock) {
      $Attribute = new-object System.Management.Automation.ValidateScriptAttribute $ScriptBlock
      $Variable.Attributes.Add($Attribute)
   }
   if($MinCount -or $MaxCount) {
      if(!$MinCount) { $MinCount = [Int]::MinValue }
      if(!$MaxCount) { $MaxCount = [Int]::MaxValue }
      $Attribute = new-object System.Management.Automation.ValidateCountAttribute $MinCount, $MaxCount
      $Variable.Attributes.Add($Attribute)
   }
   if($MinLength -or $MaxLength) {
      $Attribute = new-object System.Management.Automation.ValidateLengthAttribute $MinLength, $MaxLength
      $Variable.Attributes.Add($Attribute)
   }
   if($Pattern) {
      $Attribute = new-object System.Management.Automation.ValidatePatternAttribute $Pattern
      $Variable.Attributes.Add($Attribute)
   }
   if($MinValue -or $MaxValue) {
      $Attribute = new-object System.Management.Automation.ValidateRangeAttribute $MinValue, $MaxValue
      $Variable.Attributes.Add($Attribute)
   }
   if($Set) {
      $Attribute = new-object System.Management.Automation.ValidateSetAttribute $Set
      $Variable.Attributes.Add($Attribute)
   }
   if($NotNull) {
      $Attribute = new-object System.Management.Automation.ValidateNotNullAttribute
      $Variable.Attributes.Add($Attribute)
   }
   if($NotEmpty) {
      $Attribute = new-object System.Management.Automation.ValidateNotNullOrEmptyAttribute
      $Variable.Attributes.Add($Attribute)
   }
}

Как использовать:

#Добавим атрибут ValidateRange для переменной test,которая принимает значение в интервале 10-100.
PS >  $test = 10
PS >  Protect-Variable test -MinValue 10 -MaxValue 100

Остальные примеры, можно посмотреть в книге, а также описание и использование – этих атрибутов, можно посмотреть в справке по расширенным функциям.

Get-Help about_functions_advanced_parameters

Что изменилось в V3,теперь данные атрибуты можно добавить, указав впереди переменной (возможно при объявлении).

#Добавим атрибут ValidateRange для переменной test,которая принимает значение в интервале 10-100.
PS > [ValidateRange(10,100)]$test = 42
PS > $test = 101
The variable cannot be validated because the value 101 is not a valid value for the test variable.
At line:1 char:1
+ $test = 101
+ ~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ValidationMetadataException
    + FullyQualifiedErrorId : ValidateSetFailure

#Добавим атрибут ValidateSet для переменной test,которая может принимать значение X,Y,Z.
PS > [ValidateSet("X","Y","Z")]$test = "X"
PS > $test = "hello"
The variable cannot be validated because the value hello is not a valid value for the test variable.
At line:1 char:1
+ $test = "hello"
+ ~~~~~~~~~~~~~~~
    + CategoryInfo          : MetadataError: (:) [], ValidationMetadataException
    + FullyQualifiedErrorId : ValidateSetFailure

Как мы видим, теперь работа с атрибутами упростилась.

Follow

Get every new post delivered to your Inbox.