這個文章主要是把一些Powershell經常讓人覺得不習慣的地方,和一些內部處理的方式介紹一下。學 一門高級語言,經常會被它的方便,讓你覺得雲裡霧裡,不過我喜歡POWERSHELL的原因,是因為它是裸體 的(至少是若隱若現),呵呵,哪怕它沒有公開它的源代碼,但是卻把實現的邏輯通過Trace-Command公 開了出來。好了,現在正是開始。我比較膚淺,所以說的東西也一樣,但是希望有拋磚引玉的偉大作用。
1. Return的作用
我在想,會不會有人說,"啊?RETURN這麼簡單都講?會編程的都知道."但是我還是忍不住,說一下在 POWERSHELL的RETURN的不同,一般的語言,"retrun"有終止函數和返回結果的作用.但是在 POWERSHELL,RETURN就只有前者.不過這個純屬推測,因為表象讓人這樣覺得.舉個例子:
function bar { Write-Host "123" "567" return "234"} $result = bar
這個時候,Result裡面會是什麼呢?答案是一個數組,裡面有567和234.因此可以推論,"567"這個本 來就有返回結果的能力,而RETURN "234"呢?就更像234;retrun的作用。那我們平常要怎樣打運行過程的 信息出去呢?就要用WRITE-HOST啦。嗯嗯。
2. ParameterBinding的真相
運行這個語句Trace-Command -Name ParameterBinding -PSHost -Expression {Get-Process -Name *sql*}
結果:
BIND NAMED cmd line args [Get-Process] BIND arg [*sql*] to parameter [Name] COERCE arg type [System.String] to [System.String[]] ENCODING arg into collection Binding collection parameter Name: argument type [String], parameter type [System.String[]], collection type Array, element type [System.String], coerceElementType Creating array with element type [System.String] and 1 elements Argument type String is not IList, treating this as scalar COERCE arg type [System.String] to [System.String] Parameter and arg types the same. Adding scalar element of type String to array position 0 Executing VALIDATION metadata: [System.Management.Automation.ValidateNotNullOrEmptyAttribute] BIND arg [System.String[]] to param [Name] SUCCESSFUL BIND POSITIONAL cmd line args [Get-Process] MANDATORY PARAMETER CHECK on cmdlet [Get-Process] CALLING BeginProcessing CALLING ProcessRecord CALLING EndProcessing
運行這些語句:
$b = (Get-Process explorer) Trace-Command -Name ParameterBinding -PSHost -Expression {$b | Get-Process }
BIND NAMED cmd line args [Get-Process] BIND POSITIONAL cmd line args [Get-Process] MANDATORY PARAMETER CHECK on cmdlet [Get-Process] CALLING BeginProcessing BIND PIPELINE object to parameters: [Get-Process] PIPELINE object TYPE = [System.Diagnostics.Process] RESTORING pipeline parameter's original values Parameter [InputObject] PIPELINE INPUT ValueFromPipeline NO COERCION BIND arg [System.Diagnostics.Process (explorer)] to parameter [InputObject] Binding collection parameter InputObject: argument type [Process], parameter type [System.Diagnostics.Process[]], collection type Array, element type [System.Diagnostics.Process], nocoerceElementType Creating array with element type [System.Diagnostics.Process] and 1elements Argument type Process is not IList, treating this as scalar Adding scalar element of type Process to array position 0 BIND arg [System.Diagnostics.Process[]] to param [InputObject] SUCCESSFUL MANDATORY PARAMETER CHECK on cmdlet [Get-Process] CALLING ProcessRecord CALLING EndProcessing
從兩個結果得出的結論:
a. 如果參數需要的是數組,POWERSHELL會自動把你的STRING轉成數組
b. Powershell 裡面有驗證綁定的參數的能力。 [System.Management.Automation.ValidateNotNullOrEmptyAttribute]就是其中一個。
c. 在PIPELINE中,也就是管道中的時候,會把System.Diagnostics.Process裝箱到psobject裡面,也 就所謂的OBJECT,在下個指令從管道中提取的時候,參數綁定到InputObject後(InputObject這個 PROPERTY支持的就是PSOBJECT),會做一個類似C#裡面的 OBJECT AS System.Diagnostics.Process的操 作,把Psobject恢復成PROCESS.然後也是遇到了數組的問題,還是把System.Diagnostics.Process轉換到 System.Diagnostics.Process[]裡面。
d. 一般InputObject都是BY VALUE的,為什麼呢?因為,我也不知道。以後知道了補上去。
補充ByPropertyName,證明強扭的程序,還是甜的:
BIND NAMED cmd line args [Get-Content] BIND POSITIONAL cmd line args [Get-Content] BIND cmd line args to DYNAMIC parameters. DYNAMIC parameter object: [Microsoft.PowerShell.Commands.FileSystemContentReaderDynamicParameters] MANDATORY PARAMETER CHECK on cmdlet [Get-Content] CALLING BeginProcessing BIND PIPELINE object to parameters: [Get-Content] PIPELINE object TYPE = [System.IO.FileInfo] RESTORING pipeline parameter's original values Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [Path] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [LiteralPath] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION BIND arg [Microsoft.PowerShell.Core\FileSystem::C:\WorkAtHome\WASP\WASP\Install.ps1] to parameter [LiteralPath] Binding collection parameter LiteralPath: argument type [String], parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType Creating array with element type [System.String] and 1 elements Argument type String is not IList, treating this as scalar Adding scalar element of type String to array position 0 BIND arg [System.String[]] to param [LiteralPath] SUCCESSFUL Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION MANDATORY PARAMETER CHECK on cmdlet [Get-Content] CALLING ProcessRecord BIND PIPELINE object to parameters: [Get-Content] PIPELINE object TYPE = [System.IO.FileInfo] RESTORING pipeline parameter's original values Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [Path] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [LiteralPath] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION BIND arg [Microsoft.PowerShell.Core\FileSystem::C:\WorkAtHome\WASP\WASP\UnInstall.ps1] to parameter [LiteralPath] Binding collection parameter LiteralPath: argument type [String],parameter type [System.String[]], collection type Array, element type [System.String], no coerceElementType Creating array with element type [System.String] and 1 elements Argument type String is not IList, treating this as scalar Adding scalar element of type String to array position 0 BIND arg [System.String[]] to param [LiteralPath] SUCCESSFUL Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName NOCOERCION Parameter [ReadCount] PIPELINE INPUT ValueFromPipelineByPropertyName WITHCOERCION Parameter [TotalCount] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION Parameter [Credential] PIPELINE INPUT ValueFromPipelineByPropertyName WITH COERCION MANDATORY PARAMETER CHECK on cmdlet [Get-Content] CALLING ProcessRecord CALLING EndProcessing
這裡有個特別的過程,因為FileInfo和FileInfo的每一個Property都不能MATCH,Get-Content的任意 一個ByPropertyName的屬性(-literalPath -path,-totalCount....).原理上,上面的語句應該是不通過 的。但是在黃色Highlight的地方會發現,在全部屬性不符合的時候,居然還是被它綁到了-literalPath 的屬性。為什麼呢?現在先看看literalPath是什麼。
-literalPath <string[]> Specifies the path to an item. Unlike Path, the value of LiteralPath is used exactly as it is typed. No charact ers are interpreted as wildcards. If the path includes escape characters, enclose it in single quotation marks. Single quotation marks tell Windows PowerShell not to interpret any characters as escape sequences.(會放到‘’裡面,不會轉換任何的轉義字符)。
好的,然後根據Effective powershell的描述,把那個POWERSHELL的CORE反編譯過來發現,
[Alias(new string[] { "PSPath" }), Parameter(Position = 0, ParameterSetName = "LiteralPath", Mandatory = true, ValueFromPipeline = false, ValueFromPipelineByPropertyName = true)] public string[] LiteralPath { }
意思就是這個LiteralPath還支持一個別的屬性,就PSPath。好了,現在問題來了,PSPath又是什麼呢 ,前面有PS開頭的,我猜測應該就是PS給一些自定義的屬性,像PYTHON一樣,可以在存在的對象之上附加 一些屬性,PSPath就是其中一個。為了提高GET-CONTENT和其他指令配合的可用性,Powershell在很多原 來的.net 的類之上,附加了一些屬性,PSPath就是附加在上面的屬性。相信其他的指令也有類似的情況 。有待發現:)
3. @的存在意義
運行一下語句:$b = (1,3,2,4)
$a = (4,2,1) Compare-Object $a $b (Compare-Object $a $b).Length @(Compare-Object $a $b).Length $ret1 = (Compare-Object $a $b) #PSCustomObject $b.GetType() $ret2 = @(Compare-Object $a $b) #object[]
運行的結果相信 已經讓你基本明白@是做什麼的,可能跟上面綁定的時候,把STRING轉化成OBJECT[] 一樣,也就是把東西轉成數組。