Tee-Object to two pipelines? - powershell

I have the following code.
$summary = . {
while ($true) {
# Generating huge list of psobject
}
} |
Tee-Object -FilePath 'fname.csv' | # Need to process the input objects before writing to CSV
Group-Object -Property xxx | Select Name,Count
However, I need to process the input objects before writing to fname.csv. Is it possible to Tee the object to two pipelines?
I tried
$summary = . {
while ($true) {
# Generating huge list of psobject
}
} |
For-Each {
$_ | ConvertTo-Csv -NoTypeInformation | Out-File -Append 'file.csv'
$_
} |
Group-Object -Property xxx | Select Name,Count
But the headers are repeated every line in file.csv.

I'm not sure what you want to do. Does this help? The objects from get-process get passed to two different pipelines.
get-process cmd | foreach-object { $_ | measure-object
$_ | export-csv -append whatever.csv }

This should do the work in the question. It doesn't Tee to two pipelines, which may be needed for some use cases, though.
$summary = . {
while ($true) {
# Generating huge list of psobject
}
} |
ForEach {
$_ | Export-Csv -NoTypeInformation -Append 'file.csv'
$_
} |
Group-Object -Property xxx | Select Name,Count

Going after #mklement0 's guidance, does the below make it any simpler,
Get-Process excel | Tee-Object -Variable process | group processname | select name, count
$process | Export-Csv "D:\Op_GetProcessExcel.csv" -NoTypeInformation
Previous suggestion
As #AnsgarWiechers pointed out something like the following should work for you,
Get-Process |
group processname |
select name, count |
ConvertTo-Csv -NoTypeInformation |
Tee-Object "C:\Op_GetProcess.csv"

Related

Output to txt and cvs as one line

Good day,
I am looking to output result of a Get-NetTcpConnection into a txt and cvs files simultaneously.
This is how I do it now:
$netstat = Get-NetTCPConnection | Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort,State
$netstat | Export-Csv -Path C:\temp\$env:COMPUTERNAME-$(Get-Date -Format yyyyMMdd-HH.mm).csv -NoTypeInformation
$netstat | FT -AutoSize | Out-File -FilePath C:\temp\$env:COMPUTERNAME-$(Get-Date -Format yyyyMMdd-HH.mm).txt
Is there a way to do that as a one liner instead of using a variable?
Something like this:
Get-NetTCPConnection | Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort,State |
Export-Csv -Path C:\temp\$env:COMPUTERNAME-$(Get-Date -Format yyyyMMdd-HH.mm).csv -NoTypeInformation;
$_ | FT -AutoSize | Out-File -FilePath C:\temp\$env:COMPUTERNAME-$(Get-Date -Format yyyyMMdd-HH.mm).txt
Thank you!
"Tee-object" is build to pass the data/output straight through the pipeline from one end to other end with out format.
Get-NetTCPConnection | Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort,State |Tee-Object -FilePath "C:\Users\Narayana\Desktop\Testing Dir\temp2.txt" | Export-Excel -Path "C:\Users\Narayana\Desktop\Testing Dir\temp2.xlsx"
I've tried many attempts to get this done in a one liner like you have requested but, have been fruitless.
However, you can always just make your own function to perform this work and run it as a one liner?
function Get-NetStat{
$netstat = Get-NetTCPConnection | Select-Object -Property CreationTime,LocalAddress,LocalPort,RemoteAddress,RemotePort,State
if ($netstat)
{
$netstat | Export-Csv -Path C:\temp\$env:COMPUTERNAME-$(Get-Date -Format yyyyMMdd-HH.mm).csv -NoTypeInformation
$netstat | FT -AutoSize | Out-File -FilePath C:\temp\$env:COMPUTERNAME-$(Get-Date -Format yyyyMMdd-HH.mm).txt
}
else
{
Write-Host $Error
}
}

Iterate server list with dbatools?

I am really new to PowerShell and still learning so I am having a requirement to run some of the commands from dbatools and save the results.
$servers = 'E:\DBA\servers.txt'
$outfile = 'E:\DBA\out.csv'
Get-Content $servers | ForEach-Object {Invoke-Command DbaBackupHistory -SQLServer $_ | ConvertTo-CSV -NoTypeInformation | Select-Object -Skip 1 | Out-File -Append $outFile}
I am unsure if this is the correct way to doit
https://dbatools.io/functions/get-dbabackuphistory/
I modified you script and tested. Worked for me. I added 2 more switches to limit result set. -database and -lastfull. You can check documentation for details.
$outfile = 'c:\out.csv'
Get-Content c:\servers.txt|foreach-object {get-DbaBackupHistory -SqlServer $_
-database dbadatabase -lastfull | ConvertTo-CSV -NoTypeInformation |
Select-Object -Skip 1 | Out-File -Append $outFile}

Why won't my script run?

I've built the following PowerShell script and it doesn't seem to work:
"\\example\examplepath\" | % { $_ | select name, #{n="lines"; e={ get-content
$_.FullName | measure-object -line | Select -expand lines } } } | ft -
Autosize | Out-file c:\counts\result.csv
The script is supposed to get a line count for each file and output them to a CSV. Admittedly there around 140,000 files in the folder. Any ideas?
You are missing the Get-ChildItem cmdlet to retrieve all files. The Foreach-Object (%) cmdlet is obsolete here so I removed it. I also removed the Format-Table cmdlet because you are piping the result to Out-File:
Get-ChildItem "\\example\examplepath\" |
Select-Object name, #{n="lines"; e={ get-content $_.FullName | measure-object -line | Select-Object -expand lines } } |
Out-file c:\counts\result.csv

