Excel Office Add-In API Worksheet Protection Password - excel

I have a question relating to Excel's worksheet protection...
The context is that I need to have different worksheets available for different user groups to edit but all groups must at least see all sheets e.g. usergroup1 can edit sheets two and three and parts of sheet one, usergroup2 can edit only sheet one.
I am able to set the FormatProtection (range.format.protection.locked = false;) accordingly and WorksheetProtection (worksheet.protection.protect();) to enable this but I don't appear to have the ability to set a password through the API against the Worksheet Protection? This means for example, that either group can simply click the Unprotect Sheet option in the review ribbon and edit the sheets that I don't want them to.
I've tried going through the below documentation but to no avail unfortunately.
http://dev.office.com/reference/add-ins/excel/worksheetprotection
https://github.com/OfficeDev/office-js-docs/blob/master/reference/excel/worksheetprotection.md
As an example, here is a function that I'd like to complete:
function CopyWorksheet() {
var newAddress;
Excel.run(function (ctx) {
var worksheet = ctx.workbook.worksheets.getActiveWorksheet();
var range = worksheet.getUsedRange();
range.load();
// insert new worksheet
var newWorksheetName = "Copied_Sheet";
var newWorksheet = ctx.workbook.worksheets.add(newWorksheetName);
return ctx.sync().then(function () {
// copy the old values to the new worksheet
newAddress = range.address.substring(range.address.indexOf("!") + 1);
newWorksheet.getRange(newAddress).values = range.values;
newWorksheet.getRange(newAddress).formulas = range.formulas;
newWorksheet.getRange(newAddress).text = range.text;
// protect both worksheets
worksheet.protection.protect();
newWorksheet.protection.protect();
// requirement here to set a password so that no one can
// edit the worksheets by selecting 'Unprotect Sheet' in excel
// ...
})
.then(ctx.sync)})
.catch(function(error) {
console.log("Error: " + error);
});
}
Currently, I'm using Excel 2016 (desktop version). Is this possible to implement or have I missed some functionality that exists which can achieve the same result?
Thanks for your help.

Password-protection is not available in our APIs. You can protect the sheet to avoid casual edits, but you can't password-protect. The reason is that password-protection is not available on all endpoints (IIRC, there was an issue with Excel Online).
If you want to file a suggestion bug on UserVoice, you can see if we'd consider doing password-protection as a Desktop-only API. We have so far avoided doing those in Excel, but I do know that Word has done a few "WordApiDesktop" APIs. So depending on how much it's blocking your (and others') scenario, that might be an option. In which case you'd be able to password-protect and unprotect on desktop, but wouldn't be able to take those actions online.

There is an update for this issue: we now support password protection. Check https://learn.microsoft.com/en-us/javascript/api/excel/excel.workbookprotection?view=office-js#protect-password-

Related

Unlock individual cells before protect sheet

There's another question addressing how to protect the sheet but doesn't show how to unlock individual cells.
I can't just start recording & create a script (which usually show how it's done) because apparently, excel online still doesn't support protecting sheets from the web UI.
This took me a while to find out, so I'm answering my own question here for the benefit of others with the same need.
function main(workbook: ExcelScript.Workbook) {
let sheet = workbook.getWorksheet("Sheet1");
// will not let you lock/unlock cells if protected
sheet.getProtection().unprotect();
// just checking
let locked = sheet.getRange("B9").getFormat().getProtection().getLocked()
console.log('value of locked: ', locked)
// unlock
sheet.getRange("B9").getFormat().getProtection().setLocked(false)
// sanity check
locked = sheet.getRange("B9").getFormat().getProtection().getLocked()
console.log('locked value after set to false: ',locked)
sheet.getProtection().protect({
allowFormatCells: false
//allowFormatCells: true
});
}

The entire worksheet is not editable after protect the sheet with some locked cells

I have issue with protect worksheet in excel online. I will unlock all of the cells in the worksheet, and lock one range, then protect worksheet, after that nothing is editable in the worksheet, even the cells are unlocked.This issue only happens for excel online version, works fine for installed desktop version. Anyone has idea how to solve the problem or the is an officeJs bug?
Excel.run(function (ctx) {
//Worksheet
var sheet = ctx.workbook.worksheets.getItem("Sheet1");
//Entire Range
var entireRange = sheet.getRange();
entireRange.format.protection.locked = false;
//Specific Range
var range = sheet.getRange("A1:B5");
range.format.protection.locked = false;
//Protect Entire sheet
sheet.protection.protect({
allowInsertRows: false,
allowDeleteRows: false
});
return ctx.sync();
}).catch(errorHandler);
This should be an issue of Office-Js API.
We Office-Js API team are looking into this issue.
We are tracking it by internal bug 2542108.
The worksheet will recover to editable state when user refreshes the page. I'm afraid there's no workaround you can do from API side currently.
the issue is fixed now, this should no longer happen.

Missing method in JavaScript API for Excel: copy a sheet

Since there is no way to cancel the changes made by an add-in, we need to provide users with backup options.
The current version of JavaScript API for Excel doesn't have a method for copying a sheet with its data and formatting.
Does anyone know of any workarounds or plans for adding such method?
There are indeed currently no way easy way of duplicating a worksheet and so feel free to request it on the Office Extensibility Platform's UserVoice. While such an API may be coming in the future, you could in the meantime add a new worksheet using worksheetCollection.add(), grab a worksheet's used range using the worksheet.getUsedRange() method and copy its values to another sheet.
Your code would then look something like this :
function duplicateSheet(worksheetName) {
Excel.run(function(ctx) {
var worksheet = ctx.workbook.worksheets.getItem(worksheetName);
var range = worksheet.getUsedRange();
range.load("values", "address");
var newWorksheet = ctx.workbook.worksheets.add(worksheetName + " - Backup");
return ctx.sync().then(function() {
var newAddress = range.address.substring(range.address.indexof("!") + 1);
newWorksheet.getRange(newAddress).values = range.values;
}).then(ctx.sync);
});
}
Let me know how that works out for you.
Gabriel Royer - Developer on the Office Extensibility Team, MSFT

