Powershell script for setting Multi User Editing in excel for numerous files? - excel

I've written a code that tries to go through my company server and set all the excel files, under a certain folder, to shared so that multiple people can edit them at once. This has been a problem for a very long time here and I thought I had a nice code to fix this but I can't seem to access the property correctly. Can anyone help?
$ErrorActionPreference = "Stop"
$root = "P:\A N G"
$excelFiles = Get-ChildItem -path $root -File "*.xlsx" -Recurse
foreach ($excelFile in $excelFiles.FullName)
{
$excel = New-Object -ComObject Excel.Application
$excelWorkBook = $excel.Workbooks.Open($excelFile)
if (!$excelWorkBook.MultiUserEditing)
{
Write-Host $excelFile
$excelWorkBook._SaveAs([Microsoft.Office.Interop.Excel.XlSaveAsAccessMode]::xlShared)
$excelWorkBook.Close
}
}

With some help from a friend I managed to come up with a solution actually.
$ErrorActionPreference = "Stop"
$root = "P:\A N G"
$excelFiles = Get-ChildItem -path $root -File "*.xlsx" -Recurse
foreach ($excelFile in $excelFiles.FullName)
{
$excel = New-Object -ComObject Excel.Application
$excelWorkBook = $excel.Workbooks.Open($excelFile)
if (!$excelWorkBook.MultiUserEditing)
{
Write-Host $excelWorkBook.FullName
$accessMode = [Microsoft.Office.Interop.Excel.XlSaveAsAccessMode]::xlShared
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlWorkbookDefault
$excelWorkBook.SaveAs($excelWorkBook.FullName,$xlFixedFormat,$null,$null,$null,$null,$accessMode,$null,$null,$null,$null,$null)
$excelWorkBook.Close
}
}
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)

Related

Powershell Excel SaveAs requires confirmation

I use below script to convert bunch of xls files to xlsx.
$folderpath = %tempPath%
$filetype ="*xls"
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlWorkbookDefault
write-host $xlFixedFormat
$excel = New-Object -ComObject excel.application
$excel.visible = $true
Get-ChildItem -Path $folderpath -Include $filetype -recurse |
ForEach-Object `
{
$path = ($_.fullname).substring(0, ($_.FullName).lastindexOf("."))
"Converting $path"
$workbook = $excel.workbooks.open($_.fullname)
$path += ".xlsx"
$workbook.saveas($path, $xlFixedFormat)
$workbook.close()
}
$excel.Quit()
$excel = $null
[gc]::collect()
[gc]::WaitForPendingFinalizers()
It used to work perfectly running on VM.
Unfortunately with changing folder path I realised there are popup windows to confirm saving that didn't come up before and the script gets stuck on that.
Any simple corrections that could prevent that error?
"scriptError": {
"localizedName": "Error",
"value": "Unable to get the SaveAs property of the Workbook class\r\nAt C:\\Users\\~
"variableName": "ScriptError"
}
Here's an example of how I set the path when saving an Excel file using PowerShell. I set the path using a combination of the Get-Location cmdlet, Get-Date cmdlet and the file name, which is stored in a string variable for use when saving the script.
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlWorkbookDefault
$htFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlHtml
$Date = get-date -format R
$CurrentLocation = Get-Location
$CurrentDir = Get-location
$Timestamp = get-date -format d
$xlsx = [String] $CurrentLocation + "\MyNewExcelStuff-" + $Timestamp + ".xlsx"
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$excel.DisplayAlerts = $False
$workbook = $excel.Workbooks.add()
$sheet1 = $workbook.worksheets.Item(1)
$sheet1.name = "Stuff"
$Sheet1.Cells.Item(1,1) = "Reporting Stack Stuff"
$title = $Sheet1.Range("A1:K1")
$title.Select()
$title.MergeCells = $true
$title.VerticalAlignment = -4108 # Centre (vertically) heading
$title.HorizontalAlignment = -4108 # Centre (horizontally) heading
$Title.Interior.ColorIndex = 0
$Excel.ActiveWorkbook.SaveAs($xlsx, $xlFixedFormat)
Start-Sleep -s 2
$Excel.Quit()
$Excel = $Null
You should use $workbook.Close($false).

Powershell code cannot recognize all excel file(*.xlsm) in current location

I'm currently working on Powershell to handle excel files(*.xlsm).
The problem is the code below can only read "test.xlsm".
When the name is not test like "this.xlsm" , that code cannot read the file.
Any help...?
Thanks for your answer in advance :)
$destination = "C:\JJ\"
$dirName = Get-ChildItem -Name -Filter *.xlsm
$saveAs = $destination + "new\"
foreach($z in $dirName){
$excel=New-Object -ComObject Excel.Application
$excel.visible=$false
$excel.Displ`ayAlerts=$false
$book=$excel.Workbooks.Open($destination + $z)
$sheet=$book.Worksheets.item(1)
$sheet.Cells.Item(1,5)="=max(B2:B6)"
$book.SaveAs($saveAs + $z)
$excel.Quit()
$excel=$null
}
You are using confusing variable names in your code.. Why call the source path $destination??
Anyway, you should use the -File switch on your Get-ChildItem cmdlet to make sure this will only return FileInfo objects, not DirectoryInfo objects aswell. (these are Objects, not strings)
Then, there is a better way to construct paths. Use Join-Path instead of concatenating things like with $destination + $z.
Lastly, I would create the Excel object only once, before the loop and cleanup memory afterwards. Now, you are creating new COM objects in every iteration and never release them from memory.
Below code should do what you intend:
$source = "C:\JJ"
$destination = Join-Path -Path $source -ChildPath 'new'
# test if the destination path already exists and if not, create it
if (!(Test-Path -Path $destination -PathType Container)) {
$null = New-Item -Path $destination -ItemType Directory
}
# create the Excel COM object outside the loop
$excel = New-Object -ComObject Excel.Application
$excel.visible = $false
$excel.DisplayAlerts = $false
# get all *.xlsm files inside the source folder
Get-ChildItem -Path $source -Filter '*.xlsm' -File | ForEach-Object {
# The $_ automatic variable represents 1 FileInfo object in each iteration
$book = $excel.Workbooks.Open($_.FullName)
$sheet = $book.Worksheets.item(1)
$sheet.Cells.Item(1,5) = "=max(B2:B6)"
# join the destination path and the file name for output
$saveAs = Join-Path -Path $destination -ChildPath $_.Name
$book.SaveAs($saveAs)
$book.Close()
}
# cleanup Com objects
$excel.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($sheet)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($book)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
$excel = $null
Note, If you have PowerShell version below 3.0, the -File switch is not available. Instead, then use
Get-ChildItem -Path $source -Filter '*.xlsm' | Where-Object {!$_.PSIsContainer} | ForEach-Object { ... }
# remove -name to get a directory object instead of a string
$dirName = Get-ChildItem -Filter *.xlsm
# you need the file name from the directory object listing
foreach($z in $dirName.name){ ...... }

