Hey, Scripting Guy! Question

Hey, Scripting Guy! When I add data to an Office Excel spreadsheet, it always seems to put stuff on the right side of the column. I would like to know how to center the contents of a column. I do not think it should be that hard, but I just cannot figure it out.

- LK

SpacerHey, Scripting Guy! Answer

Hi LK,

Did you try Open Sesame? I can certainly sympathize with you. It can be really frustrating trying many different things in a script to see if it will work or not. I still, painfully, remember a situation many years ago, when I was trying to connect to the local WinNT repository on a remote computer, in another domain. There can, of course, be many potential issues from name resolution to security. I tried them all; at least I thought I had. I had been working on this script for more than six hours, and I kept trying and trying to get the thing to work. Finally, I tried “WinNT” with this exact capitalization. I was sure it couldn’t be something so simple, but, capitalization was indeed the problem. It had to be capitalized in exactly this manner. When the script worked, I was not sure if I should be happy that it worked, or sad that I had wasted six hours of my life—and not one reference I consulted during those six hours mentioned this little piece of trivia! Of course, all the examples were capitalized in this manner, but nothing told me that it had to be cased in this manner. This was even more frustrating because most of VBScript is case insensitive. Of course, when I later wrote the Microsoft VBScript Step by Step book, I made certain to include a nice big warning to this fact.

The Office Excel automation model is documented here on MSDN. Here are previous "Hey, Scripting Guy!" articles that illustrate using VBScript to automate Microsoft Excel. The Office space archive also has numerous examples of using VBScript with Office Excel. You can also find lots of examples of automating Office Excel in the Script Center Repository. Perhaps I also saved the best for last. The Community-Submitted Scripts Center has a ton of scripts that automate Office Excel. Here is the direct link to that gold mine of information. Look in the Microsoft Office section. If you are new to using Microsoft PowerShell, you can get a jump-start on it with the resources in the Windows PowerShell hub.

I am doing something I do not normally like to do: This script is basically useless. It does answer the question and is important from a learning standpoint, but unless your pointy-headed boss (PHB) comes floating around and asks you, "Can you write a script that will populate the first row with the letters a, b, and c and center the letter a?" you will have no occasion to use the script. On the other hand, maybe, just maybe (you never know with a PHB). So just in case, here is the script:

Function NewExcelSheet($sheetName)
{
 $excel = new-object -comobject excel.application
 $excel.visible = $true
 $workbook = $excel.workbooks.add()
 $workbook.workSheets.item(3).delete()
 $workbook.WorkSheets.item(2).delete()
 $workbook.WorkSheets.item(1).Name = $sheetName
 $sheet = $workbook.WorkSheets.Item($sheetName)
 AddExcelContent
} #end NewExcelSheet

Function AddExcelContent()
{
 $sheet.cells.item(1,1) = "A"
 $sheet.cells.item(1,2) = "B"
 $sheet.cells.item(1,3) = "C"
 CenterCells
}

Function CenterCells()
{
 [reflection.assembly]::loadWithPartialname("Microsoft.Office.Interop.Excel") | out-Null
 $xlConstants = "microsoft.office.interop.excel.Constants" -as [type]
 $sheet.Cells.item(1,1).HorizontalAlignment = $xlConstants::xlCenter
}

NewExcelSheet("Test")

To begin our script, we create a function called NewExcelSheet. The advantage of putting the essential steps for working with Microsoft Excel is that we can easily use this function again in another script. As it is written, very little would need to be changed to enable us to use this function in other scripts.

The first thing we do when creating a function is use the function keyword, followed by the name of the function. We will pass the name of the spreadsheet to the function when we call it, which allows us to change the name of the spreadsheet during the creation. This line of code is seen here:

Function NewExcelSheet($sheetName)

Now we need to create an instance of the Excel.Application object. This is the main object we use when working with automating Microsoft Excel. The New-Object cmdlet is used to create the object, and we specify the –comobject parameter because Excel.Application is a com object. We store the resulting application object in the $excel variable. After we have created the Excel.Application, we make it visible by setting the visible property to true. This is shown here:

$excel = new-object -comobject excel.application
 $excel.visible = $true

Next we need to add a workbook to the empty Excel.Application. To add a workbook, we use the add method from the workbooks object. This is illustrated here:

$workbook = $excel.workbooks.add()

We then delete the two extra spreadsheets. This is done by using the worksheets property to return a worksheets collection, and using the item method to retrieve a specific spreadsheet. We then call the delete method from the worksheet object, which remotes the extra spreadsheets. This is shown here:

 $workbook.workSheets.item(3).delete()
 $workbook.WorkSheets.item(2).delete()