Google Doc referencing another sheet

After speaking to Google Enterprise Support they suggested I create a post on Stackoverflow.
I have a Google Doc sheet with a list of stores (sheet A) and I'm trying to reference another sheet (sheet B) to VOID specific stores.
What I'm going to accomplish is if a store name on the void sheet is entered into sheet A it will automatically convert the store name to VOID.
Google support believes an IF statement would be the beginning to the solution, they weren't able to help beyond this.
For anyone's time that comes up with a solution, I'd be happy to buy you a couple Starbucks coffees. Your support means a lot.
make it simple using Google Scripts. (Tutorial)
To edit scripts do: Tools -> Script Editor
and in the current add this function
EDIT:
Well, you need to make a trigger. In this case will be when the current sheet is edited
Here is the javascript
function onEdit(event) {
// get actual spreadsheet
var actual = event.source.getActiveSheet();
// Returns the active cell
var cellSheet1 = actual.getActiveCell();
// get actual range
var range = event.source.getActiveRange();
// get active spreadsheet
var activeSpreadsheet = SpreadsheetApp.getActiveSpreadsheet();
// get sheets
var sheet_two = activeSpreadsheet.getSheetByName("Sheet2");
range.copyValuesToRange(sheet_two, range.getColumn(), range.getColumn(), range.getRow(), range.getRow());
// get cell from sheet2
var cell = sheet_two.getRange(range.getValue());
cell.setValue(cellSheet1.getValue());
// display log
Logger.log(cellSheet1.getValue());
}
if you want to test it you can check my spreadsheet, there you can check that all data thats is inserted in sheet1 will be copied to sheet2

Excel process stays alive even after calling Quit

I am creating Excel Sheet using Devexpress Exporter and then saving the file at a particular location.
After the creation of file, I have to open it, to add dropdownlist of items and then save it again in same location.
After all the operations, the file has to be emailed automatically to the email address from database.
Now if I have 1000 email addresses, and to automate this process, it is creating more than 10 instances of Excel.
How can I stop creation of those instance and how can I use excel operations without using more memory.
Code is as below:
protected string CreateExcelFile(string FilterName)
{
Random ranNumber = new Random();
int number = ranNumber.Next(0, 10000000);
string FileName = "TestDoc"+DateTime.Now.Year.ToString()+number.ToString()+DateTime.Now.Second.ToString()+".xls";
string path = #"c:\TestDocuments\"+FileName;
Directory.CreateDirectory(Path.GetDirectoryName(path));
FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
XlsExportOptions options = new XlsExportOptions();
options.ExportHyperlinks = false;
ASPxExporter.WriteXls(fs, options);
fs.Close();
AddDropDownToExcel(path);
return path;
}
//Adding The Dropdownlist Of Items TO Generated Excel Sheet
protected void AddDropDownToExcel(string path)
{
Microsoft.Office.Interop.Excel.Application application = new Microsoft.Office.Interop.Excel.Application();
string fileName = path.Replace("\\", "\\\\");
string RowCount = "F" + (testgrid.VisibleRowCount + 1).ToString();
// Open Excel and get first worksheet.
var workbook = application.Workbooks.Open(fileName);
var worksheet = workbook.Worksheets[1] as Microsoft.Office.Interop.Excel.Worksheet;
// Set range for dropdownlist
var rangeNewStatus = worksheet.get_Range("F2", RowCount);
rangeNewStatus.ColumnWidth = 20;
rangeNewStatus.Validation.Add(Microsoft.Office.Interop.Excel.XlDVType.xlValidateList, Microsoft.Office.Interop.Excel.XlDVAlertStyle.xlValidAlertStop,
Microsoft.Office.Interop.Excel.XlFormatConditionOperator.xlBetween, "Item1,Item2,Item3,Item4");
// Save.
workbook.Save();
workbook.Close(Microsoft.Office.Interop.Excel.XlSaveAction.xlSaveChanges, Type.Missing, Type.Missing);
application.Quit();
}
First, I sincerely hope this isn't running on a server.
Then, if your problem is that too many instances of Excel are created, a thought is "don't create an instance every single time". Instead of starting Excel every time AddDropDownToExcel is called, can you reuse the same instance?
The problem you are having shows up regularly in Excel interop scenario; even though you are done and tell Excel to close, it "stays alive". It's usually caused by your app still holding a reference to a COM object that hasn't been disposed, preventing Excel from closing. This StackOverflow answer provides some pointers: https://stackoverflow.com/a/158752/114519
In general, to avoid that problem, you want to follow the "one-dot" rule. For instance, in your code:
var workbook = application.Workbooks.Open(fileName);
will be a problem, because an "anonymous" wrapper for Workbooks is created, and will likely not be disposed properly. The "one-dot" rule would say "don't use more than one dot when working with Excel interop", in this case:
var workbooks = application.Workbooks;
var workbook = workbooks.Open(fileName);
A totally different thought - instead of using Interop, can't you use OpenXML to generate your Excel file? I have never tried it to create drop downs, but if it supports it, it will be massively faster than Interop, and the type of problems you have won't happen.
Hope this helps.
As I know the grow of number of runnig excel.exe processes is 'normal' situation to excel :)
The dumbest advice is just kill sometimes it's processes. BUT, this way will be absolutely unhelpful if you use excel during your app is working because of you rather don't get which one excel.exe is yours.

Resources