Reputation: 171
I have the following test script in powershell, the issue I am facing is that I want to store the details of the error in a custom object or a variable as a string, right now the value of the error variable is of type System.Collections.ArrayList.
invoke-sqlcmd -ServerInstance "$sql" -inputfile $file -Database test -OutputSqlErrors $true -ConnectionTimeout 10 -ErrorAction Continue -Errorvariable err | Out-Null
Now, here is what is strange, if I run
$err | Get-Type
its of type System.Collections.ArrayList
if i run write-host $err
, it prints out the error correctly, but assigning the value of $err
to a custom object, then I lose the value but get 'System.Collections.ArrayList'
instead.
$error_values += New-Object -TypeName psobject -Property @{ErrorMessage =$err}
Now running $error_values | select ErrorMessage returns System.Collections.ArrayList
I just need it to be a simple string, not sure what is incorrect here.
Upvotes: 2
Views: 7288
Reputation: 438188
Generally, don't use Write-Host
to output data, as that won't work; use it for display-only output only; to output data, use Write-Output
, or, better yet, use PowerShell's implicit output feature.
In your case, $error_values | select ErrorMessage
by itself would not only output the information of interest as data, it would also have resulted in helpful output formatting.
See this answer for more information.
Specifically, even when for-display-only output is desired, don't use Write-Host
to print representations of complex objects (loosely speaking, objects with properties);
use Out-Host
instead.
$error_values | select ErrorMessage | Out-Host
select
(Select-Object
) call is virtually a no-op; I presume what you actually meant was $error_values | select -ExpandProperty ErrorMessage
- see this answer for more information.Write-Host
does not perform rich output formatting, whereas PowerShell's default display formatting and Out-Host
do. Since Write-Host
uses simple .ToString()
stringification, complex objects usually result in unhelpful representations - see this answer for more information.A complete example:
# Create a sample ArrayList, as returned by
$err = [System.Collections.ArrayList] ('one', 'two')
# Construct a custom object ([pscustomobject]) with an .ErrorMessage
# property that contains the array list
$obj = [pscustomobject] @{ ErrorMessage = $err }
# !! Write-Host results in UNHELPFUL display:
# !! Note how instead of listing the *elements* of the ArrayList
# !! the *type name* ("System.Collections.ArrayList") is printed instead.
PS> Write-Host $obj
@{ErrorMessage=System.Collections.ArrayList}
# OK: Out-Host produces richly formatted *display-only* output.
PS> $obj | Out-Host
ErrorMessage
------------
{one, two}
# OK as well: *implicit* output, *as data* - same representation.
PS> $obj
ErrorMessage
------------
{one, two}
Note: For direct to-display output of a collection whose elements are not complex objects, Write-Host
can be helpful if single-line output is desired, because the elements are then simply space concatenated:
$err = [System.Collections.ArrayList] ('one', 'two')
# OK with collection of non-complex objects to get a
# *single-line* representation.
# Out-Host and implicit output print each element on its own line.
PS> Write-Host $err
one two
You can even use -Separator
to use a separator other than a space:
PS> Write-Host -Separator / 'one', 'two'
one/two
Of course, you can also use an expression to create such a string, using the -join
, the string joining operator operator, which would allow you to use the output as data:
PS> 'one', 'two' -join '/'
one/two
Optional reading: Why a target variable passed to -ErrorVariable
receives a System.Collections.ArrayList
instance:
The common -ErrorVariable
parameter - and indeed all common -*Variable
parameters that collect a stream's output in a variable - always return a System.Collections.ArrayList
instance with the collected output, which is surprising in two respects:
PowerShell generally uses [object[]]
arrays as its default collection data type.
Additionally, in the case of -OutVariable
, the behavior is inconsistent with direct output from the pipeline, where a single object output from a command is output as such - rather than being wrapped in a collection, such as ArrayList
in this case; that is, even though you would expect the following two commands to be equivalent, they're not:
$out = Get-Date
# -> $out is a [datetime] instance.
# !! -OutVariable *always* creates ArrayList.
$null = Get-Date -OutVariable out
# -> $out is a *single-element ArrayList* containing a [datetime] instance.
For a discussion of these inconsistencies, see GitHub issue #3154.
Upvotes: 1
Reputation: 856
$arrayList = [System.Collections.ArrayList]::new()
[void]$arrayList.Add("one")
[void]$arrayList.Add("two")
[void]$arrayList.Add("three")
$msg = $arrayList -join ", "
Write-Host $msg
Upvotes: 3