Strange output combining Tee-object and $(Get-Date) - powershell

I am trying to append output to a .txt file. My command is as follows:
ni C:\example\example.txt -type file -value "`n$(Get-Date)"|out-null
$CSVvariable | sort Property | Format-Table | Tee-Object -Append -FilePath C:\example\example.txt
When I run the command I get the following output in the .txt file:
《⼹㔰㈯㄰″㤱㐺㨹
(The table is being presented correctly.)
$(Get-Date) seems to become the above symbols. Anyone have an idea why ?
Thanks in advance.

You don't really want to use format-table inside a pipeline like this. The output of format-table is a collection of "formatting objects" that the host interprets and are pretty much incomprehensible. The last time I checked, they weren't even documented well.
If you really want the table formatting, you can try adding out-string to the pipeline before the tee-object, but at that point you'll have a collection of strings, not "objects".
That's a separate issue from why you got strange characters, but I'd try removing the format-table and see how the file looks.

What is your CultuerInfo?
([System.Threading.Thread]::CurrentThread.CurrentCulture).DateTimeFormat
It seems like it might be set to something other than en-US.

Related

POWERSHELL: Simplest way to save string variable to csv file

I know a little bit of Bash scripting, but I am very new to PowerShell. When I execute below code using bash, everything is fine. But, when I use PowerShell, each entry per echo is saved only in a single cell in Excel. Why is it like this? How can I accomplish my objective in the simplest way?
echo "1,2,3" > file.csv
echo "A,B,C" >> file.csv
UNDESIRED:
DESIRED:
I tried to Google it. But, in my understanding, they are converting the string type variables to something like PS Object and convert to CSV format. I tried it and it worked. But I had to force include a header.
New-Object -Type PSObject -Property #{
'X' = $A
'Y' = $B
'Z' = $C
} | Export-Csv 'C:\Temp\test.csv' -NoType
When I also opened the csv file using notepad, every word has double quotation marks (which I don't prefer to have)
You see, that is way more complicated compared to Linux Scripting. Can someone teach me the simplest way to do what I want? Thank you very much!
If in your system locale the ListSeparator character is NOT the comma, double-clicking a comma-delimited csv file will open Excel with all values in the same column.
I believe this is what happens here.
You can check by typing
[cultureinfo]::CurrentCulture.TextInfo.ListSeparator
in PowerShell
To have Excel 'understand' a CSV when you double-click it, add -UseCulture switch to the cmdlet:
Export-Csv 'C:\Temp\test.csv' -UseCulture -NoTypeInformation
As for the quotes around the values:
They are not always necessary, but sometimes essential, for instance if the value has leading or trailing space characters, or if the value contains the delimiter character itself.
Just leave them as-is, Excel knows how to handle that.
If you really can't resist on having a csv without quotes, please first have a look at the answers given here about that subject.
Edit
If you are absolutely sure all fields can do without quoting, you can do this:
$sep = [cultureinfo]::CurrentCulture.TextInfo.ListSeparator
"1,2,3", "A,B,C" -replace ',', $sep | Out-File -FilePath 'D:\Test\file.csv' -Encoding utf8

Select-Object join behavior in scripts

In this post some is surprised that the following example doesn't work properly when run in a script
get-process | select-object cpu, name
dir | Select-Object name, length
When I put this in a script the second command doesn't show the length
And the answer to this:
PowerShell is joining both outputs. You could pipe the first output to
Format-Table [-auto] if you don't mind the format. Alternatively, you
can separate the first output from the following formatted output by
piping it to Out-Default, Out-Host, Out-string or Write-host
Now my question is why is it joining the output of those two seemingly unrelated commands and why doesn't this happen in the interactive console? They are not connected with a pipe. How does this work?
It seems that I still haven't quite understood basic concepts about piping in scripts.
See if this helps: blogs.msdn.com/b/powershell/archive/2006/04/30/586973.aspx
This issue isn't really the pipeline, but the default console formatting

piping get-childitem into select-string in powershell

I am sorting a large directory of files and I am trying to select individual lines from the output of an ls command and show those only, but I get weird results and I am not familiar enough with powershell to know what I'm doing wrong.
this approach works:
ls > data.txt
select-string 2012 data.txt
rm data.txt
but it seems wasteful to me to create a file just to read the data that I already have to fill into the file. I want to pipe the output directly to select-string.
I have tried this approach:
ls | select-string 2012
but that does not give me the appropriate output.
My guess is that I need to convert the output from ls into something select-string can work with, but I have no idea how to do that, or even whether that is actually the correct approach.
PowerShell is object-oriented, not pure text like cmd. If you want to get fileobjects(lines) that were modified in 2012, use:
Get-ChildItem | Where-Object { $_.LastWriteTime.Year -eq 2012 }
If you want to get fileobjects with "2012" in the filename, try:
Get-ChildItem *2012*
When you use
ls | select-string 2012
you're actually searching for lines with "2012" INSIDE every file that ls / get-childitem listed.
If you really need to use select-string on the output from get-childitem, try converting it to strings, then splitting up into lines and then search it. Like this:
(Get-ChildItem | Out-String) -split "`n" | Select-String 2012
I found another simple way to convert objects to strings:
Get-ChildItem | Out-String -stream | Select-String 2012
in this very interesting article:
http://blogs.msdn.com/b/powershell/archive/2006/04/25/how-does-select-string-work-with-pipelines-of-objects.aspx
If you wanted Select-String to work on the Monad formatted output, you'll need to get that as a string. Here is the thing to grok about
our outputing. When your command sequence emits a stream of strings,
we emit it without processing. If instead, your command sequence
emits a stream of objects, then we redirect those objects to the
command Out-Default. Out-Default looks at the type of the object and
the registered formating metadata to see if there is a default view
for that object type. A view defines a FORMATTER and the metadata for
that command. Most objects get vectored to either Format-Table or
Format-List (though they could go to Format-Wide or Format-Custom).
THESE FORMATTERS DO NOT EMIT STRINGS! You can see this for yourself
by the following: "These formating records are then vectored to an
OUT-xxx command to be rendered into the appropriate data for a
particular output device. By default, they go to Out-Host but you can
pipe this to Out-File, Out-Printer or Out-String. (NOTE: these
OUT-xxx commands are pretty clever, if you pipe formating objects to
them, they'll render them. If you pipe raw object to them, they'll
first call the appropriate formatter and then render them.)

why export-csv returns a file that contains wierd data?

I have a binary cmdlet Get-CustomPSObject. When I do something like:
Get-CustomPSObject > a.txt
the result is stored as a plain text, meaning that the Get-CustomPSObject is working fine.
However when I try:
Get-CustomPSObject | Export-csv a.csv
The a.csv file becomes:
"Capacity","Count","IsReadOnly","IsFixedSize","SyncRoot","IsSynchronized"
"4","1","False","False","System.Object","False"
none of these fields are in my PSObject. I've no idea what they stands for. Any thoughts?
Export-CSV takes the first object it recieves to create the headers. Most likely, your Get-CustomPSOjbect runs a method/cmdlet/script that returns an object you didn't save. E.g. you use something like
get-childitem
and not
$files = get-childitem
inside your Get-CustomPSObject function.
EDIT
Okay, so you're cmdlet is a binary cmdlet. Important information. I'm no expert in this, so please correct me if I'm wrong.
When you make a binary cmdlet that can output multiple objects, you need to write them one by one. One of the ideas behind PowerShell is the use of a pipeline that can use objects as they come without waiting for the complete array.
Because of your current "design flaw" in your binary cmdlet, Export-CSV tries to export the array(as one item) to a csv-file and not the elements inside.
You now use this:
WriteObject(list/array of objects)
This is bad. It outputs all objects at the same time.
To fix it, run this at the end of your "object-creation-loop":
WriteObject(mycurrentobject)
This is good. You enable the use of pipeline and every object is sent out one by one when they're created. Export-CSV can then recieve each object and convert them to csv-format.
In your first example using > the output is run through Powershell formatting system while in the second using export-csv it is not.
If you look at get-custompsobject | gm you should see those extra properties that aren't shown in console or sent to your text file.
For export-csv you can control which properties are sent to the csv file using select-object
get-custompsobjct | select-object column1, column2 | export-csv a.csv

Powershell - Getting a directory to output a file at a time

I'm super new at all of this so please excuse my lack of technical elegance and all around idiocy.
dir c:\Users\me\desktop\Test\*.txt | %{ $sourceFile = $_; get-content $_} | Out-File "$sourceFile.results"
How can I modify this command line so that instead of one file with the contents of all the text files I have a one to one ratio so that each output files represents the contents of each text file?
I realize that this object is ridiculous in terms of application but I'm conceptually trying to piece this together bit by bit so I can really understand.
P.S. What's with the %? Haha another ridiculous question, doesn't seem worth a separate post, what does it do?
dir | % { Out-File -FilePath "new_$($_.Name)" -InputObject (gc $_.FullName) }
only one pipeline needed. this command appends "new_" to the filename because I was using the same directory to write to. You can remove this if it's not needed.