Excel File Password Protection with Open XML SDK - excel

I am using Open XML SDK for creating excel files.
I want to protect them with a password.
Do you know anyway to protect excel file with a password by using Open XML SDK?
I know "com" object way to protect them however, it is not suitable for my application. I need to protect file by using Open XML SDK or another way.

Creating an excel password for protecting workbook or worksheet is possible by open xml.
Following code samples are suggestions of Vincent (http://spreadsheetlight.com/about/) (https://stackoverflow.com/users/12984/vincent-tan) (again I thank him a lot :)
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docname,true))
{
foreach (var worksheet in spreadSheet.WorkbookPart.WorksheetParts)
{
worksheet.Worksheet.Append(new SheetProtection(){ Password = “CC”});
// add this in case it still doesn’t work. This makes sure the data is saved.
//worksheet.Worksheet.Save();
}
}
If you have a chart or something then
Following code samples are suggestions of Vincent (http://spreadsheetlight.com/about/) (https://stackoverflow.com/users/12984/vincent-tan) (again I thank him a lot :)
bool bFound;
OpenXmlElement oxe;
SheetProtection prot;
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open("OtoPark.xlsx", true))
{
foreach (var worksheet in spreadSheet.WorkbookPart.WorksheetParts)
{
prot = new SheetProtection();
prot.Password = "CC";
// these are the "default" Excel settings when you do a normal protect
prot.Sheet = true;
prot.Objects = true;
prot.Scenarios = true;
// Open up Excel and do a password protect yourself and use the
// Productivity Tool to see the property values of the resulting Excel file.
// Consider not using the Password property and use:
//prot.AlgorithmName = "SHA-512";
//prot.HashValue = "somehashvaluebythealgorithm";
//prot.SaltValue = "somesalt";
//prot.SpinCount = 100000;
bFound = false;
oxe = worksheet.Worksheet.FirstChild;
foreach (var child in worksheet.Worksheet.ChildElements)
{
// start with SheetData because it's a required child element
if (child is SheetData || child is SheetCalculationProperties)
{
oxe = child;
bFound = true;
}
}
if (bFound)
{
worksheet.Worksheet.InsertAfter(prot, oxe);
}
else
{
worksheet.Worksheet.PrependChild(prot);
}
worksheet.Worksheet.Save();
}
}
These methods makes a protection that any user cant change the data accidentally. However, if you do not want any user that don't know password to see the data then you can use following library:
http://dotnetzip.codeplex.com/
You have a password protected zipped file that contains your excel.xlsx file by using the dotnetzip library.
An example:
public void RNCreateZipFile(string ExcelDocName,string PassWord, string ZipDocName)
{
// create a zip
using (var zip = new ZipFile())
{
zip.Password = PassWord;
zip.AddFile(ExcelDocName, "");
zip.Save(ZipDocName);
}
}

As #Birol mentioned that it will only protect (or rather lock) WB or WS but user can still open file in read only mode. Using dotnetzip package, it will password protect the files inside zip but it will allow the user to see the file second time without asking for password as it is the default windows behavior. You can use free Spire.XLS which will prompt you to enter password to open it any time. It has some limitations though. You can refer - https://www.nuget.org/packages/FreeSpire.XLS/

Related

I have created EXCEL VSTO template with 2016 excel . I need to know how could I get UserName and Password of logged in User in the Excel Template

