How PowerShell Sum an Excel column and print the result? - powershell

I have an excel file with 10 columns. I want to get the sum of the column with header "Sales" and print it on the console.
How this can be done with PowerShell? I am using the below code but I do not know how to replace H with $i in the following expression:
='=SUM(H1:H'+$RowCount')'
Where H is column "Sales"
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $False
$NewWorkbook = $Excel.Workbooks.open("C:\Test.xlsx")
$NewWorksheet = $NewWorkbook.Worksheets.Item(1)
$NewWorksheet.Activate() | Out-Null
$NewWorksheetRange = $NewWorksheet.UsedRange
$RowCount = $NewWorksheetRange.Rows.Count
$ColumnCount = $NewWorksheetRange.Columns.Count
for ($i = 1; $i -lt $ColumnCount; $i++)
{
if ($NewWorksheet.cells.Item(1,$i).Value2 -eq "Sales")
{
$NewWorksheet.Cells.Item($RowCount+2,$i)='=SUM(H1:H'+$RowCount')'
Write-Host $NewWorksheet.Cells.Item($RowCount+1,$i).Value2
}
}
$Excel.Application.DisplayAlerts=$False
$NewWorkbook.SaveAs("C:\Test_New.xlsx")
$NewWorkbook.close($false)
$Excel.quit()
spps -n excel
I have replaced:
$NewWorksheet.Cells.Item($RowCount+2,$i) ='=SUM(H1:H'+(1+$RowCount)+')'
Write-Host $NewWorksheet.Cells.Item($RowCount+2,$i).Value2
with:
$FirstCell = $NewWorksheet.Cells(2,$i).Address('+True, False+')
$LastCell = $NewWorksheet.Cells(1+$RowCount,$i).Address('+True, False+')
$NewWorksheet.Cells.Item($RowCount+2,$i)='=SUM('+$FirstCell+':'+$LastCell+')'
Write-Host $NewWorksheet.Cells.Item($RowCount+2,$i).Value2

I can highly recommend the PowerShell-Module "ImportExcel". This Modules enables you to import Excel-Files as easy as with Import-Csv
Without knowing much about your files/enviroment, you could try something like this:
foreach ($data in (Import-Excel "$PSScriptRoot\test.xlsx")) {
$result += $data.Sales
}
Write-Host $result

Related

powershell rename XLSX spreadsheet columns

I have a spreadsheet that has spaces in the column names, how do I go about replacing the space with underscores on the column headers?
Note: I am new at this so bear with me
using this code with no luck:
Powershell: search & replace in xlsx except first 3 columns
Theo's code works great!
$sheetname = 'my Data'
$file = 'C:\Users\donkeykong\Desktop\1\booka.xlsx'
# create a COM Excel object
$objExcel = New-Object -ComObject Excel.Application
$objExcel.Visible = $false
$workbook = $objExcel.Workbooks.Open($file)
$sheet = $workbook.Worksheets.Item($sheetname)
$sheet.Activate()
# get the number of columns used
$colMax = $sheet.UsedRange.Columns.Count
# loop over the column headers and replace the whitespaces
for ($col = 1; $col -le $colMax; $col++) {
$header = $sheet.Cells.Item(1, $col).Value() -replace '\s+', '_'
$sheet.Cells.Item(1, $col) = $header
}
# close and save the changes
$workbook.Close($true)
$objExcel.Quit()
# IMPORTANT: clean-up used Com objects
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objExcel)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
Assuming your Excel file has the headers in the first row, this should work without using the ImportExcel module:
$sheetname = 'my Data'
$file = 'C:\Users\donkeykong\Desktop\1\booka.xlsx'
# create a COM Excel object
$objExcel = New-Object -ComObject Excel.Application
$objExcel.Visible = $false
$workbook = $objExcel.Workbooks.Open($file)
$sheet = $workbook.Worksheets.Item($sheetname)
$sheet.Activate()
# get the number of columns used
$colMax = $sheet.UsedRange.Columns.Count
# loop over the column headers and replace the whitespaces
for ($col = 1; $col -le $colMax; $col++) {
$header = $sheet.Cells.Item(1, $col).Value() -replace '\s+', '_'
$sheet.Cells.Item(1, $col) = $header
}
# close and save the changes
$workbook.Close($true)
$objExcel.Quit()
# IMPORTANT: clean-up used Com objects
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($objExcel)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()

update a cell in a excel sheet using powershell