code for bulk CSV files in a directory to convert to xlsx

I used below code to convert file from CSV to xlsx. But it only convert single file at a time. I want this to convert all the files in directory at a time.
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $true
$Workbook = $xl.Workbooks.Open("$loglocation\errors_$server.csv")
$Worksheets = $Workbooks.Worksheets
$Workbook.SaveAs("$loglocation\errors_$server.xls",1)
$Workbook.Saved = $true
$xl.Quit()
With the PSExcel Module you can use Export-XLSX which makes this process very simple:
$loglocation = "C:\folder"
Get-ChildItem -Path $loglocation -Filter *.csv | foreach {
Export-XLSX -InputObject $_ -Path "$loglocation\$($_.BaseName).xlsx"
}
Try this, should work:
$filePath = Get-ChildItem -Path "path to csv" -filter *.csv
foreach ($file in $filePath )
{
$filename = $file.FullName
$filename
$xl = new-object -comobject excel.application
$xl.visible = $true
$Workbook = $xl.workbooks.open($filename)
$Worksheets = $Workbooks.worksheets
$Workbook.SaveAs($filename.Substring(0,$filename.Length-4) + ".xlsx",1)
$Workbook.Saved = $True
$xl.Quit()
}
Can move the excel connections outside the loop as well if you need to speed it up

PowerShell Error Creating XLSX

Okay, I have 6 CSVs each containing one column. For this example, the data from the first CSV is used to create the initial document, and each after that is attempting to save to the document.
#ID
$csvFile = "$path\ID.csv"
$fpath = $Filename
$processes = Import-Csv -Path $csvFile
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.add()
$excel.cells.item(1,1) = "ID"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,1) = $process.ID
$i++
} #end foreach process
$workbook.saveas($fpath)
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
#SRP
$csvFile = "$path\SRP.csv"
$processes = Import-Csv -Path $csvFile
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.add()
$excel.cells.item(1,2) = "SRP"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,2) = $process.SRP
$i++
} #end foreach process
$workbook.save($fpath)
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
When I get down to the save line on the second one (#SRP section) I get the following error:
Cannot find an overload for "Save" and the argument count: "1".
At D:\UserAdminScripts\0_Powershell_Test_Scripts\Scripts_For_Lisa\NED Stuff\NED_Reports.ps1:130 char:15
+ $workbook.save <<<< ($fpath)
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
If I let the script run after the error, I get the same result for each column.
I'm aware this script isn't clean, because I don't need to close and reopen Excel for each run, but I butchered this script from http://blogs.technet.com/b/heyscriptingguy/archive/2010/09/09/copy-csv-columns-to-an-excel-spreadsheet-by-using-powershell.aspx. The saveas works correctly in the first attempt, it's just the save causing an error.
I find when I break the script, I get a pop-up to confirm whether or not I want to make changes to Book2.xlsx. I tell it yes and I check and Book2 has the 2nd column filled out with the data I wanted as the second column on my original sheet.
Any help is appreciated.
Have a look at the $Workbook object with Get-Member:
Save Method void Save ()
The Save() method doesn't accept any arguments and it's failing to work out what to do with that method and your file name argument.
You Quit the Excel app in the #ID section (thus closing the file) so you need to reopen the file before accessing the workbook and trying to write to it.
Well, it looks like I answered my own question, due to ConanW's inspiration to actually, you know, think critically. The answer to my issue is as follows:
#ID
$csvFile = "$path\ID.csv"
$fpath = $Filename
$processes = Import-Csv -Path $csvFile
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.add()
$excel.cells.item(1,1) = "ID"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,1) = $process.ID
$i++
} #end foreach process
#SRP
$csvFile = "$path\SRP.csv"
$processes = Import-Csv -Path $csvFile
$excel.cells.item(1,2) = "SRP"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,2) = $process.SRP
$i++
} #end foreach process
$workbook.saveas($fpath)
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()

