Counting PivotTables from an Excel Workbook with Powershell - excel

I have a problem with powershell and excel.
First of all my powershell version is 2 and excel version is 2010 x86.
My code is:
#Start Excel
[Reflection.Assembly]::LoadWithPartialName("Microsoft.Office.Interop.Excel") | Out-Null
$ObjXls = New-Object "Microsoft.Office.Interop.Excel.ApplicationClass"
$ObjXls.Visible = $False
$ObjXls.ScreenUpdating = $False
$ObjXls.DisplayAlerts = $False
#Open the template workbook
[String] $Private:TemplateFilePath = "$($Params['TEMPLATE_PATH'])\$TemplateFileName"
WriteLog -Message "Template file: $TemplateFilePath"
$WbXls = $ObjXls.Workbooks.open($TemplateFilePath)
$WbXls.RefreshAll()
#Counting Pivot Tables
ForEach ($sheet in $WbXls.Worksheets)
{
if ($sheet.Name -ne "LiteDB") {
[int]$count = $sheet.PivotTables.Count
[string]$sheetname = $sheet.Name
writelog ($sheetname + " --- " + $count)
For ($i = 0; $i -le $sheet.PivotTables.Count; $i++) {
if (-not $sheet.PivotTables($i).RefreshTable()) {throw "Unable to refresh PivotTable"}
$sheet.PivotTables($i).RefreshTable()
$sheet.PivotTables($i).PivotFields("Week").CurrentPage=$Currentweek
}
}
}
To be clear the "Writelog" command is a library created by me to generate a logfile, it
works so don't worry about it.
The output is the name of the sheets and the count of the pivot tables... but:
NS --- 0, SM --- 0, QTY --- 0
On each sheet i have one pivot table, but what is wrong? why is not recognizing the pivots on the sheets?
Can you help me with this?

PivotTables is a method of the worksheet object, not a property. So in C# (unlike in VBA), you should express the method call with parentheses.
[int]$count = $sheet.PivotTables.Count
should be
[int]$count = $sheet.PivotTables().Count

Related

Reading last row of specific column in Excel sheet and appending more data - in PowerShell

I'm trying to write data to specific column in an Excel spreadsheet with PowerShell. I would like to start below last row with data and continiue downwards. On machine I don't have Excel installed so COM won't work for me. I'm currently using Import-Excel to read whole sheet and used Open-ExcelPackage to read specific cell values.
I could do this in CSV file as opposed to .xlsx if it's easier.
Any help would be great!
Download PSExcel module from https://github.com/RamblingCookieMonster/PSExcel Import it using Import-Module.
Then use the following code:
$File = "Path to xlxs file"
$WSName = "SheetName"
$Excel = New-Excel -Path $File
$Worksheet = $Excel | Get-WorkSheet -Name $WSName
$SampleRows = #()
$SampleRows += [PSCustomObject]#{"A" = 1; "B" = 2; "C" = 3; "F" = 4 }
$row_to_insert = $SampleRows.count
$Worksheet.InsertRow($Worksheet.Dimension.Rows,$row_to_insert)
$WorkSheet.Cells["$($Worksheet.Dimension.Start.Address -replace ""\d"")$($Worksheet.Dimension.End.Row):$($Worksheet.Dimension.End.Address)"].Copy($WorkSheet.Cells["$($Worksheet.Dimension.Start.Address -replace ""\d"")$($Worksheet.Dimension.End.Row - $row_to_insert):$($Worksheet.Dimension.End.Address -replace ""\d"")$($Worksheet.Dimension.End.Row - $row_to_insert)"]);
$WorkSheet.Cells["$($Worksheet.Dimension.Start.Address -replace ""\d"")$($Worksheet.Dimension.End.Row):$($Worksheet.Dimension.End.Address)"] | % {$_.Value = ""}
ForEach ($Row in $SampleRows) {
ForEach ($data in $Row.PSObject.Properties.Name) {
$WorkSheet.Cells["$data$($Worksheet.Dimension.Rows)"].Value = $SampleRow.$data
}
}
$Excel | Close-Excel -Save
This code adds 1 row after the last row in the selected worksheet and adds values to this row from $SampleRows.... I think you got the idea. if you need add more rows to $SampleRows array.

Powershell Invalid Index Error When Using Excel Cells?