I need to search for a word in a row from a spreadsheet and update another cell in the same row with a different value. For example, I have the data like this. I need to search for the person "Smith" from the below spreadsheet and update the value of the 'Status' column from 'Enabled' to 'Disabled' for that row.
"Region","Zone","Customer","Process","Status"
"TEST","East","Smith","HR","Disabled"
"TEST","East","Allen","Finance","Enabled"
"TEST","East","Jake","Payroll","Enabled"
I tried regex and few other functions before posting the question. But I can't get them to work.
Thanks.
It's very easy to use Excel with PowerShell:
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$excelFile = 'C:\test\testsheet.xlsx'
$searchFor = 'Smith'
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$excel.ScreenUpdating = $true
$workbook = $excel.Workbooks.Open( $excelFile ,$null, $false )
$ws = $workbook.WorkSheets.item(1)
[void]$ws.Activate()
$searchRange = $ws.UsedRange
$searchResult = $searchRange.Find( $searchFor, [System.Type]::Missing, [System.Type]::Missing,
[Microsoft.Office.Interop.Excel.XlLookAt]::xlWhole,
[Microsoft.Office.Interop.Excel.XlSearchOrder]::xlByColumns,
[Microsoft.Office.Interop.Excel.XlSearchDirection]::xlNext )
while( $searchResult ) {
$row = $searchResult.Row
$col = $searchResult.Column
$ws.Cells( $row, $col + 2 ).Value2 = 'Disabled'
$searchResult = $searchRange.FindNext( $searchResult )
if( $searchResult -and $searchResult.Row -le $row ) {
break
}
}
[void]$workbook.Save()
[void]$workbook.Close()
[void]$excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel) | Out-Null
I got it working using the below script.
$TGTSERVER = "testservwc01"
$name = "ORATDLLSTR"
$input = Invoke-Command -ComputerName "$TGTSERVER" -ScriptBlock {Import-Csv 'C:\test.csv'}
$value = "Disabled"
$Output = foreach ($i in $input) {
if ($i.Process_Instance -match "$name") {$i.Status = "$value"} $i }
$OutArray = $Output | Select-Object -Property * -ExcludeProperty PSComputerName, RunspaceId, PSShowComputerName
$OutArray | Invoke-Command -ComputerName "$TGTSERVER" -ScriptBlock {Export-Csv 'C:\test.csv' -NoTypeInformation}
if ( $LastExitCode -ge 1)
{
Write-Warning -Message "$Computer : Disable Step failed"
exit 1
}
However the script fails with exit code 1 even though it updates the csv file with the right value on the remote server.
I have found solution which meet my needs... using Powershell
Not the issue mentioned as in topic.. but overall module have a lot of options which might help modify Excel File using PowerShell
https://www.powershellgallery.com/packages/PSWriteExcel/0.1.15
https://github.com/EvotecIT/PSWriteExcel/blob/master/Examples/Run-Example-FindReplace.ps1
Install-Module -Name PSWriteExcel
Import-Module PSWriteExcel -Force
$FilePath = "D:\Excel_test.xlsx"
$FilePathOutput = "D:\Excel_test1.xlsx"
Find-ExcelDocumentText -FilePath $FilePath -Find 'evotec' -Replace -ReplaceWith 'somethingelse' -FilePathTarget $FilePathOutput -OpenWorkBook -Regex -Suppress $true

Windows Power Shell rename files

