{"id":12611,"date":"2011-09-23T00:01:00","date_gmt":"2011-09-23T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2011\/09\/23\/use-powershell-to-work-with-csv-formatted-text\/"},"modified":"2011-09-23T00:01:00","modified_gmt":"2011-09-23T00:01:00","slug":"use-powershell-to-work-with-csv-formatted-text","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-work-with-csv-formatted-text\/","title":{"rendered":"Use PowerShell to Work with CSV Formatted Text"},"content":{"rendered":"<p><strong>Summary<\/strong>: See how to use Windows PowerShell to create CSV files from formatted and unformatted text.<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\" \/>Hey, Scripting Guy! I have begun to play around with Windows PowerShell, and it is absolutely the most confusing thing Microsoft has ever created. Simple things are easy. I can use <b>Get-Process<\/b> and <b>Get-Service<\/b> with no problem, but the moment I begin to think I can use this tool, I get kicked in the teeth. A case in point is the <b>Export-CSV<\/b> cmdlet. When I first saw this, I thought, &ldquo;Well, now, this is cool!&rdquo; But I have yet to see how cool it really is. The thing is nearly impossible to use. I just don&rsquo;t get it. All I want to do is save data in a CSV file, so I can open it up in Microsoft Excel. Is the cmdlet broken?<\/p>\n<p>&mdash;BB<\/p>\n<p>&nbsp;<\/p>\n<p><img decoding=\"async\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\" \/>Hello BB,<\/p>\n<p>Microsoft Scripting Guy Ed Wilson here. I can certainly sympathize with you. I get this question quite a bit, unfortunately. Part of the problem is that the cmdlet does not really do what you think it will. For example, if I have a string with a CSV listing, and I write it to a CSV file by using the <b>Export-CSV<\/b> cmdlet, I might use code that looks like the following:<\/p>\n<p style=\"padding-left: 30px\">$Outputstring = &#8220;dog&#8221;,&#8221;Cat&#8221;,&#8221;Mouse&#8221;<\/p>\n<p style=\"padding-left: 30px\">$OutputString | Export-Csv C:\\fso\\csvTest.csv<\/p>\n<p>However, when I look at the csvtest.csv file, the results are disappointing. The file created by the preceding code is shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4150.hsg-9-23-11-01.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of file created by preceding code\" alt=\"Image of file created by preceding code\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4150.hsg-9-23-11-01.png\" width=\"451\" height=\"212\" \/><\/a><\/p>\n<p>The first time I saw this, I could not believe my eyes. I actually deleted the file and ran the command a second time to make sure of the results. To my chagrin, the second file appeared as the first. Neither was a CSV file.<\/p>\n<p>There are two Windows PowerShell cmdlets that work with comma-separated values: <b>ConvertTo-CSV<\/b> and <b>Export-CSV<\/b>. The two cmdlets are basically the same; the difference is that <b>Export-CSV<\/b> will save to a text file, and <b>ConvertTo-CSV<\/b> does not. The cmdlets are useful for working with deserialized objects. For example, if I want to be able to analyze process information at a later date, I can use the <b>Get-Process<\/b> cmdlet to store the objects in a text file. I can then use <b>Import-CSV<\/b> to reconstitute the process objects. This is shown here:<\/p>\n<p style=\"padding-left: 30px\">PS C:\\&gt; Get-Process winword | Export-Csv c:\\fso\\procWord.csv<\/p>\n<p style=\"padding-left: 30px\">PS C:\\&gt; $a = Import-Csv C:\\fso\\procWord.csv<\/p>\n<p style=\"padding-left: 30px\">PS C:\\&gt; $a.Name<\/p>\n<p style=\"padding-left: 30px\">WINWORD<\/p>\n<p>The complete text of the procWord.csv file is shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5305.hsg-9-23-11-02.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of complete text of procWord.csv file\" alt=\"Image of complete text of procWord.csv file\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5305.hsg-9-23-11-02.png\" \/><\/a><\/p>\n<p>As shown in the preceding figure, the CSV file created by <b>Export-CSV<\/b> consists of three parts. The first is the type of object stored in the file. The second is the column headings, and the third contains the property values. If more than one object were stored in the file, the remaining lines would contain additional property values. If a property did not exist on the object, the file would be padded by commas. When the object is reconstituted via the <b>Import-CSV<\/b> cmdlet, all the properties stored in the file&mdash;but none of the methods&mdash;return to the object. A reconstituted object is devoid of any methods.<\/p>\n<p>If I want to save process information as a CSV file because I am planning to open the file in Excel, I use the <i>NoTypeInformation <\/i>switched parameter of the <b>Export-CSV<\/b> cmdlet. This technique is shown here (<b>GPS<\/b> is an alias for the <b>Get-Process<\/b> cmdlet):<\/p>\n<p style=\"padding-left: 30px\">GPS winword,Excel,Outlook | Export-Csv c:\\fso\\procoff.csv &ndash;NoTypeInformation<\/p>\n<p>When I open the CSV file in Microsoft Excel, each object appears on its own line. The properties are in the first line as column headers. This is shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4657.hsg-9-23-11-03.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of Excel file with each object on its own line\" alt=\"Image of Excel file with each object on its own line\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4657.hsg-9-23-11-03.png\" \/><\/a><\/p>\n<p>BB, as shown so far, the <b>Export-CSV<\/b> cmdlet is great at taking objects and storing them in an offline format so that they can be reconstituted for later analysis and comparison. In addition, I can use the <b>Export-CSV<\/b> cmdlet to save objects and then view the properties in Microsoft Excel. If I do not want all of the properties, I can create a custom object by piping to the <b>Select-Object<\/b> cmdlet first. In the following command, I use <b>gps<\/b> (the alias for <b>Get-Process<\/b>) to return information about each process on the machine. I then choose only three properties from the objects: <b>id<\/b>, <b>processName<\/b>, and <b>CPU<\/b>. This information is exported into a CSV file. This technique is shown here:<\/p>\n<p style=\"padding-left: 30px\">gps | Select-Object id, processName, CPU | Export-Csv c:\\fso\\co.csv &ndash;NoTypeInformation<\/p>\n<p>The saved data is shown in the following figure when viewed in Microsoft Excel.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6087.hsg-9-23-11-04.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of saved data viewed in Excel\" alt=\"Image of saved data viewed in Excel\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6087.hsg-9-23-11-04.png\" width=\"457\" height=\"713\" \/><\/a><\/p>\n<p>If you want to pipe your array of strings to the <b>Export-CSV<\/b> cmdlet, you will need to first convert them into objects. This is because you need a custom object with multiple properties, instead of a series of single property strings. This is the problem you were wrestling with earlier&mdash;you were not providing the <b>Export-CSV<\/b> cmdlet with a nice object upon which to work.<\/p>\n<p><b>Export-CSV<\/b> treats each object as a new row of data. The columns used with the CSV file are determined by the properties of the object. To work with <b>Export-CSV<\/b>, it is necessary to create an object for each row of data to be stored. This technique is shown here:<\/p>\n<p style=\"padding-left: 30px\">$Outputstring = &#8220;dog&#8221;,&#8221;Cat&#8221;,&#8221;Mouse&#8221;<\/p>\n<p style=\"padding-left: 30px\">$psObject = $null<\/p>\n<p style=\"padding-left: 30px\">$psObject = New-Object psobject<\/p>\n<p style=\"padding-left: 30px\">foreach($o in $outputString)<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Add-Member -InputObject $psobject -MemberType noteproperty `<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp; -Name $o -Value $o<\/p>\n<p style=\"padding-left: 30px\">}<\/p>\n<p style=\"padding-left: 30px\">$psObject | Export-Csv c:\\fso\\psobject.csv -NoTypeInformation<\/p>\n<p>The resulting CSV file is shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5706.hsg-9-23-11-05.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of resulting CSV file\" alt=\"Image of resulting CSV file\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/5706.hsg-9-23-11-05.png\" width=\"446\" height=\"186\" \/><\/a><\/p>\n<p>Most of the time, if I need to create a CSV file from unformatted text, I tend to use manual string techniques, as shown here:<\/p>\n<p style=\"padding-left: 30px\">$Outputstring = &#8220;dog&#8221;,&#8221;Cat&#8221;,&#8221;Mouse&#8221;<\/p>\n<p style=\"padding-left: 30px\">$Outputstring -join &#8220;,&#8221; &gt;&gt; c:\\fso\\joinCSV.csv<\/p>\n<p>The output from this approach is shown in the following figure.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0675.hsg-9-23-11-06.png\"><img decoding=\"async\" style=\"border: 0px\" title=\"Image of output from this approach\" alt=\"Image of output from this approach\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/0675.hsg-9-23-11-06.png\" width=\"478\" height=\"222\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>BB, those are several ways of working with CSV data and the <b>Export-CSV<\/b> cmdlet.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: See how to use Windows PowerShell to create CSV files from formatted and unformatted text. &nbsp; Hey, Scripting Guy! I have begun to play around with Windows PowerShell, and it is absolutely the most confusing thing Microsoft has ever created. Simple things are easy. I can use Get-Process and Get-Service with no problem, but [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[169,3,4,45],"class_list":["post-12611","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-csv-and-other-delimited-files","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: See how to use Windows PowerShell to create CSV files from formatted and unformatted text. &nbsp; Hey, Scripting Guy! I have begun to play around with Windows PowerShell, and it is absolutely the most confusing thing Microsoft has ever created. Simple things are easy. I can use Get-Process and Get-Service with no problem, but [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/12611","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=12611"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/12611\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=12611"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=12611"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=12611"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}