{"id":86396,"date":"2018-05-08T05:01:21","date_gmt":"2018-05-08T13:01:21","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/koryt\/?p=215"},"modified":"2019-10-09T13:24:00","modified_gmt":"2019-10-09T21:24:00","slug":"grabbing-excel-xlsx-values-with-powershell","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/grabbing-excel-xlsx-values-with-powershell\/","title":{"rendered":"Grabbing Excel (XLSX) values with PowerShell"},"content":{"rendered":"<h2>The Goal:<\/h2>\n<p><span style=\"font-size: small;\"><span style=\"font-size: medium;\">Import data from XLSX files conveniently like import-csv lets you do with simpler data.<\/span> <\/span><\/p>\n<h2>The preamble:<\/h2>\n<p><span style=\"font-size: medium;\">Excel is a mainstay of the business world at this point, which means a lot of the data you might have to work with will come at you as an XLSX file or need to be one. This can be a bit annoying when scripting. <\/span><\/p>\n<p><span style=\"font-size: medium;\">If we&#8217;re just working in PowerShell-land and we can choose to use simple CSV data we have the handy import-csv and export-csv cmdlets, and those CSV files can open up in excel just fine. However, when we are forced to work with XLSX files it can lead to headaches. <\/span><\/p>\n<p><span style=\"font-size: medium;\">If you search around online, or have worked with excel in PowerShell before, you have probably found solutions involving COM objects that tend to start a little like this:<\/span><\/p>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:3e54fd6c-0d34-431c-8e04-587302fce7cc\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:ps decode:true\">$ExcelFile = New-Object -ComObject Excel.Application<\/pre>\n<\/div>\n<p><span style=\"font-size: medium;\">\nThen there is lots of methods and properties we can interact with on that COM object. This lets us do what we need, but ultimately leverages excel and can cause huge performance issues when working with a lot of data. Often you might see the excel process stop responding for a while and then finally it finishes its work. This is clunky, confusing and un-fun. <\/span><\/p>\n<h2>The motivation:<\/h2>\n<p><span style=\"font-size: medium;\">I recently had a folder full of XLSX files that I needed to read in. I only cared about a couple columns, and I wanted to import them as objects like I could with import-csv and then pull only unique values out.<\/span><\/p>\n<p><span style=\"font-size: medium;\">I leveraged the PowerShell Gallery and just searched for &#8220;Excel&#8221;. There is actually quite a few different options there now, but at the time I saw the description for a module called <a href=\"https:\/\/www.powershellgallery.com\/packages\/PSExcel\/1.0.2\">PSExcel<\/a>, by a fellow named RamblingCookieMonster. The description was simple: <\/span><\/p>\n<blockquote><p><span style=\"font-size: medium;\">Work with Excel without installing Excel<\/span><\/p><\/blockquote>\n<p><span style=\"font-size: medium;\">That sounded good enough to me, so I figured I&#8217;d take it for a spin. <\/span><\/p>\n<h2>The meat:<\/h2>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:69b34c36-03e9-4853-9e42-3bcd618fc706\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:ps decode:true\">Install-module PSExcel\r\nGet-command -module psexcel<\/pre>\n<\/div>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:e99a72c7-1328-4b9a-8395-1b0382851683\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:default decode:true\">CommandType Name Version Source\r\n----------- ---- ------- ------\r\nFunction Add-PivotChart 1.0.2 psexcel\r\nFunction Add-PivotTable 1.0.2 psexcel\r\nFunction Add-Table 1.0.2 psexcel\r\nFunction Close-Excel 1.0.2 psexcel\r\nFunction ConvertTo-ExcelCoordinate 1.0.2 psexcel\r\nFunction Export-XLSX 1.0.2 psexcel\r\nFunction Format-Cell 1.0.2 psexcel\r\nFunction Get-CellValue 1.0.2 psexcel\r\nFunction Get-Workbook 1.0.2 psexcel\r\nFunction Get-Worksheet 1.0.2 psexcel\r\nFunction Import-XLSX 1.0.2 psexcel\r\nFunction Join-Object 1.0.2 psexcel\r\nFunction Join-Worksheet 1.0.2 psexcel\r\nFunction New-Excel 1.0.2 psexcel\r\nFunction Save-Excel 1.0.2 psexcel\r\nFunction Search-CellValue 1.0.2 psexcel\r\nFunction Set-CellValue 1.0.2 psexcel\r\nFunction Set-FreezePane 1.0.2 psexcel<\/pre>\n<\/div>\n<p><span style=\"font-size: medium;\">Import-XLSX sounds like exactly what I wanted. <\/span><\/p>\n<p><span style=\"font-size: medium;\"><a href=\"https:\/\/msdnshared.blob.core.windows.net\/media\/2018\/01\/FakePeople.xlsx\" target=\"_blank\" rel=\"noopener noreferrer\">Here<\/a> I&#8217;ve generated a simple XLSX with fake people and companies. What I want to do is pull out just a list of unique company names from the company column. In my real world example the XLSX was a bit more complicated and I had dozens to read in on a loop, but that just involved scaling up these actions.<\/span><\/p>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:9804c7df-f264-40b3-bcae-be3eca77aad3\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:ps decode:true\">$path = \"$PSScriptRoot\\fakepeople.xlsx\"\r\n\r\nimport-module psexcel #it wasn't auto loading on my machine\r\n\r\n$people = new-object System.Collections.ArrayList\r\n\r\nforeach ($person in (Import-XLSX -Path $path -RowStart 1))\r\n\r\n{\r\n\r\n$people.add($person) | out-null #I don't want to see the output\r\n\r\n}\r\n\r\n$people.company | select -unique<\/pre>\n<\/div>\n<div id=\"scid:C89E2BDB-ADD3-4f7a-9810-1B7EACF446C1:f556c82b-88f3-4bf9-a69e-00b92b117c57\" class=\"wlWriterEditableSmartContent\" style=\"margin: 0px; padding: 0px; float: none;\">\n<pre class=\"lang:default decode:true\">Contoso\r\nContosoSuites\r\n\r\nFabrikam\r\n\r\nParnell Aerospace\r\n\r\nHumongous Insurance<\/pre>\n<\/div>\n<p><span style=\"font-size: medium;\">Just a quick note, if you&#8217;re looking to do a bit more with Excel, I found <a href=\"https:\/\/www.powershellgallery.com\/packages\/ImportExcel\/4.0.8\">this<\/a> module as well, which seems a bit more robust. <\/span><\/p>\n<p><span style=\"font-size: medium;\">That&#8217;s all for now. Hopefully this helps you if you need to grab some data from XLSX files! <\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Goal: Import data from XLSX files conveniently like import-csv lets you do with simpler data. The preamble: Excel is a mainstay of the business world at this point, which means a lot of the data you might have to work with will come at you as an XLSX file or need to be one. [&hellip;]<\/p>\n","protected":false},"author":7300,"featured_media":87096,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1738],"tags":[2221,2125,48,377],"class_list":["post-86396","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-kory-thacher","tag-koryt","tag-microsoft-excel","tag-powershell"],"acf":[],"blog_post_summary":"<p>The Goal: Import data from XLSX files conveniently like import-csv lets you do with simpler data. The preamble: Excel is a mainstay of the business world at this point, which means a lot of the data you might have to work with will come at you as an XLSX file or need to be one. [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86396","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\/7300"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=86396"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/86396\/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=86396"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=86396"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=86396"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}