Trace-Commnd 跟蹤管道參數傳遞

今天在powershell.com 看見了一個很有趣的問題。問題如下,有一個csv文件,大概內容是這樣的

wKioL1bov12Cq2-NAAAJxMn4ZLE508.png


然後請問爲什麼這個命令不工作?


import-csv name.csv | get-service

報錯:

wKioL1bov2HwbrdZAABRYtMWCx8609.png


理論上管道應該可以通過byvalue或者bypropertyname傳遞,get-service有-computername這個選項,前面導入的csv文件也有comutername這個屬性,理論上應該自動匹配纔對啊?那麼問題出在哪裏呢?

管道的基本實現方式參見 http://beanxyz.blog.51cto.com/5570417/1678609



我們可以用trace-command 命令來跟蹤具體發生了什麼

trace-command -PSHost -name ParameterBinding -Expression{
import-csv name.csv | get-service
}

首先是import-csv的命令,沒問題

wKiom1bowFCB3uaOAABnVGaWRSM955.png

然後接下來管道要把他獲取的內容傳遞給 get-service


注意看我以爲會自動匹配的computername並沒有自動匹配進去,反而是name這個參數匹配進去了!儘管他第一次匹配因爲類型不同忽略了,第二次他自動進行了一個類型轉換,強行和name匹配成功

wKiom1bo0huQADg0AAGFJlLHdwk665.png


原因何在呢? 查看一下get-service的幫助文檔。小技巧:我一般是使用-showwindows 或者-online,這樣我可以新開一個窗口進行搜索,不過win10和ps5有個bug,-show的內容不完善所以我使用在線查看。

help get-service -online


搜索byvalue,我們可以看見有兩個參數接受,分別是

-InputObject<ServiceController[]>

-Name<String[]>


搜索bypropertyname, 也有兩個參數接受這個方式:

-ComputerName<String[]>

-Name<String[]>


然後再看看position的參數, 發現-Name是設定爲1的,也就是說默認情況下如果我們沒有指定參數,他會認爲自動用-name來匹配對應的字符串!


wKiom1bo0qbxFvbHAABcEQEMmxA214.png


當管道嘗試匹配的時候,因爲我們沒有指定參數,他會自動用-Name參數來進行匹配,儘管他的類型對不上,他會自動把PSCustomObject轉換成字符串進行嘗試,這樣一來類型一樣了,他就自動匹配成了-Name而不是-ComputerName,因爲後者根本沒有機會來匹配。

wKioL1bowrzSsGkbAAAnQXvGXhs280.png


怎麼解決呢?很簡單我們需要明確告訴他哪些參數和屬性要配對。

比如

import-csv name.csv | get-service -name * -ComputerName {$_.computername}


或者

get-service -computername ((import-csv name.csv ).computername)

這樣就行啦。


還有一個類似的例子 (http://powershell.com/cs/blogs/donjones/archive/2011/12/10/troubleshooting-pipeline-parameter-binding-by-peeking-inside.aspx)


這個命令也不會工作,儘管管道前面和後面都有一樣的名字“computerName”

get-adcomputer -filter * | select @{n='computername';e={$_.name}} |invoke-command -ScriptBlock { dir }


爲什麼?因爲

  1. Invoke-command 的computername根本就不支持管道

  2. 他的-inputobject 接受任何類型!!也就是說任何嘗試傳遞給invoke-command的管道參數都會被接管,其他的管道參數設置是毫無用處的。


wKioL1bo2ZeQRS9UAADzoUyIqBw239.png

    wKioL1bo2g6hN0zqAABVv-HXO9U776.png

怎麼解決?和上面一樣直接跑吧 別用管道了

invoke-command -ScriptBlock { dir } -computername (get-adcomputer -filter * | select -expand name)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章