PowerShell stdout and redirect

I would like to build powershell pipeline like
cmd | transform_a | stdout_and | transform_b | store_variable
^
|
copy input to next consumer and to console
I tried to utilize Tee-Object but without success. I dont want to do this
dir | select -last 5 | tee lastFiveLines | select -first 1
echo $lastFiveLines
altough it works. Instead I want the content to be printed directly.
You can try a foreach-loop and Out-Default or Out-Host to skip the rest of the pipeline (Host is Default output anyways), while also sending the object down the pipeline. Sample:
Get-ChildItem |
Select-Object Name, FullName |
ForEach-Object {
#Send Name-value directly to console (default output)
$_.Name | Out-Default
#Send original object down the pipeline
$_
} |
Select-Object -ExpandProperty FullName | % { Start-sleep -Seconds 1; "Hello $_" }
You can create a filter to make it easy to reuse it.
#Bad filter-name, but fits the question.
filter stdout_and {
#Send Name-value directly to console (default output)
$_.Name | Out-Default
#Send original object down the pipeline
$_
}
Get-ChildItem |
Select-Object Name, FullName |
stdout_and |
Select-Object -ExpandProperty FullName | % { Start-sleep -Seconds 1; "Hello $_" }

powershell group object and create csv with new header header

In Windows Powershell, how can I change the csv output format of executing this command:
$logs = 'System'
$today = (Get-Date).Date
$logs | foreach{
get-eventlog -log $_ -After ([datetime]::today) |
group eventid,EntryType -noel |
sort count -desc |
export-csv "eventLog_$_.csv" -notype
}
My output must be :
"Values","Count","Group","ID","Severity"
"System.Collections.ArrayList","1085","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","1501", "Information"
"System.Collections.ArrayList","15","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","37", "Information"
"System.Collections.ArrayList","13","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","1500", "Information"
"System.Collections.ArrayList","8","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","20001", "Information"
But when running the command above, I got this output instead:
"Values","Count","Group","Name"
"System.Collections.ArrayList","1085","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","1501,Information"
"System.Collections.ArrayList","15","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","37,Information"
"System.Collections.ArrayList","13","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","1500,Information"
"System.Collections.ArrayList","8","System.Collections.ObjectModel.Collection`1[System.Management.Automation.PSObject]","20001,Information"
Is there a better way than replacing with csv file modification ?
I not sure why you would want a bunch of lines in your file like "System.Collections.ArrayList" and so forth. You output that you should expect from your command is
Count Name
----- ----
116 7036, Information
5 7040, Information
1 206, Information
1 14204, Information
1 7001, Information
1 201, Information
The extra information can be stripped out with a simple Select-Object. The for each loop is not required unless you acutually have something more in $logs. If the case then you should have -Append on your Export-Csv. You also dont use $today
$logs = 'System'
get-eventlog -log $logs -After ([datetime]::today) |
Group-Object EventID,EntryType -NoElement |
Sort-Object Count -Descending |
Select-Object count,name |
Export-Csv C:\temp\test.txt -NoTypeInformation
A bonus to help
The above answer might be sufficient but this adds a little to it. I mentioned that your loop seemed odd. If you are looking at other logs than System then i could see a point. I have an example below. Also the return for Name contains both and eventID and EventType and we could do something about that. I create a PSCustomObject that splits the Name into its two parts.
$logs = 'System','Application'
$logs | ForEach-Object{
get-eventlog -log $_ -After ([datetime]::today) |
Group-Object EventID,EntryType -NoElement |
Sort-Object Count -Descending |
Select-Object count,name | ForEach-Object{
[PSCustomObject]#{
'EventID' = ($_.Name -split ", ")[0]
'EventType' = ($_.Name -split ", ")[1]
'Count' = $_.Count
}
}
} | Export-Csv C:\temp\test.txt -NoTypeInformation
The CSV output looks a little better now. The following is from the truncated csv
"EventID","EventType","Count"
"7036","Information","118"
"7040","Information","5"
"102","Information","1"
"902","0","1"
"300","Information","1"
"10","Error","1"
"302","Information","1"
If you only have powershell 2.0 you wont have access to [PSCustomObject] in which cause you could do the following instead. Notice the array $csv that is built in the ForEach loop and is then piped into Export-Csv
$csv = #()
$logs = 'System','Application'
$logs | ForEach-Object{
get-eventlog -log $_ -After ([datetime]::today) |
Group-Object EventID,EntryType -NoElement |
Sort-Object Count -Descending |
Select-Object count,name | ForEach-Object{
$properties = #{
'EventID' = ($_.Name -split ", ")[0];
'EventType' = ($_.Name -split ", ")[1];
'Count' = $_.Count;
}
$psobject = new-object psobject -Property $properties
$csv += $psobject
}
}
$csv | Export-Csv C:\temp\test.txt -NoTypeInformation