I've got all the information I need in a nice powershell table after running
get-mailbox | get-mailboxstatistics | ft displayname, totalitemsize
However the information gets changed to a single line of numbers and letters when I go to export it using:
| Export-Csv "C:\MailboxList.csv"
Is there a way to export the table as it's shows in the powershell shell?
Per the comment from Shaneis, this issue occurs because the ft (Formt-Table) cmdlet changes the object type and as such you cannot then use Export-Csv after it.
You should instead use Select-Object to filter your results down to the properties you want to output and then use Export-CSV after this:
get-mailbox | get-mailboxstatistics | select displayname, totalitemsize | Export-Csv "C:\MailboxList.csv"
Generally you use the Format-Table cmdlet as the last cmdlet when you want to output a nicely formatted table to the screen (although you can also send this output to a file with Out-File and it will appear in the file exactly as it does on screen).
To understand this issue in more detail, I recommend reading this article about how you should filter left, format right.
Related
In a nutshell I'm trying to get what would be the output of this command to run.
Get-Process | Format-Table | sort-object Handles
Yes, I know you usually sort BEFORE Format-Table, but in this case I've created a hash-table within the Format-Table command that needs to be sorted. The problem is, there is no way to sort with Format-Table that I can figure out.
I also considered trying to output the FT to CSV and then massaging it but that didn't work for me either.
I'm expecting to get a sorted table.
I've created a hash-table within the Format-Table command that needs to be sorted
By definition, you can not output a hashtable via any of the -Format-* cmdlets:
Format-* cmdlets emit output objects whose sole purpose is to provide formatting instructions to PowerShell's for-display output-formatting system. In short: only ever use Format-* cmdlets to format data for display, never for subsequent programmatic processing - see this answer for more information.
Assuming you've used calculated properties, with Format-Table, use them with Select-Object instead, which produces data output, namely in the form of [pscustomobject] instances whose properties you can sort by, via Sort-Object.
For instance, the following creates custom objects with .Name and .MemUse properties and sorts by the latter, then outputs the top 10 results:
Get-Process |
Select-Object Name, #{ Name = 'MemUse'; Expression = 'WorkingSet64' } |
Sort-Object -Descending MemUse |
Select-Object -First 10
Inverting the logic and letting Sort-Object operate on the original objects output by Get-Process is more efficient:
Get-Process |
Sort-Object -Descending WorkingSet64 |
Select-Object -First 10 |
Select-Object Name, #{ Name = 'MemUse'; Expression = 'WorkingSet64' }
If you only care about for-display output, you can replace Select-Object Name, ... with Format-Table -Name, ... or Format-List -Name, ..., which illustrates an important point: Format-* calls should generally only come last in a pipeline.
This basically works
foreach ($cprev in $CopyPreventeds) {
Write-Host ("prevented copy $(($cprev)."Name")")
$cprev | Select-Object Path, Name, Length, LastWrite, DestinationNewer | Export-Csv '.\prevented.csv' -NoTypeInformation
}
But only the last output is written to the csv. How could I write all contents to a new csv with an output at the same time for the user in PowerShell.
Maybe I'm missing something?
While I appreciate a solution has already been proposed in the comments, I have to ask, given the narrow scope of the question why are we using an obscure, albeit clever technique? And/or, repeatedly invoking Export-Csv...
The question doesn't mention sparing a variable. Moreover, There doesn't appear to be a need for the ForEach loop.
$CopyPreventeds |
Select-Object Path, Name, Length, LastWrite, DestinationNewer |
Export-Csv '.\prevented.csv' -NoTypeInformation
In the above $CopyPreventeds already exists and remains so, unmolested after the export. You would need only to output it again for the benefit of an interactive user. All taking advantage of PowerShell's intuitive pipeline and features.
Moreover, since the iteration variable $cprev isn't needed you are still less one variable.
Note: You don't need -Append because you are streaming into a single Export-Csv command, as opposed to repeatedly invoking it.
There are at least 2 ways (probably many more) you could conveniently output to an interactive user.
1: Echo a header, something like "The following copies were prevented:" then echo the variable $CopyPreventeds, presumably to a table.
Note: That given multiple points at which you seem only interested in a subset of properties. You may think about trimming those objects beforehand:
$CopyPreventeds =
$CopyPreventeds |
Select-Object Path, Name, Length, LastWrite, DestinationNewer
$CopyPreventeds | Export-Csv '.\prevented.csv' -NoTypeInformation
Write-Host "The following copies were prevented:"
$CopyPreventeds | Format-Table -AutoSize | Out-Host
Note: More than 4 Properties in a [PSCustomObject] (resulting from Select-Object) where custom formatting hasn't been defined will by default output as a list, so use Format-Table to overcome that. Out-Host is then used to prevent pipeline pollution.
2: Return to using a ForEach-Object Loop for the output between the Select-Object and the Export-Csv command.
$CopyPreventeds |
Select-Object Path, Name, Length, LastWrite, DestinationNewer
ForEach-Object{
"Prevented Copy : {0}, {1}, {2}, {3}, {4}" -f $_.Path, $_.Name, $_.Length, $_.LastWrite, $_.DestinationNewer |
Write-Host
$_
} |
Export-Csv '.\prevented.csv' -NoTypeInformation
In this example, when you are done outputting to the screen (admittedly a little messy), you emit $_ from the loop, thus piping it to Export-Csv just the same.
Note: there are a number of ways to construct strings, I choose to use the -f operator here because it's a little cleaning than imbedding numerous $() sub expressions. And, of course this assume you want to prefix on every line Which I personally think is gratuitous, so I'd choose something more like #1..
very new to heavier powershell and I've been hacking at this all day and can't figure it out.
I need to get a list of UPNs from office 365 accounts. I have the names in a CSV file. It has one column, with a long list of names. Heading is "name"
I want to run the get-user command against every name with the pipe format-list name, universalprincipalname and then output it to a new file.
I tried this:
get-content "m:\filename.csv" |
foreach {get-user '$_.user' -identity -resultsize unlimited} |
format-list name, userprincipalname |
out-file -FilePath m:\newfilename.csv
But it did not work (I also tried it with import-csv). It seemed to instead of pulling from my list, pull right from the office365 exchange server and when it finally finished had way more names in it than I have in my list.
My overall goal is to generate a list of upns of all the people who do not have mobile devices with their account so I can use a powershell command to disable active sync and OWA for mobile devices. Unfortunately, the command I used to generate my list of users produced the list in first name, last name format...and we have so many users I can't just concatenate the thing in excel, because there would be a ton of mistakes.
CSV is laid out like this:
Column1
name
first last
first last
first last
first last
Assuming the CSV's header is Name, the code should look like this:
Import-Csv "m:\filename.csv" | ForEach-Object {
Get-User -Identity $_.Name.Trim() -ResultSize Unlimited
} | Select-Object Name, UserPrincipalName |
Export-Csv "m:\newfilename.csv" -NoTypeInformation
Note that I'm using Select-Object instead of Format-Table. You should only use Format-Table to display your output to the PowerShell host, objects passed through the pipeline to this cmdlet will be recreated into a new object of the type FormatEntryData which you do not want if your intent is to export the data.
I'm trying to figure out why Select-Object
adds a lot of whitespace at the start of its output; and
truncates long properties with ellipsis.
Here's a repro of what I mean. Suppose you run these commands on C:\:
New-Item "MyTest" -Type Directory
cd MyTest
"Some very long lorem ipsum like text going into a certain file, bla bla bla and some more bla." | Out-File test.txt
Get-ChildItem | Select-String "text" | Select-Object LineNumber,Line
This will show output like this:
The ellipsis I can understand, that would be just the way the command ends up getting formatted when the result is written to the console host. However, the whitespace at the start still confuses me in this case.
Things get weirder for me though when I pipe the result to either clip or Out-File output.txt. I get similarly formatted output, with a lot of whitespace at the start and truncated Line properties.
Which command is causing this behavior, and how can I properly solve this? Most importantly: how can I get the full results into a file or onto my clipboard?
The default behavior of outputting the data is to use Format-Table without any modifiers, and the default behavior of Format-Table is to split the viewport into columns of equal width. This makes no assumption on the output width, and is faster in that the cmdlet doesn't need to process any string data from the pipeline prior to output.
To reduce the whitespace, you should use Format-Table -AutoSize as the output method. The -AutoSize switch first measures the widths of data, then outputs with regard to calculated width. If you need to not receive ellipsis and always display the full data set, add -Wrap switch to Format-Table, this way the value will be wrapped into more than a single line, but you can copy it via selecting a square area in Powershell window, just strip newlines off the clipped contents.
Get-ChildItem | Select-String "text" | Select-Object LineNumber,Line | Format-Table -AutoSize -Wrap
I'd say the best way to get the full output into a file would be to export the result as a CSV:
Get-ChildItem |
Select-String "text" |
Select-Object LineNumber,Line |
Export-Csv 'out.csv'
You could also build a string from the selected properties, which might be better for copying the data to the clipboard:
Get-ChildItem |
Select-String "text" |
ForEach-Object { '{0}:{1}' -f $_.LineNumber, $_.Line } |
Tee-Object 'out.txt' | clip
The behavior you observed is caused by the way PowerShell displays output. Basically, it looks at the first object and counts the properties. Objects with less than 5 properties are sent to Format-Table, otherwise to Format-List. The columns of tabular output are spread evenly across the available space. As #Vesper already mentioned you can enforce proportional column width by using the -AutoSize parameter, and wrapping of long lines by using the -Wrap parameter. Format-List wraps long strings by default.
See this blog post from Jeffrey Snover for more information.
I'm using the Quest AD cmdlets, particularly Get-QADUser, to pull a list of users from AD and return just a few attributes. No problems, easy enough, but I want to transform one of the properties (parentContainerDN) before exporting to CSV.
Get-QADUser -name "Froosh" | Select-Object logonName,homeDrive,parentContainerDN | Export-CSV C:\Temp\File.csv
This works of course, but the parentContainerDN is long and untidy. Is there an easy way to replace that with parentContainerDN.Name before passing that to Export-CSV?
I'd be happy with a commandline solution, or a script snippet.
Thanks!
There's a special syntax to create on-the-fly properties in select-object. Try this (wrapping added for clarity):
get-qaduser -name "hamilmat"
| select-object logonName, homeDrive,
#{Name="containerName"; Expression={$_.parentContainerDN.Name}}
| export-csv ...