I am currently working on a script where I use several arrays to lookup inventory lists in Excel. After running a few tests I can get my script to read the contents of each cell (thanks to some research from this site!) but I can't use the contents of the cell in a variable. I receive an "Invalid Index" error when I try to switch to a worksheet using contents from one of the cells being read. I've also added an example of how the data is arranged.
#Test array
$array = "Dog", "Cat", "Mouse", "Tiger"
#Location of the Excel file to edit
$FileLoc = "Q:\Cutsheet.xlsx"
#Create Excel Com Object, and display it
$excel = new-object -com Excel.Application
$excel.visible = $true
#Open Workbook
$workbooks = $excel.workbooks.Open($FileLoc)
$worksheets = $workbooks.Worksheets
$worksheet = $worksheets.item("DATA")
#opens inventory workbook
$source = $excel.workbooks.Open("Q:\inventory.xlsx")
$sourceSheets = $source.Worksheets
<#
#This loop will search for match element of the array with a corresponding cell on an excel spreadsheet.
#That cell is grouped with several names of inventory worksheet names. The script will copy each inventory
#and append it to the existing cutsheet.
#>
foreach($element in $array) {
for ($i = 9; $i -lt 20; $i++) {
if ($worksheet.Cells.Item($i, 1).Text -eq $element) {
$j = 2
while ($worksheet.Cells.Item($i, $j).Text -ne "") {
Write-Host $worksheet.Cells.Item($i, $j).Value2
$name = $worksheet.Cells.Item($i, $j).Value2
$sourceSheet = $sourceSheets.Item($name)
$sourceSheet.Copy([system.type]::missing, $worksheets)
$j++
}
}
}
}
Example spreadsheet

Command to retrieve all non-empty block-content from Excel workbooks?

I have a sheet DataRepo about the size of 300 rows and 10 rows, about 300 such Excel files in XLSX format. I need to read each Excel file and store it as a CSV (because original XLSX files are corrupted with KeyError, other methods in Python/R resulting to KeyError unless resaving manually with Excel).
I am currently using $Sheet.Cells.Item(row, col).Text to get single value as text but the need over the whole block: either I need to 2-loop over the block and save it CSV or find some ready method for the $Sheet, any ready PowerShell method available? Which looping options available in PowerShell?
How can I retrieve all non-empty content in an Excel sheet with PowerShell?
$XLSDoc = 'C:\Users\hhh\Desktop\1.xlsx'
$SheetName = "DataRepo"
$Excel = New-Object -ComObject "Excel.Application"
$Workbook = $Excel.Workbooks.Open($XLSDoc)
$Sheet = $Workbook.Worksheets.Item($SheetName)
#Get data:
$Sheet.Cells.Item(1,2).Text
Can I do something similar to VBA in PowerShell?
Dim i As Integer
Dim j As Integer
i = 1
j = 1
Do While i < 10
Do While j < 10
Sheet.Cells.Item(i, j).Text
j = j + 1
Loop
i = i + 1
Loop
Use something like this to export each worksheet to a separate CSV:
$wbName = $Workbook.Name
$wbPath = $Workbook.Path
$Workbook.Worksheets | ForEach-Object {
$csvName = Join-Path $wbPath ('{0}_{1}.csv' -f $wbName, $_.Name)
$_.SaveAs($csvName, 6)
}
The following code creates a function out of the code here and then loop over all of the xlsx files in the directory, replacement and trimming added to avoid 216 chars limit per file. Then it outputs the CSV files to the directory of each sheet.
Function ExportXLSXToCSVs ($XLSDoc)
{
$Excel = New-Object -ComObject "Excel.Application"
$Workbook = $Excel.Workbooks.Open($XLSDoc)
$wbName = $Workbook.Name
$wbPath = $Workbook.Path
$Workbook.Worksheets | ForEach-Object {
$csvName = Join-Path $wbPath ('{0}_{1}.csv' -f $wbName, $_.Name)
#Trim/replacements added to avoid the limit 216 chars per file
$csvName = $csvName.Trim().Replace(" ", "")
$_.SaveAs($csvName, 6) #CSV
}
}
#DEMO 1 over a single file
#ExportXLSXToCSVs('C:\Users\hhh\Desktop\1.xlsx')
#DEMO 2 over all files in a directory
Get-ChildItem "C:\Users\hhh\Desktop\Data\" -Filter *.xlsx | ForEach-Object {
$myFile = $_.DirectoryName +"\"+ $_.Name
ExportXLSXToCSVs($myFile)
}

Find text in Excel