Now we want to rename the first spreadsheet. To do this, we use the item method from the worksheets object to retrieve the worksheet. We then assign a new value to the name property. This is seen here:

$workbook.WorkSheets.item(1).Name = $sheetName

We then store the worksheet object in the variable $sheet. This time, we use the name of the spreadsheet to retrieve the newly renamed worksheet. After we have stored the worksheet in the $sheet variable, we call the AddExcelContent function. This can be seen here:

$sheet = $workbook.WorkSheets.Item($sheetName)
 AddExcelContent

In the AddExcelContent function, we assign three letters to three different cells. The first number represents the row in the spreadsheet, and the second number the column. It is a bit confusing that we use 1,1 to refer to cell 1a in Excel. But it is not that difficult, so I will not whine about it. To assign a value to the cell, we use the cells collection, and the item to grab a specific cell, and then we use the equality operator to assign the value to it. We then call the CenterCells function. This is seen here, and is not nearly as complicated as it sounds:

Function AddExcelContent()
{
 $sheet.cells.item(1,1) = "A"
 $sheet.cells.item(1,2) = "B"
 $sheet.cells.item(1,3) = "C"
 CenterCells
}

Now we get to the hard part of the script. The first thing we do in the function is load the Microsoft.Office.Interop.Excel assembly. This is because it is not loaded by default. To load the assembly in Windows PowerShell 1.0, we use the static loadWithPartialName method from the reflection.assembly class. In Windows PowerShell 2.0 (which is in a community technology preview as of this date), you can add this reference by using the add-type cmdlet. When the assembly is loaded, it produces feedback on the screen, which is seen here:

PS C:\> [reflection.assembly]::loadWithPartialname("Microsoft.Office.Interop.Excel")

GAC    Version        Location
---    -------        --------
True   v1.1.4322      C:\WINDOWS\assembly\GAC\Microsoft.Office.Interop.Excel\12.0.0.0__71e9bce111e9429c\Microsoft.Of...


PS C:\>

Because that feedback can be a bit distracting, I send the output to the out-Null cmdlet. The out-Null cmdlet is a cmdlet with a really bad memory, and therefore it does nothing. You give it something, and it immediately forgets about it (kind of like Dory from Finding Nemo). This section of the code can be perused at your leisure:

Function CenterCells()
{
 [reflection.assembly]::loadWithPartialname("Microsoft.Office.Interop.Excel") |
 out-Null

We now create the constant type. The VBScript version of this script uses what I call a "magic number," and magic numbers are, in my mind, a big no-no! They are hard to read and extremely error prone. For instance, if I were troubleshooting the script and I come across this line of code, what would I need to do?:

objWorksheet.Cells(1, 2).HorizontalAlignment = -4108

There is absolutely no way I can verify if this is the correct value. Also, what are the other options available to me? It is simply a number, and that is about it. In our current script, we use the actual constant values.

We need to understand two lines of code. The first we already discussed; we loaded the interop assembly. Now we create the constants and store them in the $xlConstants variable. This is actually pretty cool because this pulls the mask off of all those annoying magic numbers you have been seeing around here for the last eight years. If you are like me, you want to know where in the heck those values are documented. They are in fact on MSDN. You can also use Windows PowerShell to find this information on your own, as seen here:

[reflection.assembly]::loadWithPartialname("Microsoft.Office.Interop.Excel") | out-Null
[enum]::getNames($xlconstants) | 
ForEach-Object { "$xlconstants:$_" +  " " + $xlConstants::$_.value__ } 

To simplify the troubleshooting of the script, we create the constants as shown here.

$xlConstants = "microsoft.office.interop.excel.Constants" -as [type]

We then use this constant to specify the alignment of the cells. We are interested in the horizontal alignment, and we use the HorizontalAlignment property and specify the xlcenter constant to center the data in the cell. There are other constants we could use for this as well. These are seen here:

xlCenter

xlDistributed

xlJustify

xlLeft

xlRight

We use the cells property from the worksheet object to return a cells collection. The item method returns a specific cell, and then we supply a new value for the HorizontalAlignment:

$sheet.Cells.item(1,1).HorizontalAlignment = $xlConstants::xlCenter

We begin the script by calling the NewExcelSheet function and passing the name of our spreadsheet. This is the entry point into the script. It is seen here.

NewExcelSheet("Test")

The completed Office Excel workbook is seen here:

Image of the Office Excel workbook

 

Well, that is about all there is to it. The key was finding out the constant values that allow us to specify where the alignment will be performed. See you tomorrow.

Ed Wilson and Craig Liebendorfer, Scripting Guys