I have created Excel 2016 VSTO template.
Open Visual studio and select the EXCEL VSTO TEMPLATE
Then I select the .xltx template
Select the .xltx Image
The project is created in the specified location with xltx Template.
VSTO excel template Project location
Now if I open the template from the project location and go to the option.
you will see in the UserName place its getting the Default machine UserName
and its being Retrieved in the code. But I don't want it.
Excel option General
Now we will see that there is one more User is there that is logged in User.
Logged In User need to retrieved in code
The code I am using to Retrieve the Logged In User.
Code for retrieving the logged in User
But in this code I am getting the user from Excel General Option area
but I want it from the Logged In Area.
Please tell me how to do it.
Thanks.
You can use the Environment.UserName to get the user name of the current user.
I don't believe you can get the password.
The Excel object model (nor VSTO) doesn't provide any property or method for that unfortunately.
It is not possible to get the Windows session password (string), only the user name using:
Environment.UserName
However, you can validate a password against the password of the Windows username using a routine like this:
public bool CheckUser(string userName, string password)
{
string domainName = System.Environment.UserDomainName;
string domainUserName = System.Environment.UserName;
bool answer = false;
PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName, domainUserName, ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing);
//PrincipalContext pc = new PrincipalContext(ContextType.Domain, domainName, domainUserName,ContextOptions.SecureSocketLayer | ContextOptions.Negotiate | ContextOptions.Signing | ContextOptions.Sealing);
try
{
bool isValid = pc.ValidateCredentials(userName.ToUpper(), password);
if (isValid)
{
answer = true;
}
else
{
pc.Dispose();
answer = false;
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
return answer;
}

Embedding Excel Add-Ins with OpenXml

My team is working on an Office 365 add-in for Excel, and as part of the project, we’re creating Excel documents through the GraphAPI with the end goal of having the add-in already setup for the document. We’re using the .NET OpenXml library to create the document before copying it through the GraphAPI.
We haven’t been able to find many resources for how to setup an add-in through OpenXml and have not been able to get anything working. The last thing we tried was copying the example we found here, but we couldn’t get it working. Does anyone know how to setup add-ins using the OpenXml library?
Note: the add-in is already in the Office Add-Ins store, and we have information like the AppSource ID.
Thank you!
We're actually about to publish a new sample around this scenario. The sample shows how to create an Excel document using OOXML, embed your add-in, and then upload the file to OneDrive. It also creates a Team chat that links to the file.
You can try out the sample here: Open data from your web site in a spreadsheet in Microsoft Teams
Or give us feedback on the PR: https://github.com/OfficeDev/PnP-OfficeAddins/pull/197
To answer your question about how to embed the add-in, you need to create a web extension section. I've copied the relevant code here. Note this is the same code from the Office-OOXML-EmbedAddin sample you already looked at. We reused it for the new sample. You can change the CUSTOM MODIFICATION section to provide any custom properties you want to your add-in when it opens.
// Embeds the add-in into a file of the specified type.
private void EmbedAddin(SpreadsheetDocument spreadsheet)
{
spreadsheet.DeletePart(spreadsheet.WebExTaskpanesPart);
var webExTaskpanesPart = spreadsheet.AddWebExTaskpanesPart();
CreateWebExTaskpanesPart(webExTaskpanesPart);
}
// Adds child parts and generates content of the specified part.
private void CreateWebExTaskpanesPart(WebExTaskpanesPart part)
{
WebExtensionPart webExtensionPart1 = part.AddNewPart<WebExtensionPart>("rId1");
GenerateWebExtensionPart1Content(webExtensionPart1);
GeneratePartContent(part);
}
// Generates content of webExtensionPart1.
private void GenerateWebExtensionPart1Content(WebExtensionPart webExtensionPart1)
{
// Add web extension containg Id for Script Lab add-in
We.WebExtension webExtension1 = new We.WebExtension() { Id = "{635BF0CD-42CC-4174-B8D2-6D375C9A759E}" };
webExtension1.AddNamespaceDeclaration("we", "http://schemas.microsoft.com/office/webextensions/webextension/2010/11");
// Add store information for Script Lab add-in
We.WebExtensionStoreReference webExtensionStoreReference1 = new We.WebExtensionStoreReference() { Id = "wa104380862", Version = "1.1.0.0", Store = "en-US", StoreType = "OMEX" };
We.WebExtensionReferenceList webExtensionReferenceList1 = new We.WebExtensionReferenceList();
We.WebExtensionPropertyBag webExtensionPropertyBag1 = new We.WebExtensionPropertyBag();
// Add the property that makes the taskpane visible.
We.WebExtensionProperty webExtensionProperty1 = new We.WebExtensionProperty() { Name = "Office.AutoShowTaskpaneWithDocument", Value = "true" };
webExtensionPropertyBag1.Append(webExtensionProperty1);
// CUSTOM MODIFICATION BEGIN
// Add the property that specifies the snippet to import.
string snippetToImportValue = string.Format("{{\"type\":\"gist\",\"id\":\"{0}\"}}", "{72189570-AE11-4207-9DEE-C8BDE4B83188}");
We.WebExtensionProperty webExtensionProperty2 = new We.WebExtensionProperty() { Name = "SnippetToImport", Value = snippetToImportValue };
webExtensionPropertyBag1.Append(webExtensionProperty2);
// CUSTOM MODIFICATION END
We.WebExtensionBindingList webExtensionBindingList1 = new We.WebExtensionBindingList();
We.Snapshot snapshot1 = new We.Snapshot();
snapshot1.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
webExtension1.Append(webExtensionStoreReference1);
webExtension1.Append(webExtensionReferenceList1);
webExtension1.Append(webExtensionPropertyBag1);
webExtension1.Append(webExtensionBindingList1);
webExtension1.Append(snapshot1);
webExtensionPart1.WebExtension = webExtension1;
}
// Generates content of part.
private void GeneratePartContent(WebExTaskpanesPart part)
{
Wetp.Taskpanes taskpanes1 = new Wetp.Taskpanes();
taskpanes1.AddNamespaceDeclaration("wetp", "http://schemas.microsoft.com/office/webextensions/taskpanes/2010/11");
Wetp.WebExtensionTaskpane webExtensionTaskpane1 = new Wetp.WebExtensionTaskpane() { DockState = "right", Visibility = true, Width = 350D, Row = (UInt32Value)4U };
Wetp.WebExtensionPartReference webExtensionPartReference1 = new Wetp.WebExtensionPartReference() { Id = "rId1" };
webExtensionPartReference1.AddNamespaceDeclaration("r", "http://schemas.openxmlformats.org/officeDocument/2006/relationships");
webExtensionTaskpane1.Append(webExtensionPartReference1);
taskpanes1.Append(webExtensionTaskpane1);
part.Taskpanes = taskpanes1;
}

Read Excel 2007 Workbook Custom Properties without opening or running macros

I'm writing a program (in C#) that will be able to replace a local workbook from a server if the server version is higher, and then open it. To this end I'm trying to read Custom Property "Revision Number" of both local and server copies. The issue is that the workbook contains macros that launch on open, and I don't want to run any macros just to check the Revision Code. So is there a way to read the Revision Number of an excel 2007 xlsm file without actually opening it? If not, is there a way to open a workbook in C# and not execute it's macros?
Actually I tried the tkacprow's suggestion to use OpenXML and it worked. It just took me a while to produce a working code and I just got it working yesterday. Fratyx, your tip also looks interesting - i'll keep that in mind. Here's a working code:
public string GetVersion(string fileName)
{
string propertyValue = string.Empty;
try
{
using (var wb = SpreadsheetDocument.Open(fileName, false))
{
const string corePropertiesSchema = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
const string dcPropertiesSchema = "http://purl.org/dc/elements/1.1/";
const string dcTermsPropertiesSchema = "http://purl.org/dc/terms/";
// Get the core properties part (core.xml).
CoreFilePropertiesPart xCoreFilePropertiesPart;
xCoreFilePropertiesPart = wb.CoreFilePropertiesPart;
// Manage namespaces to perform XML XPath queries.
NameTable nt = new NameTable();
XmlNamespaceManager nsManager = new XmlNamespaceManager(nt);
nsManager.AddNamespace("cp", corePropertiesSchema);
nsManager.AddNamespace("dc", dcPropertiesSchema);
nsManager.AddNamespace("dcterms", dcTermsPropertiesSchema);
// Get the properties from the package.
XmlDocument xdoc = new XmlDocument(nt);
// Load the XML in the part into an XmlDocument instance.
xdoc.Load(xCoreFilePropertiesPart.GetStream());
string searchString = string.Format("//cp:coreProperties/{0}", "cp:version");
XmlNode xNode = xdoc.SelectSingleNode(searchString, nsManager);
if (!(xNode == null))
{
//Console.WriteLine(" version is " + xNode.InnerText);
propertyValue = xNode.InnerText;
}
}
}
catch (OpenXmlPackageException e)
{
throw new ApplicationException(String.Format("Incorrect Format detected in a file: {0}" , fileName),e.GetBaseException());
}
return propertyValue;
}

How to read data in Excel in Symfony2 liuggio Excel

Hi I am new to Symfony2 and I need to upload Excel file to MYSQL database?
Can anyone send me a example of how to do it?
Thanks you
Raki
Start by adding: "CodePlex/PHPExcel": "1.7.7", to your composer.json file and updating.
Add a class to sit between the PHPExcel stuff and your code. Something like:
namespace Cerad\ArbiterBundle\Format;
class Excel
{
protected function createReaderForFile($fileName,$readDataOnly = true)
{
// Most common case
$reader = new \PHPExcel_Reader_Excel5();
$reader->setReadDataOnly($readDataOnly);
if ($reader->canRead($fileName)) return $reader;
// Make sure have zip archive
if (class_exists('ZipArchive'))
{
$reader = new \PHPExcel_Reader_Excel2007();
$reader->setReadDataOnly($readDataOnly);
if ($reader->canRead($fileName)) return $reader;
}
// Note that csv does not actually check for a csv file
$reader = new \PHPExcel_Reader_CSV();
if ($reader->canRead($fileName)) return $reader;
throw new Exception("No Reader found for $fileName");
}
public function load($fileName, $readDataOnly = true)
{
$reader = $this->createReaderForFile($fileName,$readDataOnly);
return $reader->load($fileName);
}
}
Now in your code you would have something like:
$excel = new Excel();
$reader = $excel->load('SomeFileName.xls');
$ws = $reader->getSheet(0);
$rows = $ws->toArray();
And process away.
the example of Cerad is an option but it doesn't use that bundle and neither work with mysql,
that bundle is a simple dependency that expose services,
If you have to store data from excel to mysql,
you need first do upload file somewhere, then
read the file with the service,
$excelObj = $this->get('xls.load_xls5')->load($filename);
and then you have to read the documentation of PHPExcel
Hope it helps a little

Programmatically Edit Infopath Form Fields?

I have a form library in my share point site. Programmatically I need to fill some fields. Can I do that? If any one know please provide me some sample code. First I need to retrieve the infopath document and then I need to fill the fields.
What axel_c posted is pretty dang close. Here's some cleaned up and verified working code...
public static void ChangeFields()
{
//Open SharePoint site
using (SPSite site = new SPSite("http://<SharePoint_Site_URL>"))
{
using (SPWeb web = site.OpenWeb())
{
//Get handle for forms library
SPList formsLib = web.Lists["FormsLib"];
if (formsLib != null)
{
foreach (SPListItem item in formsLib.Items)
{
XmlDocument xml = new XmlDocument();
//Open XML file and load it into XML document
using (Stream s = item.File.OpenBinaryStream())
{
xml.Load(s);
}
//Do your stuff with xml here. This is just an example of setting a boolean field to false.
XmlNodeList nodes = xml.GetElementsByTagName("my:SomeBooleanField");
foreach (XmlNode node in nodes)
{
node.InnerText = "0";
}
//Get binary data for new XML
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xml.OuterXml);
using (MemoryStream ms = new MemoryStream(xmlData))
{
//Write data to SharePoint XML file
item.File.SaveBinary(ms);
}
}
}
}
}
}
The Infopath document is just a regular XML file, the structure of which matches the data sources you defined in the Infopath form.
You just need to access the file via the SharePoint object model, modify it using standard methods (XmlDocument API) and then write it back to the SharePoint list. You must be careful to preserve the structure and insert valid data or you won't be able to open the form using Infopath.
You should really check out a book on SharePoint if you plan to do any serious development. Infopath is also a minefield.
Object model usage examples: here, here and here. The ridiculously incomplete MSDN reference documentation is here.
EDIT: here is some example code. I haven't done SharePoint for a while so I'm not sure this is 100% correct, but it should give you enough to get started:
// Open SharePoint site
using (SPSite site = new SPSite("http://<SharePoint_Site_URL>"))
{
using (SPWeb web = site.OpenWeb())
{
// Get handle for forms library
SPList formsLib = web.Lists["FormsLib"];
if (formsLib != null)
{
SPListItem itm = formsLib.Items["myform.xml"];
// Open xml and load it into XML document
using (Stream s = itm.File.OpenBinary ())
{
MemoryStream ms;
byte[] xmlData;
XmlDocument xml = new XmlDocument ();
xml.Load (s);
s.Close ();
// Do your stuff with xml here ...
// Get binary data for new XML
xmlData = System.Text.Encoding.UTF8.GetBytes (xml.DocumentElement.OuterXml);
ms = new MemoryStream (xmlData);
// Write data to sharepoint item
itm.File.SaveBinary (ms);
ms.Close ();
itm.Update ();
}
}
web.Close();
}
site.Close();
}
It depends a bit on your available tool set, skills and exact requirements.
There are 2 main ways of pre populating data inside an InfoPath form.
Export the relevant fields as part of the form's publishing process. The fields will then become columns on the Document / Forms library from where you can manipulate them either manually, via a Workflow or wherever your custom code is located.
Directly manipulate the form using code similar to what was provided by Axel_c previously. The big question here is: what will trigger this code? An event receiver on the Document Library, a SharePoint Designer Workflow, a Visual Studio workflow etc?
If you are trying to do this from a SharePoint Designer workflow then have a look at the Workflow Power Pack for SharePoint. It allows C# and VB code to be embedded directly into the workflow without the need for complex Visual Studio development. An example of how to query InfoPath data from a workflow can be found here. If you have some development skills you should be able to amend it to suit your needs.
I also recommend the site www.infopathdev.com, they have excellent and active forums. You will almost certainly find an answer to your question there.
Thanks for the sample code, #axel_c and #Jeff Burt
Below is just the same code from Jeff Burt modified for a file in Document set which I needed. If you don't already have the Document Set reference, you can check out this site on how to grab one:
http://howtosharepoint.blogspot.com/2010/12/programmatically-create-document-set.html
Also, the codes will open the .xml version of the infopath form and not the .xsn template version which you might run into.
Thanks again everyone...
private void ChangeFields(DocumentSet docSet)
{
string extension = "";
SPFolder documentsetFolder = docSet.Folder;
foreach (SPFile file in documentsetFolder.Files)
{
extension = Path.GetExtension(file.Name);
if (extension != ".xml") //check if it's a valid xml file
return;
XmlDocument xml = new XmlDocument();
//Open XML file and load it into XML document, needs to be .xml file not .xsn
using (Stream s = file.OpenBinaryStream())
{
xml.Load(s);
}
//Do your stuff with xml here. This is just an example of setting a boolean field to false.
XmlNodeList nodes = xml.GetElementsByTagName("my:fieldtagname");
foreach (XmlNode node in nodes)
{
node.InnerText = "xyz";
}
//Get binary data for new XML
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xml.OuterXml);
using (MemoryStream ms = new MemoryStream(xmlData))
{
//Write data to SharePoint XML file
file.SaveBinary(ms);
}
}
}
I had this issue and resolved it with help from Jeff Burt / Axel_c's posts.
I was trying to use the XMLDocument.Save([stream]) and SPItem.File.SaveBinary([stream]) methods to write an updated InfoPath XML file back to a SharePoint library. It appears that XMLDocument.Save([stream]) writes the file back to SharePoint with the wrong encoding, regardless of what it says in the XML declaration.
When trying to open the updated InfoPath form I kept getting the error "a calculation in the form has not been completed..."
I've written these two functions to get and update and InfoPath form. Just manipulate the XML returned from ReadSPFiletoXMLdocument() in the usual way and send it back to your server using WriteXMLtoSPFile().
private System.Xml.XmlDocument ReadSPFiletoXMLdocument(SPListItem item)
{
//get SharePoint file XML
System.Xml.XmlDocument xDoc = new System.Xml.XmlDocument();
try
{
using (System.IO.Stream xmlStream = item.File.OpenBinaryStream())
{
xDoc.Load(xmlStream);
}
}
catch (Exception ex)
{
//put your own error handling here
}
return xDoc;
}
private void WriteXMLtoSPFile(SPListItem item, XmlDocument xDoc)
{
byte[] xmlData = System.Text.Encoding.UTF8.GetBytes(xDoc.OuterXml);
try
{
using (System.IO.MemoryStream outStream = new System.IO.MemoryStream(xmlData))
{
item.File.SaveBinary(outStream);
}
}
catch (Exception ex)
{
//put your own error handling here
}
}

Resources