Powershell hashtable does not write to file as expected - receive only "System.Collections" rows
Can someone please explain Why my first examples don't work, and why adding in a ForEach-Object solves the problem? Thanks in advance!
I parsed the return from a command into a hashtable (sample at end of post) and want to log the information to a file as part of my processing. I know that $ht.GetEnumerator() | Sort-Object Name
will return the full hash to screen, sorted. However, once I try sending things to file, it breaks.
$ht | Add-Content log.txt
only logs a single row of System.Collections.Hashtable
. So, I've also tried
$ht.GetEnumerator() | Sort-Object Name | Add-Content log.txt
and end up with rows of
System.Collections.DictionaryEntry
System.Collections.DictionaryEntry
System.Collections.DictionaryEntry
So then I tried to loop through and handle each individually开发者_C百科 with
foreach ($key in $ht.keys) {
Add-Content log.txt "$key : $ht.$key" }
and end up with
Server address : System.Collections.Hashtable.Server address
Client address : System.Collections.Hashtable.Client address
User name : System.Collections.Hashtable.User name
Solved with:
$ht.GetEnumerator() | Sort-Object Name |
ForEach-Object {"{0} : {1}" -f $_.Name,$_.Value} |
Add-Content log.txt
For reference, the hashtable sample:
$ht = @{
"Server address" = "server.net";
"Client address" = "10.20.121.153";
"User name" = "myuser"
}
Answering the why part, you obviously have a solution :)
In your first example
$ht | Add-Content log.txt
PowerShell takes $ht
and tries to somehow convert it to a string so that it can be stored via Add-Content
. Because there is no conversion defined for the hashtable, only the type name is returned from the conversion. Same as for example new-Object Random|Add-Content d:\log.txt
. Again, only type name is written.
Next
$ht.GetEnumerator() | Sort-Object Name | Add-Content log.txt
is similar. GetEnumerator
returns object that is used for iteration; objects of type System.Collections.DictionaryEntry
are returned. Again, there is no conversion to string, so type names are returned.
Personally, I think PowerShell should be smart enough and help here. The question is "how?". Designers probably didn't want to hardcode the output. It might be "{key}: {value}"
or "{key} = {value}"
, or "{key}/{value}"
, or ... The format is not clear, so they left it for us to decide and format as you did it with the foreach
statement.
I agree with mjolinor... just not enough points to vote up... plus i'll add that you dont need the GetEnumerator
$ht | out-string | add-content log.txt
will do it.
Your first example does not work, or better, partially works, because you are trying to get a property value within the string. Normally, inside strings, the parser is able to resolve only direct variables (like $key
). To resolve more complex variable you need parenthesis.
For the loop, this should work:
foreach ($key in $ht.keys) { Add-Content log.txt "$key : $($ht.$key)" }
or even better
$ht.keys | %{ Add-Content log.txt "$_ : $($ht.$_)" }
As you can see in Microsoft documentation a hash table is simply a collection of name-value pairs.
So $ht
is really System.Collections.Hashtable
composed of System.Collections.DictionaryEntry
.
A good way to use it is
foreach ($i in $ht.keys)
{
add-content log.txt ("{0} {1}" -f $i, $ht[$i])
}
How about:
$ht.GetEnumerator() | Sort-Object Name | out-string | Add-Content log.txt
You can write a "raw" dump of a hash table to an ASCII file using Out-File:
$data = @{
Name = "Something"
Type = "123"
}
$data | Out-File "myfile.txt" -Encoding ascii
精彩评论