<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>XLS Archives - LucD notes</title>
	<atom:link href="https://www.lucd.info/tag/xls/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.lucd.info/tag/xls/</link>
	<description>My PowerShell ramblings</description>
	<lastBuildDate>Fri, 04 Feb 2011 00:05:04 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9</generator>

<image>
	<url>https://www.lucd.info/wp-content/uploads/2018/12/cropped-120px-Tibetan_Dharmacakra-32x32.png</url>
	<title>XLS Archives - LucD notes</title>
	<link>https://www.lucd.info/tag/xls/</link>
	<width>32</width>
	<height>32</height>
</image> 
<atom:link rel="hub" href="https://pubsubhubbub.appspot.com"/><atom:link rel="hub" href="https://pubsubhubbub.superfeedr.com"/><atom:link rel="hub" href="https://websubhub.com/hub"/>	<item>
		<title>Beyond Export-Csv: Export-Xls</title>
		<link>https://www.lucd.info/2010/05/29/beyond-export-csv-export-xls/</link>
					<comments>https://www.lucd.info/2010/05/29/beyond-export-csv-export-xls/#comments</comments>
		
		<dc:creator><![CDATA[LucD]]></dc:creator>
		<pubDate>Sat, 29 May 2010 19:00:04 +0000</pubDate>
				<category><![CDATA[PowerShell]]></category>
		<category><![CDATA[Spreadsheet]]></category>
		<category><![CDATA[export]]></category>
		<category><![CDATA[XLS]]></category>
		<guid isPermaLink="false">http://www.lucd.info/?p=2261</guid>

					<description><![CDATA[Warning: this post has no &#8220;virtual&#8221; content ! This time I post a [&#8230;]]]></description>
										<content:encoded><![CDATA[<p><span style="color: #ffffff;"><span style="background-color: #ff0000;">Warning</span></span>: this post has no &#8220;<em>virtual</em>&#8221; content !</p>
<p>This time I post a function that allows you to export your data to a &#8220;real&#8221; spreadsheet (XLS format) instead of a CSV file.</p>
<p>The reason for posting this function was a series of threads in the <a href="https://communities.vmware.com/community/vmtn/vsphere/automationtools/powercli;jsessionid=CF7ABD969A7E6F5BA5E110A012442FA7?view=discussions" target="_blank">PowerCLI Community</a> by <a href="https://communities.vmware.com/people/Sureshadmin?view=overview" target="_blank">Suresh</a>. Over several threads he has been collecting scripts that create various reports on his vSphere environment. Ultimately he wanted to have a spreadsheet where <a href="https://communities.vmware.com/thread/269701?tstart=15" target="_blank">each report </a>would be stored on a worksheet.</p>
<p>PowerShell has the very handy <strong>Export-Csv</strong> cmdlet to create CSV files but afaik nothing for creating XLS files <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f641.png" alt="🙁" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
<p><span id="more-2261"></span></p>
<p>That&#8217;s when I decided to &#8220;<em>pimp</em>&#8221; my <strong>XLS</strong> creating function I already had to something more suited for general use.</p>
<p>The function uses Excel through a COM object. So yes, you do need to have Excel installed on the client where you use the function. The function first exports the data to a CSV file with the Export-Csv cmdlet. And then does a copy/paste to the worksheet in the XLS file.</p>
<p><strong><span style="background-color: #ffff00;">Update June 16th 2010</span></strong>: the function has a new parameter <strong>-ChartType</strong> which allows the addition of a chart on the worksheet.<br />
<strong> </strong></p>
<p><strong><span style="background-color: #ffff00;">Update November 2nd 2010</span></strong>: a complete overhaul of the function</p>
<ul>
<li>The function now uses the <strong>clipboard</strong>, instead of a temporary CSV file, to hold the data that needs to be written to the worksheet.</li>
<li>The function places the array on the clipboard in such a way that it can be <strong>correctly pasted</strong> into the Worksheet. Thanks to my colleague <strong>Géry</strong> for his algorithm.</li>
<li>The function uses the <strong>Textbox</strong> trick as described in <a href="https://thoughtfulcode.wordpress.com/2010/09/03/copy-and-paste-with-clipboard-from-powershell/" target="_blank">Copy and Paste with Clipboard from PowerShell</a>. With this method we don&#8217;t need to start an new PowerShell thread with the STA attribute. And this method is considerably<strong> faster</strong> !</li>
</ul>
<h2>The script</h2>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">#requires -version 2

function Export-Xls{
	&lt;#
.SYNOPSIS
	Saves Microsoft .NET Framework objects to a worksheet in an XLS file
.DESCRIPTION
	The Export-Xls function allows you to save Microsoft .NET Framework objects
	to a named worksheet in an Excel file (type XLS). The position of the
	worksheet can be specified.
.NOTES
	Author:  Luc Dekens
.PARAMETER InputObject
	Specifies the objects to be written to the worksheet. The parameter accepts
	objects through the pipeline.
.PARAMETER Path
	Specifies the path to the XLS file.
.PARAMETER WorksheetName
	The name for the new worksheet. If not specified the name will
	be &quot;Sheet&quot; followed by the &quot;Ticks&quot; value
.PARAMETER SheetPosition
	Specifies where the new worksheet will be inserted in the series of
	existing worksheets. You can specify &quot;begin&quot; or &quot;end&quot;. The default
	is &quot;begin&quot;.
.PARAMETER ChartType
	Specifies the type of chart you want add to the worksheet.
	All types in the [microsoft.Office.Interop.Excel.XlChartType]
	enumeration are accepted.
.PARAMETER NoTypeInformation
	Omits the type information from the worksheet. The default is to
	include the &quot;#TYPE&quot; line.
.PARAMETER AppendWorksheet
	Specifies if the worksheet should keep or remove the existing
	worksheet in the spreadsheet. The default is to append.
.EXAMPLE
	PS&gt; $data = Get-Process | Select-Object Name, Id, WS
	PS&gt; Export-Xls $data C:\Reports\MyWkb.xls -WorksheetName &quot;WS&quot; -AppendWorksheet:$false
.EXAMPLE
	PS&gt; $data = Get-Process | Select-Object Name, Id, WS
	PS&gt; Export-Xls $data C:\Reports\MyWkb.xls -SheetPosition &quot;end&quot;
.EXAMPLE
	PS&gt; $data = Get-Process | Select-Object Name, Id, WS
	PS&gt; Export-Xls $data C:\Reports\MyWkb.xls -WorksheetName &quot;WS&quot; -ChartType &quot;xlColumnClustered&quot;
#&gt;
	param(
	[parameter(ValueFromPipeline = $true,Position=1)]
	[ValidateNotNullOrEmpty()]
	$InputObject,
	[parameter(Position=2)]
	[ValidateNotNullOrEmpty()]
	[string]$Path,
	[string]$WorksheetName = (&quot;Sheet &quot; + (Get-Date).Ticks),
	[string]$SheetPosition = &quot;begin&quot;,
	[PSObject]$ChartType,
	[switch]$NoTypeInformation = $true,
	[switch]$AppendWorksheet = $true
	)

	begin{
		[System.Reflection.Assembly]::LoadWithPartialName(&quot;Microsoft.Office.Interop.Excel&quot;)
		if($ChartType){
			[microsoft.Office.Interop.Excel.XlChartType]$ChartType = $ChartType
		}

		function Set-ClipBoard{
			param(
				[string]$text
			)
			process{
				Add-Type -AssemblyName System.Windows.Forms
				$tb = New-Object System.Windows.Forms.TextBox
				$tb.Multiline = $true
				$tb.Text = $text
				$tb.SelectAll()
				$tb.Copy()
			}
		}

		function Add-Array2Clipboard {
			param (
				[PSObject[]]$ConvertObject,
				[switch]$Header
			)
			process{
				$array = @()

				if ($Header) {
					$line =&quot;&quot;
					$ConvertObject | Get-Member -MemberType Property,NoteProperty,CodeProperty | Select -Property Name | %{
						$line += ($_.Name.tostring() + &quot;`t&quot;)
					}
					$array += ($line.TrimEnd(&quot;`t&quot;) + &quot;`r&quot;)
				}
				else {
					foreach($row in $ConvertObject){
						$line =&quot;&quot;
						$row | Get-Member -MemberType Property,NoteProperty | %{
							$Name = $_.Name
							if(!$Row.$Name){$Row.$Name = &quot;&quot;}
							$line += ([string]$Row.$Name + &quot;`t&quot;)
						}
						$array += ($line.TrimEnd(&quot;`t&quot;) + &quot;`r&quot;)
					}
				}
				Set-ClipBoard $array
			}
		}

		$excelApp = New-Object -ComObject &quot;Excel.Application&quot;
		$originalAlerts = $excelApp.DisplayAlerts
		$excelApp.DisplayAlerts = $false
		if(Test-Path -Path $Path -PathType &quot;Leaf&quot;){
			$workBook = $excelApp.Workbooks.Open($Path)
		}
		else{
			$workBook = $excelApp.Workbooks.Add()
		}
		$sheet = $excelApp.Worksheets.Add($workBook.Worksheets.Item(1))
		if(!$AppendWorksheet){
			$workBook.Sheets | where {$_ -ne $sheet} | %{$_.Delete()}
		}
		$sheet.Name = $WorksheetName
		if($SheetPosition -eq &quot;end&quot;){
			$nrSheets = $workBook.Sheets.Count
			2..($nrSheets) |%{
				$workbook.Sheets.Item($_).Move($workbook.Sheets.Item($_ - 1))
			}
		}
		$sheet.Activate()
		$array = @()
	}

	process{
		$array += $InputObject
	}

	end{
		Add-Array2Clipboard $array -Header:$True
		$selection = $sheet.Range(&quot;A1&quot;)
		$selection.Select() | Out-Null
		$sheet.Paste()
		$Sheet.UsedRange.HorizontalAlignment = [microsoft.Office.Interop.Excel.XlHAlign]::xlHAlignCenter
		Add-Array2Clipboard $array
		$selection = $sheet.Range(&quot;A2&quot;)
		$selection.Select() | Out-Null
		$sheet.Paste() | Out-Null
		$selection = $sheet.Range(&quot;A1&quot;)
		$selection.Select() | Out-Null

		$sheet.UsedRange.EntireColumn.AutoFit() | Out-Null
		$workbook.Sheets.Item(1).Select()
		if($ChartType){
			$sheet.Shapes.AddChart($ChartType) | Out-Null
		}
		$workbook.SaveAs($Path)
		$excelApp.DisplayAlerts = $originalAlerts
		$excelApp.Quit()
		Stop-Process -Name &quot;Excel&quot;
	}
}</pre><p></p>
<h4>Annotations</h4>
<p><strong>Line 65-77</strong>: This short function place a string in the Textbox control and then uses the Copy method to send the string to the Clipboard. <a href="https://thoughtfulcode.wordpress.com/2010/09/03/copy-and-paste-with-clipboard-from-powershell/" target="_blank">Function</a> by <a href="https://thoughtfulcode.wordpress.com/" target="_blank">Brian Reiter</a>.</p>
<p><strong>Line 79-107</strong>: This concept for this function came from my colleague <strong>Géry</strong>. The trick is to separate the properties from the array by the TAB character. That way a paste in Excel will place the properties in different cells. The first part of the function handles the property names (or the column headers in Excel), the second part prepares the actual data.</p>
<p><strong>Line 110-111,155</strong>: The Excel alerts are temporarily disabled to avoid pop-up messages. The original setting is restored just before leaving the function.</p>
<p><strong>Line 112-117:</strong> The function tests if the XLS file exists or not.</p>
<p><strong>Line 118</strong> A new worksheet is added in position 1.</p>
<p><strong>Line 119-121</strong>: If the AppendWorksheet switch is $false, all the other worksheets are removed.</p>
<p><strong>Line 123-128</strong>: These lines move the worksheet to the end of the list if the SheepPosition parameter states &#8220;end&#8221;.</p>
<p><strong>Line 134</strong>: All the objects from the InputObject are copied to the local $array variable.</p>
<p><strong>Line 138</strong>: The property names of the $array variable are copied to the clipboard</p>
<p><strong>Line 139-141</strong>: The column headers (the property names) are pasted to the Excel worksheet</p>
<p><strong>Line 142</strong>: The column headers are aligned.</p>
<p><strong>Line 143</strong>: The data in the $array variable is copied to the clipboard</p>
<p><strong>Line 144-146</strong>: The data is pasted into the Excel worksheet 1 row below the headers.</p>
<p><strong>Line 147</strong>: Unselect the range that was just copied.</p>
<p><strong>Line 150</strong>: The width of all columns in the worksheet is changed so all cell values are visible.</p>
<p><strong>Line 158</strong>: Although the Quit method is called, the Excel process stays active. The only way to get rid of it is through a Stop-Process cmdlet.</p>
<h2>Examples</h2>
<p>Some sample runs I did with Excel 2003.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$data = Get-Process | Select-Object Name, Id, WS
Export-Xls $data D:\Reports\MyWkb.xls</pre><p></p>
<p>This produces the following</p>
<p><a href="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex11.png"><img fetchpriority="high" decoding="async" class="alignnone size-full wp-image-2299" title="export-xls-ex1" src="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex11.png" alt="" width="398" height="217" srcset="https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex11.png 398w, https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex11-300x163.png 300w" sizes="(max-width: 398px) 100vw, 398px" /></a></p>
<p>In this installation Excel was configured to start a new spreadsheet with 3 worksheets.</p>
<p>But we can get rid of those by using the <strong>-AppendWorksheet</strong> switch.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$data = Get-Process | Select-Object Name, Id, WS
Export-Xls $data D:\Reports\MyWkb.xls -AppendWorksheet:$false</pre><p></p>
<p>Now we only have the worksheet we just created.</p>
<p><a href="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex21.png"><img decoding="async" class="alignnone size-full wp-image-2300" title="export-xls-ex2" src="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex21.png" alt="" width="335" height="221" srcset="https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex21.png 335w, https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex21-300x197.png 300w" sizes="(max-width: 335px) 100vw, 335px" /></a></p>
<p>You can use the function in a pipeline</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">Get-Process | Select-Object Name, Id, WS | Export-Xls -Path D:\Reports\MyWkb.xls -WorksheetName &quot;My new sheet&quot;</pre><p></p>
<p>This gives</p>
<p><a href="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex31.png"><img decoding="async" class="alignnone size-full wp-image-2301" title="export-xls-ex3" src="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex31.png" alt="" width="358" height="223" srcset="https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex31.png 358w, https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex31-300x186.png 300w" sizes="(max-width: 358px) 100vw, 358px" /></a></p>
<p>And you can specify that the new worksheet should be at the end</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">Get-Process | Select-Object Name, Id, WS | `
   Export-Xls -Path D:\Reports\MyWkb.xls -WorksheetName &quot;Another sheet&quot; -SheetPosition &quot;end&quot;</pre><p></p>
<p>This gives</p>
<p><a href="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex41.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2302" title="export-xls-ex4" src="https://lucd.info/wp-content/uploads/2010/05/export-xls-ex41.png" alt="" width="457" height="223" srcset="https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex41.png 457w, https://www.lucd.info/wp-content/uploads/2010/05/export-xls-ex41-300x146.png 300w" sizes="auto, (max-width: 457px) 100vw, 457px" /></a></p>
<h2>Charts</h2>
<p>With the <strong>-ChartType</strong> parameter you can create a chart on the worksheet.</p>
<p>The <strong>accepted values</strong> for this parameter are all the values present in the <strong>microsoft.Office.Interop.Excel.XlChartType</strong> enumtype. If you want to produce a list with the acceptable values you can do something like this.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">[System.Reflection.Assembly]::LoadWithPartialName(&quot;Microsoft.Office.Interop.Excel&quot;) | Out-Null

[microsoft.Office.Interop.Excel.XlChartType] | gm -Static -MemberType Property | %{$_.Name}</pre><p></p>
<p>It will produce a rather long list of available chart types.<br />
<a href="https://lucd.info/wp-content/uploads/2010/05/XLS-charttypes.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2359" title="XLS-charttypes" src="https://lucd.info/wp-content/uploads/2010/05/XLS-charttypes.png" alt="" width="374" height="645" /></a></p>
<p>Some sample runs</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$data = Get-Process | Sort-Object -Property WorkingSet -Descending | `
  Select-Object Name, @{N=&quot;WS&quot;;E={$_.WorkingSet/1MB}} -First 10
Export-Xls $data C:\Temp\MyWkb.xls -AppendWorksheet:$false -WorksheetName &quot;WS&quot; -ChartType &quot;xlColumnClustered&quot;</pre><p></p>
<p>Produces</p>
<p><a href="https://lucd.info/wp-content/uploads/2010/05/XLS-chart-1.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2360" title="XLS-chart-1" src="https://lucd.info/wp-content/uploads/2010/05/XLS-chart-1.png" alt="" width="631" height="318" srcset="https://www.lucd.info/wp-content/uploads/2010/05/XLS-chart-1.png 789w, https://www.lucd.info/wp-content/uploads/2010/05/XLS-chart-1-300x150.png 300w" sizes="auto, (max-width: 631px) 100vw, 631px" /></a></p>
<p>This short script selects the working set and the peak working set and add a line graph.</p>
<p></p><pre class="urvanov-syntax-highlighter-plain-tag">$data = Get-Process | Select-Object -First 10 Name, @{N=&quot;WS&quot;;E={$_.WorkingSet/1MB}},@{N=&quot;PM&quot;;E={$_.PeakWorkingSet/1MB}}
Export-Xls $data C:\Temp\MyWkb.xls -AppendWorksheet:$false -WorksheetName &quot;WS&quot; -ChartType &quot;xlLine&quot;</pre><p></p>
<p>And this produces</p>
<p><a href="https://lucd.info/wp-content/uploads/2010/05/XLS-chart-21.png"><img loading="lazy" decoding="async" class="alignnone size-full wp-image-2746" title="XLS-chart-2" src="https://lucd.info/wp-content/uploads/2010/05/XLS-chart-21.png" alt="" width="710" height="274" srcset="https://www.lucd.info/wp-content/uploads/2010/05/XLS-chart-21.png 887w, https://www.lucd.info/wp-content/uploads/2010/05/XLS-chart-21-300x115.png 300w" sizes="auto, (max-width: 710px) 100vw, 710px" /></a></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.lucd.info/2010/05/29/beyond-export-csv-export-xls/feed/</wfw:commentRss>
			<slash:comments>65</slash:comments>
		
		
			</item>
	</channel>
</rss>
