2012-04-27 16 views
6

Ustawiam atrybut XML za pomocą String, a PowerShell mówi mi "tylko łańcuchy mogą być używane jako wartości do ustawienia właściwości XmlNode". Oto prosty przykład. Po pierwsze, to uruchomić:Dlaczego PowerShell mówi mi, że ciąg nie jest ciągiem? I tylko przy wywołaniu String.Length, najpierw

$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) 

Dla mnie wyjście jest:

$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 

Ten komunikat ma być błędne. Wartość po prawej stronie znaku równości to ciąg, jak pokazano na powyższym wyjściu. Ale uległo ono erozji, więc atrybut XML nadal brzmi "a". Teraz robi się jeszcze dziwniej. Skomentuj linię, która wywołuje $ newId.length i zobacz, jak działa poprawnie.

Komentując jako taki: #$length = $newId.Length. Wyjście jest teraz:

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

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

ComponentRef.Id is now: b 

Nie pytam o kropce, bo wiem, jak obejść ten problem poprzez odlewanie na [ciąg] po prawej stronie ostatniego operatora przypisania. Co chciałbym wiedzieć to:

Czy ktoś może wyjaśnić, dlaczego wywołanie $ newId.Length (getter!) Może spowodować, że PowerShell uzna, że ​​$ newId nie jest już ciągiem znaków?

Dzięki!

+0

Wygląda na to, że problem tkwi gdzieś w sposobie, w jaki obiekty PowerShell są zaadaptowane z obiektów root .NET (na przykład w C# nie mogłeś t wywołaj xmlDoc.root - root jest właściwością, którą PS dodaje). To powinno być przezroczyste dla PS i dowolnych obiektów .NET, które napotykasz, więc nie jestem pewien, dlaczego ten wysadza w powietrze. $ xmlDoc.root.ComponentRef.SetAttribute ("Id", $ newId) na przykład działa dobrze. Bardzo dziwne ... –

+0

To musi być coś takiego. Na pewno dziwne, że wywołanie długości go uruchomi. Sprawia, że ​​myślę, że to błąd PowerShell. Być może to jest tak daleko, jak odpowiedź pójdzie, zobaczymy;) Nie jestem pewien, czy zespół PowerShell przyjmuje zgłoszenia błędów od ogółu, czy też nie. – Vimes

+1

JohnB robią raporty o błędach - zaloguj się, aby połączyć się z witryną.microsoft.com/powershell z identyfikatorem Live i zgłoś błąd za pomocą repro. – x0n

Odpowiedz

6

Jest to niefortunny błąd w rozszerzonym systemie typu V2, w którym można utworzyć opakowanie typu psobject wokół podstawowego typu .NET. Może się to zdarzyć, gdy dodasz członków do obiektu lub gdy uzyskasz dostęp do właściwości, która nie istnieje. Może się to również zdarzyć, gdy uzyskasz dostęp do właściwości IIRC obiektu np. psobject, np. $newId.psobject. Podczas pobytu w PowerShell zwykle nie powoduje to żadnych problemów.

Aktualizacja: Nie jest to problem wywołujący .NET. Niektóre szybki kod testowy .NET pokazuje, że pobiera on nieopakowany obiekt dla narzędzia ustawiającego właściwości. Po patrząc na to z Trace-Command wydaje się być błąd w PowerShell za XmlNodeAdapater:

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) 

Jednym ze sposobów, aby upewnić się zawsze uzyskać obiekt base .NET jest:

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

Dobrą wiadomością jest to, że ten problem jest ustalone w V3, np .:

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

Daje poczucie, że przyczyną problemu jest adapter XML. To wyjaśniałoby, dlaczego cofa się metoda .NET SetAttribute: $ xmlDoc.root.ComponentRef.SetAttribute ("Id", $ newId) –

+0

Mam ten sam problem w wersji 5.0 (Windows 10).Wygląda na to, że ta "cecha" pojawia się ponownie ... –

+0

Skrypt OP działa dla mnie w wersji 5.0 5.0.10130.0. Którą wersję 5.0 używasz? –

Powiązane problemy