2012-04-27 20 views
6

Tôi đang thiết lập thuộc tính XML bằng String và PowerShell cho tôi biết "chỉ các chuỗi có thể được sử dụng làm giá trị để đặt thuộc tính XmlNode". Đây là một ví dụ đơn giản. Trước tiên, tôi chạy này:Tại sao PowerShell cho tôi biết một chuỗi không phải là một chuỗi? Và chỉ khi gọi String.Length, đầu tiên là

$xmlDoc = [xml]@" 
<root> 
    <ComponentRef Id="a" /> 
</root> 
"@ 

$newId = "b" 

$length = $newId.Length 

Write-Host ("`n`$newId is a string, see: `$newId.GetType().FullName = " + $newId.GetType().FullName + "`n") 
Write-Host ("Running `"`$xmlDoc.root.ComponentRef.Id = `$newId`"...`n") 
$xmlDoc.root.ComponentRef.Id = $newId 
Write-Host ("ComponentRef.Id is now: " + $xmlDoc.root.ComponentRef.Id) 

Đối với tôi, kết quả là:

$newId is a string, see: $newId.GetType().FullName = System.String 

Running "$xmlDoc.root.ComponentRef.Id = $newId"... 

Cannot set "Id" because only strings can be used as values to set XmlNode properties. 
At D:\Build\Tools\mass processing\Untitled4.ps1:14 char:27 
+ $xmlDoc.root.ComponentRef. <<<< Id = $newId 
    + CategoryInfo   : InvalidOperation: (:) [], RuntimeException 
    + FullyQualifiedErrorId : PropertyAssignmentException 

ComponentRef.Id is now: a 

Đó thông báo lỗi đã có thể sai. Giá trị ở bên phải của dấu bằng một Chuỗi, như được hiển thị trong đầu ra ở trên. Nhưng nó sai, vì vậy thuộc tính XML vẫn đọc "a". Bây giờ nó được weirder. Hãy bình luận ra dòng gọi $ newId.length và xem nó hoạt động chính xác.

Nhận xét như vậy: #$length = $newId.Length. Kết quả hiện tại là:

$newId is a string, see: $newId.GetType().FullName = System.String 

Running "$xmlDoc.root.ComponentRef.Id = $newId"... 

ComponentRef.Id is now: b 

Tôi không yêu cầu khắc phục, vì tôi biết cách giải quyết vấn đề này bằng cách truyền tới [string] ở bên phải của toán tử gán cuối cùng. Điều tôi muốn biết là:

Bất cứ ai có thể giải thích lý do tại sao gọi $ newId.Length (getter!) Có thể khiến PowerShell nghĩ $ newId không còn là chuỗi nữa?

Cảm ơn!

+0

Có vẻ vấn đề ở đâu đó trong cách đối tượng PowerShell được điều chỉnh từ đối tượng .NET gốc (ví dụ: trong C# bạn không thể ' t gọi xmlDoc.root - root là thuộc tính mà PS đang thêm). Điều này phải rõ ràng đối với PS và đối với bất kỳ đối tượng .NET nào bạn gặp phải, vì vậy tôi không chắc chắn tại sao đối tượng này lại bị thổi phồng lên. $ xmlDoc.root.ComponentRef.SetAttribute ("Id", $ newId) cho ví dụ hoạt động tốt. Rất lạ ... –

+0

Nó phải giống như thế. Nó chắc chắn kỳ lạ mà gọi Length sẽ kích hoạt nó. Làm tôi nghĩ đó là lỗi PowerShell. Có lẽ đó là như xa như câu trả lời sẽ đi, chúng ta sẽ thấy;) Tôi không chắc liệu nhóm PowerShell có báo cáo lỗi từ công chúng hay không. – Vimes

+1

JohnB họ thực hiện báo cáo lỗi - đăng nhập vào connect.microsoft.com/powershell bằng id trực tiếp và đăng nhập lỗi bằng repro. – x0n

Trả lời

6

Đây là lỗi không may trong hệ thống loại mở rộng V2, trong đó trình bao bọc psobject có thể được tạo xung quanh loại .NET cơ bản. Điều này có thể xảy ra khi bạn thêm thành viên vào đối tượng hoặc khi bạn truy cập thuộc tính không tồn tại. Điều này cũng có thể xảy ra khi bạn truy cập thuộc tính psobject trên một đối tượng IIRC, ví dụ: $newId.psobject. Khi bạn ở trong PowerShell, điều này thường không gây ra bất kỳ vấn đề nào.

Cập nhật: Đây không phải là vấn đề khi gọi đến .NET. Một số mã kiểm tra .NET nhanh chóng cho thấy rằng nó nhận được một đối tượng chưa được mở cho một trình thiết lập thuộc tính. Sau khi xem xét điều này với Trace-Command nó dường như là một lỗi trong XmlNodeAdapater PowerShell của:

DEBUG: ETS Information: 0 : Method  Enter PSObject..ctor():object = System.Management.Automation.RuntimeException: 
Cannot set "Id" because only strings can be used as values to set XmlNode properties. ---> 
System.Management.Automation.SetValueException: Cannot set "Id" because only strings can be used as values to set 
XmlNode properties. 
    at System.Management.Automation.XmlNodeAdapter.PropertySet(PSProperty property, Object setValue, Boolean 
convertIfPossible) 
    at System.Management.Automation.Adapter.BasePropertySet(PSProperty property, Object setValue, Boolean convert) 
    at System.Management.Automation.PSProperty.SetAdaptedValue(Object setValue, Boolean shouldConvert) 
    at System.Management.Automation.PSProperty.set_Value(Object value) 
    at System.Management.Automation.PropertyReferenceNode.SetValue(PSObject obj, Object property, Object value, 
ExecutionContext context) 
    --- End of inner exception stack trace --- 
    at System.Management.Automation.PropertyReferenceNode.SetValue(PSObject obj, Object property, Object value, 
ExecutionContext context) 
    at System.Management.Automation.AssignablePropertyReference.SetValue(Object value, ExecutionContext context) 
    at System.Management.Automation.AssignmentStatementNode.Execute(Array input, Pipe outputPipe, ExecutionContext 
context) 
    at System.Management.Automation.StatementListNode.ExecuteStatement(ParseTreeNode statement, Array input, Pipe 
outputPipe, ArrayList& resultList, ExecutionContext context) 

Một cách để đảm bảo bạn luôn luôn nhận được đối tượng base NET là:

$xmlDoc.root.ComponentRef.Id = $newId.psobject.baseobject 

Tin tốt là vấn đề này được sửa trong V3 ví dụ:

PS> $xmlDoc = [xml]@" 
<root> 
    <ComponentRef Id="a" /> 
</root> 
"@ 

PS> $newId = "b" 

PS> $newId.Length 
1 

PS> $newId.psobject.typenames 
System.String 
System.Object 

PS> $xmlDoc.root.ComponentRef.Id = $newId 

PS> $xmlDoc | format-xml # From PowerShell Community Extensions 
<root> 
    <ComponentRef Id="b" /> 
</root> 
+1

Làm cho cảm giác rằng bộ điều hợp XML đang gây ra sự cố. Điều đó sẽ giải thích tại sao lại quay trở lại phương thức .NET SetAttribute: $ xmlDoc.root.ComponentRef.SetAttribute ("Id", $ newId) –

+0

Tôi có cùng một vấn đề trong 5.0 (windows 10).Có vẻ như "tính năng" này đang xuất hiện trở lại ... –

+0

Kịch bản lệnh của OP hoạt động với tôi trên 5.0 build 5.0.10130.0. Bạn đang chạy phiên bản 5.0 nào? –

Các vấn đề liên quan