Using Powershell to loop through Excel files and check if Spreadsheet name exists

I'm trying to write a powershell script that will loop through each excel file in the given directory, check the file for a specifically named worksheet, and then copy that file to another location if it's a match.
Please see below for what I've already tried:
[void][reflection.assembly]::Loadwithpartialname("microsoft.office.excel")
$Excel = New-Object -ComObject Excel.Application
$tempLocation = "C:\Test\" # Path to read files
$files = Get-ChildItem C:\Test
ForEach ($file in $files)
{
#Check for Worksheet named TestSheet
$WorkBook = $Excel.Workbooks.Open($file)
$WorkSheets = $WorkBook.WorkSheets
foreach ($WorkSheet in $Workbook.Worksheets) {
If ($WorkSheet.Name -eq "TestSheet")
{$path = $tempLocation + "\" + $file
Write "Saving $path"
Copy-Item c:\Test\$file c:\Confirmed}
Else {Write "$path does not contain TestSheet"}
$WorkBook.Close()
}
}
This script returns no errors in PowerShell, but just sits there without writing anything or copying any files. Any ideas?
EDIT: Here's my final script that is now running successfully
$ErrorActionPreference= 'silentlycontinue'
$tempLocation = "C:\Source" # Path to read files
$targetlocation = "C:\Target"
Write "Loading Files..."
$files = Get-ChildItem C:\Source
Write "Files Loaded."
ForEach ($file in $files)
{
#Check for Worksheet named TestSheet
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $false
$Excel.DisplayAlerts = $false
$WorkBook = $Excel.Workbooks.Open($file.Fullname)
$WorkSheets = $WorkBook.WorkSheets | where {$_.name -eq "TestSheet"}
if($WorkSheets) {
$path = $tempLocation + "\" + $file
$dest = $targetlocation + "\" + $file
Write "Saving $path"
$WorkBook.SaveAs($dest)
}
$Excel.Quit()
Stop-Process -processname EXCEL
}
Read-host -prompt "The Scan has completed. Press ENTER to close..."
clear-host;
There were several issues with my script's logic. The following script ran successfully! It took hours of research...
$ErrorActionPreference= 'silentlycontinue'
$tempLocation = "C:\Source" # Path to read files
$targetlocation = "C:\Target"
Write "Loading Files..."
$files = Get-ChildItem C:\Source
Write "Files Loaded."
ForEach ($file in $files)
{
#Check for Worksheet named TestSheet
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $false
$Excel.DisplayAlerts = $false
$WorkBook = $Excel.Workbooks.Open($file.Fullname)
$WorkSheets = $WorkBook.WorkSheets | where {$_.name -eq "TestSheet"}
if($WorkSheets) {
$path = $tempLocation + "\" + $file
$dest = $targetlocation + "\" + $file
Write "Saving $path"
$WorkBook.SaveAs($dest)
}
$Excel.Quit()
Stop-Process -processname EXCEL
}
Read-host -prompt "The Scan has completed. Press ENTER to close..."
clear-host;
You don't need this line:
[void][reflection.assembly]::Loadwithpartialname("microsoft.office.excel")
($Excel = New-Object -ComObject Excel.Application is sufficient here)
I don't think you're referencing the full path to your Excel files. Try modifying this line:
$WorkBook = $Excel.Workbooks.Open($file)
Amend to:
$WorkBook = $Excel.Workbooks.Open($file.Fullname)
Additionally, consider adding a filter to your Get-ChildItem command, if there are sub-directories or non-Excel files, they will cause errors:
$files = Get-ChildItem C:\Test -filter "*.xls"

Resources