I am writing a script, to automate taking reports from various SQL databases, which is currently ran once a month manually. So far I have a working prototype that will read an SQL database and will parse the information into an Excel file, save it, and then email it to someone.
What I want to be able to do is have another Excel file called emails.xlsx. This file will have three columns: Emails(A), Server(B), Database(C). I want to be able to search the file for anything in column 2 that is the same and grab the emails from those rows and put them in to a var.
#Import Email Details
$emailPath = "C:\temp\emails.xlsx"
$sheetName = "emails"
$workBook1 = $excel.Workbooks.Open($emailPath)
$worksheet = $workBook1.sheets.Item($sheetName)
$cell = 1;
$CcCheck = $worksheet.Range.("A1").Text;
FOREACH($dbase in $worksheet.Range("C1").EntireColumn)
{
DO{
$CcCheck = $worksheet.Range("A$cell").Text;
if($CcCheck -ne " ") {
$data = $worksheet.Range("C$cell").Text;
$server = $worksheet.Range("B$cell").Text;
$Cc += ", $CcCheck";
$cell++
}
} while($foreach.MoveNext() -eq $foreach.Current)
}
Write-Host " Loaded Server, $cell Emails and DB" -ForegroundColor "Green";
Write-Host "";
Import-Csv .\emails.csv -Header emails,server,database | Foreach-Object{
$dataSource = $_.server
$dataBase = $_.database
This fixed the problem by just referencing the headers after converting the excel file to a CSV.

Export as CSV instead of a XLS file

I have a script that places everything nicely into a spread sheet. The problem is, I need it to export as a csv file instead. All the foreach loops are completely baffling me here as far as where to put the export csv functions in the script. If someone could could school me on how to get the fields into a csv file, It would be greatly appreciated.
$date = 0
$date = get-date -format "yyyy-MMM-dd-hhmm"
$date
#New Excel Application
$Excel = New-Object -Com Excel.Application
$Excel.visible = $False
# Create 1 worksheets
$Excel = $Excel.Workbooks.Add()
# Assign each worksheet to a variable and
# name the worksheet.
$Sheet1 = $Excel.Worksheets.Item(1)
$Sheet1.Name = "HH_SERVERS"
#Create Heading for General Sheet
$Sheet1.Cells.Item(1, 1) = "Machine_Name"
$Sheet1.Cells.Item(1, 2) = "OS"
$Sheet1.Cells.Item(1, 3) = "Software"
$Sheet1.Cells.Item(1, 4) = "Vendor"
$Sheet1.Cells.Item(1, 5) = "Version"
$colSheets = ($Sheet1)
foreach ($colorItem in $colSheets)
{
$intRow = 2
$intRowDisk = 2
$intRowSoft = 2
$intRowNet = 2
$WorkBook = $colorItem.UsedRange
$WorkBook.Interior.ColorIndex = 20
$WorkBook.Font.ColorIndex = 11
$WorkBook.Font.Bold = $True
}
#Auto Fit all sheets in the Workbook
foreach ($colorItem in $colSheets)
{
$WorkBook = $colorItem.UsedRange
$WorkBook.EntireColumn.AutoFit()
clear
}
$Servers = get-content "c:\temp\HH_Servers.txt"
foreach ($Server in $Servers)
{
$GenItems2 = gwmi Win32_OperatingSystem -Comp $Server
$Software = gwmi Win32_Product -Comp $Server
# Populate General Sheet(1) with information
foreach ($objItem in $GenItems2)
{
$Sheet1.Cells.Item($intRow, 2) = $objItem.Caption
}
#Populate Software Sheet
foreach ($objItem in $Software)
{
$Sheet1.Cells.Item($intRowSoft, 1) = $Server
$Sheet1.Cells.Item($intRowSoft, 3) = $objItem.Name
$Sheet1.Cells.Item($intRowSoft, 4) = $objItem.Vendor
$Sheet1.Cells.Item($intRowSoft, 5) = $objItem.Version
$intRowSoft = $intRowSoft + 1
}
}
$outputfile = "c:\temp\" + $date.toString() + "-HH_Server_Software"
$Excel.SaveAs($outputfile)
$Excel.Close()
Write-Host "*******************************" -ForegroundColor Green
Write-Host "The Report has been completed." -ForeGroundColor Green
Write-Host "*******************************" -ForegroundColor Green
# ========================================================================
# END of Script
# ==================
You can't save an entire workbook as CSV. You need to save the individual worksheet instead. The file format value for CSV is 6 (don't remember where I found that out though):
$xlCSV = 6
$outputfile = "c:\temp\" + $date.toString() + "-HH_Server_Software.csv"
$Sheet1.SaveAs($outputfile, $xlCSV)
(Tested on Windows 7 with Excel 2013.)
Thanks to #Matt for a comment with a link to the XLFileFormat Enumerations.

Resources