2

Starting from this Question I discovered that using the powershell.exe.config to load .net Framework 4.0 runtime, this code:

$word = "Thisisatest"
[System.String]::Join("-", $word.ToCharArray())

return System.Char[]

Executing Powershell w/o powershell.exe.config the same code works in the right way.

Someone can reproduce this issue and explain why??

My box is windows 7 pro with Powershell 2.0

Edit: my powershell.exe.config

<?xml version="1.0"?>
<configuration>
    <startup useLegacyV2RuntimeActivationPolicy="true">
         <supportedRuntime version="v4.0.30319"/>        
         <supportedRuntime version="v2.0.50727"/>        
    </startup>
</configuration>
Community
  • 1
  • 1
CB.
  • 58,865
  • 9
  • 159
  • 159
  • Can you post your `powershell.exe.config` ? – Andy Arismendi Feb 06 '12 at 20:31
  • 1
    Well at least I could reproduce on Windows XP 32bit w/ PS 2.0. When I commented out `` it returned the data instead of the type as expected so it has something to do with that. – Andy Arismendi Feb 06 '12 at 20:39
  • @AndyArismendi. Thank you for trying to reproduce it. Now I'm sure that is loading .net 4.0 runtime the issue. Some conflict in type call maybe? – CB. Feb 06 '12 at 20:41
  • So this works `[string]::Join("-" , (1,2,3))`. It's just that `ToCharArray` method. It could be an issue with `DotNetTypes.format.ps1xml` or just a bug. You might want to check the [Microsoft PowerShell Connect](http://connect.microsoft.com/PowerShell) site. – Andy Arismendi Feb 06 '12 at 20:46
  • yes. Doesn't work only with char[]! (1,2,3) is an object[]. – CB. Feb 07 '12 at 06:42

2 Answers2

2

This is due to the new overloads to string.Join added in version 4 of the .NET framework:

PS> [Environment]::Version.ToString()
2.0.50727.5456
PS> [string]::Join.OverloadDefinitions
static string Join(string separator, string[] value)
static string Join(string separator, string[] value, int startIndex, int count)


PS> [Environment]::Version.ToString()
4.0.30319.269
PS> [string]::Join.OverloadDefinitions
static string Join(string separator, Params string[] value)
static string Join(string separator, Params System.Object[] values)
static string Join[T](string separator, System.Collections.Generic.IEnumerable[T] values)
static string Join(string separator, System.Collections.Generic.IEnumerable[string] values)
static string Join(string separator, string[] value, int startIndex, int count)


In .NET 2.0, the only applicable method overload takes a string[] as the second argument, so each character from $word.ToCharArray() is coerced to a string.
PS> Trace-Command *Member* { [string]::Join( "-", $word.ToCharArray() ) } -PSHost
...
MemberResolution: Method argument conversion.
MemberResolution:     Converting parameter "-" to "System.String".
MemberResolution: Method argument conversion.
MemberResolution:     Converting parameter "System.Char[]" to "System.String[]".
MemberResolution: Calling Method: static string Join(string separator, string[] value)

In .NET 4, the object[] overload is preferred. Rather than boxing each character, the entire array is coerced to an object, sending a single-element object array to string.Join, which then has ToString called to produce the "System.Char[]" output.

Method argument conversion.
    Converting parameter "-" to "System.String".
Method argument conversion.
    Converting parameter "System.Char[]" to "System.Object".
Method argument conversion.
    Converting parameter "System.Object[]" to "System.Object[]".
Calling Method: static string Join(string separator, Params System.Object[] values)

To get the old behavior, you can insert a [string[]] cast to influence how the method is resolved (or in this case just use PowerShell's -join operator, which works correctly everywhere :).

PS> $word = 'test'
PS> [string]::Join( '-', $word.ToCharArray() )
System.Char[]
PS> [string]::Join( '-', [string[]]$word.ToCharArray() )
t-e-s-t
PS> [char[]]$word -join '-'
t-e-s-t
Emperor XLII
  • 13,014
  • 11
  • 65
  • 75
0

Use the solution I provided in the other question. That is the PowerShell supported method of achieving what you want to do:

"Thisisatest".ToCharArray() -join '-'

http://technet.microsoft.com/en-us/library/dd315375.aspx