Why does PowerShell tell me that String is not a string? And only when calling String.Length, first

I set the XML attribute using String, and PowerShell tells me: "Only strings can be used as values ​​to set XmlNode properties." Here is a simple example. First, I run this:

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

For me, the conclusion is:

 $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 

This error message must be erroneous. The value on the right side of the equal sign is a string, as shown in the output above. But this is a mistake, so the XML attribute still reads "a". Now it is getting weirder. Let's comment on the line that calls $ newId.length, and watch how it works correctly.

Commenting as such: #$length = $newId.Length . Now the conclusion:

 $newId is a string, see: $newId.GetType().FullName = System.String Running "$xmlDoc.root.ComponentRef.Id = $newId"... ComponentRef.Id is now: b 

I am not asking for a fix because I know how to get around this problem by going to [string] on the right side of the last assignment statement. I'd like to know:

Can someone explain why calling $ newId.Length (getter!) Might make PowerShell think that $ newId is no longer a string?

Thank!

+6
powershell
Apr 27 '12 at 17:58
source share
1 answer

This is an unsuccessful bug in an extended type V2 system where a psobject can be created around a base .NET type. This can happen when adding elements to an object or when accessing a missing property. This can also happen when you access the psobject property on an IIRC object, for example. $newId.psobject . When you stay in PowerShell, this usually does not cause any problems.

Update: This is not a .NET calling problem. Some quick .NET test code shows that it gets a deployed object for a property setting tool. Looking at it with Trace-Command , it looks like an error in the PowerShell 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) 

One way to ensure that you always get a base .NET object:

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

The good news is that this problem is fixed in V3, for example:

 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> 
+6
Apr 27 '12 at 23:19
source share



All Articles