I am sort of new to scripting and here's my task:
A folder with X files. Each file contains some Word documents, Excel sheets, etc. In these files, there is a client name and I need to assign an ID number.
This change will affect all the files in this folder that contain this client's name.
How can do this using Windows Power Shell?
$configFiles = Get-ChildItem . *.config -rec
foreach ($file in $configFiles)
{
(Get-Content $file.PSPath) |
Foreach-Object { $_ -replace " JOHN ", "123" } |
Set-Content $file.PSPath
}
Is this the right approach ?
As #lee_Daily pointed out you would need to have different code to perform a find and replace in different file types. Here is an example of how you could go about doing that:
$objWord = New-Object -comobject Word.Application
$objWord.Visible = $false
foreach ( $file in (Get-ChildItem . -r ) ) {
Switch ( $file.Extension ) {
".config" {
(Get-Content $file.FullName) |
Foreach-Object { $_ -replace " JOHN ", "123" } |
Set-Content $file.FullName
}
{('.doc') -or ('.docx')} {
### Replace in word document using $file.fullname as the target
}
{'.xlsx'} {
### Replace in spreadsheet using $file.fullname as the target
}
}
}
For the actual code to perform the find and replace, i would suggest com objects for both.
Example of word find and replace https://codereview.stackexchange.com/questions/174455/powershell-script-to-find-and-replace-in-word-document-including-header-footer
Example of excel find and replace Search & Replace in Excel without looping?
I would suggest learning the ImportExcel module too, it is a great tool which i use a lot.
For Word Document : This is what I'm using. Just can't figure out how this script could also change Header and Footer in a Word Document
$objWord = New-Object -comobject Word.Application
$objWord.Visible = $false
$list = Get-ChildItem "C:\Users\*.*" -Include *.doc*
foreach($item in $list){
$objDoc = $objWord.Documents.Open($item.FullName,$true)
$objSelection = $objWord.Selection
$wdFindContinue = 1
$FindText = " BLAH "
$MatchCase = $False
$MatchWholeWord = $true
$MatchWildcards = $False
$MatchSoundsLike = $False
$MatchAllWordForms = $False
$Forward = $True
$Wrap = $wdFindContinue
$Format = $False
$wdReplaceNone = 0
$ReplaceWith = "help "
$wdFindContinue = 1
$ReplaceAll = 2
$a = $objSelection.Find.Execute($FindText,$MatchCase,$MatchWholeWord, `
$MatchWildcards,$MatchSoundsLike,$MatchAllWordForms,$Forward,`
$Wrap,$Format,$ReplaceWith,$ReplaceAll)
$objDoc.Save()
$objDoc.Close()
}
$objWord.Quit()
What If I try to run on C# ? Is anything else missing?
}
string rootfolder = #"C:\Temp";
string[] files = Directory.GetFiles(rootfolder, "*.*",SearchOption.AllDirectories);
foreach (string file in files)
{ try
{ string contents = File.ReadAllText(file);
contents = contents.Replace(#"Text to find", #"Replacement text");
// Make files writable
File.SetAttributes(file, FileAttributes.Normal);
File.WriteAllText(file, contents);
}
catch (Exception ex)
{ Console.WriteLine(ex.Message);
}
}

Extract sections from range found in word document

Below code works fine, we got start and end point which needs to be extracted but im not able to get range.set/select to work
I'm able to get the range from below, just need to extra and save it to CSV file...
$found = $paras2.Range.SetRange($startPosition, $endPosition) - this piece doesn't work.
$file = "D:\Files\Scan.doc"
$SearchKeyword1 = 'Keyword1'
$SearchKeyword2 = 'Keyword2'
$word = New-Object -ComObject Word.Application
$word.Visible = $false
$doc = $word.Documents.Open($file,$false,$true)
$sel = $word.Selection
$paras = $doc.Paragraphs
$paras1 = $doc.Paragraphs
$paras2 = $doc.Paragraphs
foreach ($para in $paras)
{
if ($para.Range.Text -match $SearchKeyword1)
{
Write-Host $para.Range.Text
$startPosition = $para.Range.Start
}
}
foreach ($para in $paras1)
{
if ($para.Range.Text -match $SearchKeyword2)
{
Write-Host $para.Range.Text
$endPosition = $para.Range.Start
}
}
Write-Host $startPosition
Write-Host $endPosition
$found = $paras2.Range.SetRange($startPosition, $endPosition)
# cleanup com objects
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($doc) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($word) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
This line of code is the problem
$found = $paras2.Range.SetRange($startPosition, $endPosition)
When designating a Range by the start and end position it's necessary to do so relative to the document. The code above refers to a Paragraphs collection. In addition, it uses SetRange, but should only use the Range method. So:
$found = $doc.Range.($startPosition, $endPosition)

How to sort an excel column using Powershell

I need to sort an excel spreadsheet by sorting one column be ascending numbers so 1,2,3,4,5...
Does anyone know a quick and dirty way to sort a excel column in powershell?
function Release-Ref ($ref) {
([System.Runtime.InteropServices.Marshal]::ReleaseComObject(
[System.__ComObject]$ref) -gt 0)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
$objExcel = new-object -comobject excel.application
$objExcel.Visible = $True
$objWorkbook = $objExcel.Workbooks.Open("C:\test\flag for errors\1921BB.xls")
$objWorksheet = $objWorkbook.Worksheets.Item(1)
$objRange = $objWorksheet.UsedRange
$objRange2 = $objworksheet.Range("E1")
[void] $objRange.Sort($objRange2)
$objWorkbook.Save()
$a = Release-Ref($objWorksheet)
$a = Release-Ref($objWorkbook)
$a = Release-Ref($objExcel)