Pergunta

My Goal: Create a new tab and name it within a function.

My Issue: When I create the new tab inside of the function I cannot name the tab.

Notes: When I create the tab outside of the function it gets named correctly.

My Code:

Function Function_CreateWorksheets($Worksheets) {
    ForEach ($Worksheet in $Worksheets) {
        $Excel_Count_Worksheet++
        If ($Excel_Count_Worksheet -gt 3) {$Script:Excel.Worksheets.Add() |Out-Null}
        $Script:Excel.Worksheets.Item($Excel_Count_Worksheet).Name = $Worksheet
    }
}

#Load-Module -Module grouppolicy -Reload
Get-Variable Excel_* |Remove-Variable -Force

#Create Excel Com Object
$Excel = New-Object -com Excel.Application

# Make the Excel Application Visible to the end user
$Excel.visible = $True

# Create a WorkBook inside the Excel application
# that we can start manipulating.
$Excel_Workbook = $Excel.Workbooks.Add()
$Action_CreateWorksheet = 

#=======================================================
# Now that we have a workbook we need to create some
# additional worksheets (Tabs) beyond that initial 3
# that are created when the workbook is opened.
#=======================================================
#$Temp_MakeWorkSheet = $Excel.Worksheets.Add()

#=======================================================
# Once all the sheets are created each of the worksheets
# need to be assigned to a variable so they can be
# manipulated.
#=======================================================
Function_CreateWorksheets -Worksheets "System Summary","Test1","Test2","Test3","Test4"
Foi útil?

Solução

The problem is that you're assuming that the new worksheet is added as the last worksheet, but by default the Add method adds the new worksheet at the beginning. The script as you have it works for up to three worksheets, but after that it adds new worksheets with default names at the beginning and keeps renaming the last worksheet. You need to add the worksheets at the end.

Change

$Script:Excel.Worksheets.Add()

to

$Script:Excel.Worksheets.Add([System.Reflection.Missing]::Value, $Script:Excel.Worksheets.Item($Script:Excel.Worksheets.Count))

How that works:

  • The Add method takes four arguments: Before, After, Number, and Type.
  • $Excel.Worksheets.Item($Excel.Worksheets.Count)) gets the object representing the last worksheet. You want to supply that as the After argument in order to add the new worksheet after the last worksheet.
  • [System.Reflection.Missing]::Value is a placeholder for the missing Before argument (it can't be null)

APPENDIX

As an afterthought...although it works for this specific script, I find it a little iffy to rely on the default initial configuration of three worksheets, have the function change behavior based on that assumption (rename three worksheets, then start adding more), and rely on a counter variable to determine which worksheet you're renaming rather than renaming the active sheet you just added. Since the function inherits a preexisting workbook rather than creating a new one, I think it's "cleaner" to write a function that will give you a workbook that has blank worksheets with the specified names regardless of the initial configuration.

Maybe it's just my personal philosophical inclination to write functions in ways that are more generally applicable (read: reusable) rather than ad hoc, but I prefer functions that make as few assumptions as possible. Here's how I'd do it:

function Function_CreateWorksheets {
  [CmdletBinding()]
  param (
    [string[]] $WorkSheets,
    [object] $Excel
  )
  for ($i = 1; $i -le $Excel.Worksheets.Count; $i++) {
    $Excel.Worksheets.Item($i).Name = "DeleteMe$i"
  }
  foreach ($Worksheet in $Worksheets) {
      $Excel.Worksheets.Add([System.Reflection.Missing]::Value,$Excel.Worksheets.Item($Excel.Worksheets.Count)) | Out-Null
      $Excel.ActiveSheet.Name = $Worksheet
  }
  $Excel.DisplayAlerts = $false
  while ($Excel.Worksheets.Count -gt $Worksheets.Count) {
    $Excel.Worksheets.Item(1).Delete()
  }
  $Excel.DisplayAlerts = $true
}
  • The while loop at the end deletes all the preexisting worksheets. All new worksheets are added at the end, so the loop removes worksheets from the beginning until the number of worksheets in the workbook ($Excel.Worksheets.Count) matches the number of new worksheets ($Worksheets.Count). This needs to come at the end because a workbook has to have at least one worksheet, so you'll get an error if you try to delete all the worksheets before creating any new ones.
  • The initial for loop renames all the preexisting worksheets so that the function won't break if any of the new names match names that are already in use. You're going to get rid of them anyway, so you don't care what their names are.
  • By passing the Application object to the function as an argument, you can avoid the need to keep scoping it. You can call the function like this:

    Function_CreateWorksheets -Worksheets "System Summary","Test1","Test2","Test3","Test4" -Excel $Excel
    

(Of course, you can leave off the parameter names -Worksheets and -Excel as long as you maintain the correct order.)

Outras dicas

Thanks to your post I was able to get the result I needed. I did a slight variation to make the function reusable.

Function Function_CreateWorksheets {
    [CmdletBinding()]
    param (
        [parameter(Mandatory=$true,ValueFromPipeline=$true)][object] $Excel,
        [string[]] $WorkSheets
    )
    ForEach ($Worksheet in $Worksheets) {
        $Script:Excel_Count_Worksheet++
        If ($Excel_Count_Worksheet -gt $Excel.Worksheets.Count) {$Excel.Worksheets.Add([System.Reflection.Missing]::Value, $Excel.Worksheets.Item($Script:Excel.Worksheets.Count)) |Out-Null}
        $Excel.Worksheets.Item($Excel_Count_Worksheet).Name = $Worksheet
    }
    While ($Excel.Worksheets.Count -gt $Script:Excel_Count_Worksheet) {
        $Excel.Worksheets.Item($Excel.Worksheets.Count).Delete()
    }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top