I have an Excel add-in published that allows customers to retrieve/send data from a Spreadsheet to my application. The first add-in screen asks the users to provide valid credentials (of my app) before proceeding. These credentials are a user name and an API Key. Some customers are complaining they need to enter the 40-digit long API key every time they want to use the add-in.
My question is: is there a way to safely store these credentials within the add-in? I can't store them on the spreadsheet, since the users just use a temporary one to retrieve/edit the data - and just close Excel after doing it.
It's not really unusual to require a passcode of some kind every time a user starts another session with an app. Facebook and most other online services work this way. Is it the sheer length of the key that bothers your users?
At any rate, if the workbook isn't being preserved, then you can't store it in the document and the add-in has no way to store it locally because web apps don't have access to the file system (except for cookies).
You could store the key in a cookie. Another possibility is LocalStorage.
I've built something like this and used the PERSONAL.XLSB to address this. Important to note that this is not very secure and anyone who had access to person's laptop/account could probably extract it once saved.
Const namedReference = "userAPI"
Sub storeOnLocalMachine()
Dim theAPIKEY As String, wkbk As Workbook
theAPIKEY = "sample123key" 'maybe have them enter once as inputbox
For Each wkbk In Application.Workbooks
If wkbk.Name = "PERSONAL.XLSB" Then Exit For
Next wkbk
If wkbk Is Nothing Then
'figure out how to open silentely open for user
End If
wkbk.Names.Add Name:=namedReference, RefersToLocal:="=""" & theAPIKEY & """", Visible:=False
wkbk.Save
End Sub
Function retrieveTheAPI() As String
Dim wkbk As Workbook
For Each wkbk In Application.Workbooks
If wkbk.Name = "PERSONAL.XLSB" Then Exit For
Next wkbk
retrieveTheAPI = Evaluate(wkbk.Names(namedReference).RefersTo)
End Function
Related
I have made an userform excel system to SignUp or Login users to a kind of quizz. All this files are available on sharepoint of my company to be run. When someone SignUp, all information he had written in the userform are sent to an external workbook that gathered all users inscriptions. All works find individually, but when two people or more are submitting their signup data barely at the same time, their is a conflict in the external workbook because the users overwrite what the earliest one as putted into the cells while I asked to write in the next empty row. I think this is because, the external workbook has not the time to update on SharePoint what the very previous user as written.
To avoid this trubble, I have decide the CheckOut if an other user is already writting in the external workbook. However, I have a kind of similar issue with the CheckOut VBA code lines I used below. When the two users send their data barely at the same time, they come togather in the "CanCheckOut", then one of them succed to checkout the workbook, but the other one is bring to a message box who say "The workbook is already checkout. Would you like to open the file as readOnly or cancel file opening". My wish is that that only one of the users enter in the "If CanCheckOut Then", or to close automaticaly in VBA the messagebox for the second user trying to checkin. I don't know if I can avoid the two users to come inside this "if" because it could a standard lag of syncronisation due to SharePoint. So I tryed the second solution that is to close automaticaly in VBA the messagebox for the second user trying to checkin, however it seems that "Application.DisplayAlerts = False" or "On Error GoTo ErrorUser" don't work so I am kind of stuck and looking for your help and your experience in VBA with multi-users configurations on SharePoint to solve this issue.
Sub UseCheckOut()
Dim App As New Excel.Application
Dim wBook As Excel.Workbook
Dim FileNameUser As String
FileNameUser = ThisWorkbook.Path & "/Support/UsersData.xlsm"
If Workbooks.CanCheckOut(FileNameUser) = True Then
Workbooks.CheckOut FileNameUser ' When two users run the code simultaneously they
' both come to this line
Set wBook = App.Workbooks.Open(FileNameUser)
Else
MsgBox "Someone else signup to the quizz. Please, submit you registration again"
Exit Sub
End If
End Sub
I have an excel file stored in Sharepoint (which is also accessible with Microsoft Teams), with the path: https://organization.sharepoint.com/PathOfFile/myFile.xlsx
The file can be edited by multiple at the same time with the co-authoring feature in Sharepoint.
I want to use another excel file stored locally in my computer to access and modify the one in Sharepoint. This local file has a button with this VBA code in it:
Sub UpdateSP():
f_name = "https://organization.sharepoint.com/PathOfFile/myFile.xlsx"
Workbooks.Open f_name
Workbooks("myFile.xlsx").Activate
ActiveWorkbook.Sheets("sheet1").Activate
Range("A" & Rows.Count).End(xlUp).Offset(1).Select
ActiveCell.Value = 9999
ActiveCell.Offset(0, 1).Select
ActiveCell.Value = 0000
ActiveWorkbook.Close SaveChanges:=True
End Sub
In principle it works, the file in Sharepoint is modified. But things go wrong if there's someone editing the file while I run the code, then two versions of the file seem to be created, one for the online-live editing, and the one for my code.
If this happens, the online version of the file won't show the changes made by the code, and whenever the file is opened with the excel app, a pop-up will show asking which version of the file should be kept, losing all the changes done in the disposed version.
I have tried to use the CanCheckOut and CheckOut methods, but CanCheckOut always returns False for whatever reason (there are some questions here with the same issue but I havent been able to find a solution).
Can someone suggest a solution to this issue? Thanks.
I'm not 100% sure it will work on SharePoint, but in theory, ADODB is a library for VBA that has the syntax of objects to use Microsoft's Jet Engine so you can open files AdLockOptimistic---ally. ((look up lock types in ADO.net))
This works on a file directory basis, so if the DB being modified is open, it will handle the update.
Instead of using Excel's Application to open the file, you would establish an ADO connection, and then specify the type of Lock in order to access the Excel's sheets and tables inside it.
This works for shared / network drives, so I'm guessing since SharePoint can be mapped as a file explorer drive, then ADO should work and is worth a try.
Here's a basic example to get you started: ADO question
Try enabling the autosave after activating the workbook.
To do so, add this line:
ActiveWorkbook.AutoSaveOn = True
after the Workbooks("myFile.xlsx").Activate line.
I have had similar issues with collaborative files and making sure the autosave is enabled has solved it.
To be able to incorporate changes that way your code must run inside a coauthoring context.
Instead of opening the document from another doc or local copy, the code must be running inside the same document being opened from the same source URL (Sharepoint or OneDrive), that way the add-in or macro can make changes that Excel itself will handle on a coauthoring context.
I recommend taking a look at Coauthoring in Excel add-ins of the Office Dev Center, including the linked articles inside (specifically "coauthoring", redirecting to the support center, and "About coauthoring in Excel (VBA)" at the bottom with more samples).
CanCheckOut will always return false if a workbook is open. Thus you must check before you touch it. The CheckOut command will not open the file so we must also have an open statement after CheckOut.
Using your example it would look like this;
Option Explicit
Public Sub UpdateSP()
Dim fName As String
fName = "https://organization.sharepoint.com/PathOfFile/myFile.xlsx"
If Workbooks.CanCheckOut(fName) Then
Workbooks.CheckOut fName
Dim myFile As Workbook
Set myFile = Workbooks.Open(fName)
Dim mySheet As Worksheet
Set mySheet = myFile.Sheets("Sheet1")
Dim startRange As Range
Set startRange = mySheet.Range("A" & mySheet.Rows.Count).End(xlUp).Offset(1)
startRange.Value = 9999
startRange.Offset(0, 1).Value = 0
myFile.Close SaveChanges:=True
Else
MsgBox fName & " can't be checked out at this time.", vbInformation
End If
End Sub
I have a Workbook that, when opened, I would like to pull copied information from another workbook located on a shared drive on a remote server. This remote file, though, is password protected. When these files are on the same computer, it works fine. When tested over the network, though, it prompts me for the password almost as if it were a loop glitch. That is to say, when it prompts me, even if I cancel, it will still use the password given from the code and complete.
Private Sub Workbook_Open()
Application.DisplayAlerts = False
Set DATES = Workbooks.Open("Shareddrivepath\test.xlsx", password:="test")
Range("G2:H27").Copy
ThisWorkbook.Sheets(1).Range("C2:D27").PasteSpecial
Range("J2:K27").Copy
ThisWorkbook.Sheets(1).Range("G2:H27").PasteSpecial
Range("A1:E21").Copy
ThisWorkbook.Sheets("SET").Range("A1:E21").PasteSpecial
ThisWorkbook.Sheets(1).Activate
DATES.Close
Application.DisplayAlerts = True
End Sub
Is there something I am missing that can load that password immediately or will it have to be linked to another sub called upon when opened? I have also tried just merely linking the cells and it still requires/requests password on start.
I believe I found a way around this:
http://office.microsoft.com/en-us/excel-help/create-and-manage-links-to-other-workbooks-HA001054812.aspx
Linking to password protected workbooks
Assigning a protection password to a source worksheet or workbook does not prevent users of linking workbooks who don't know the password from updating the links. If you want users to have to enter a password to update links, save the source workbook file with a password to open (click Save As on the File menu, click General Options on the Tools menu).
Set DATES = Workbooks.Open _
("Shareddrivepath\test.xlsx", WriteResPassword:="test")
I created an Excel spreadsheet that my boss wants to put on the company's internal website. The spreadsheet contains some seldom-used, esoteric, but handy functions that only certain employees within the company will find really useful.
The problem is that I don't know who the future users are, and my boss wants me to identify who uses my spreadsheet.
He asked that I password-protect the Excel spreadsheet in such a way that one password does NOT unlock all of the copies that people can download from the site. For example, I can't just make the password "stackoverflow" because once a user legitimately gets the password from me, and is shared with other people, it can be used by anyone within the company to unlock all subsequently downloaded spreadsheets. I will never be able to ascertain who is using the spreadsheet. Also, I cannot modify the website, so I hope to achieve this tracking of users through Excel and email.
Is there a way to have Excel randomly generate a string, which the user emails me, and then I respond with the appropriate password that will unlock the file (based off the generated string)? This requires the user to check in with me before using the spreadsheet (the ideal situation).
Is such an arrangement possible in Excel 2010 Professional Plus?
I think password protection in the method you describe is unnecessarily cumbersome if it is even doable at all.
He asked that I password-protect the Excel spreadsheet in such a way that one password does NOT unlock all of the copies that people can download from the site.
I can't imagine how this might be possible using only Excel. Maybe an Add-in could do this, but at the file level, I don't think it could be done, at least not easily.
I will never be able to ascertain who is using the spreadsheet.
It sounds like this is the really important bit. You are not using the password as a security measure, only as a gatekeeping method to determine who is using the file. This can be automated in other ways, easiest of which would be to use certain Environment variables, e.g.:
MsgBox Environ("username") will display a message box with the current user's name.
You can assign Environ("username") to a string variable, and then you could for example automate Outlook to send you an email that "John Doe has opened the file", or something to that effect. If you want to avoid getting an email every time, you could do some tweaking with a Named Range variable in the Excel file, so that the macro will only send the email once, etc.
Alternatively, you may be able to write a log/txt file to a shared network location (of course, assuming the user is connected to the network) instead of sending emails.
Update
Here is some example code that I've taken from places around the web, it will send an email from the user. You will have to modify the sendTo lines to use your email address as recipient, etc.
Put this in the Workbook's code module, it should email you any time they open this file:
Option Explicit
Private Sub Workbook_Open()
' This example uses late-binding instead of requiring an add'l reference to the
' MS Outlook 14.0 Object Library.
Dim oApp As Object 'Outlook.Application 'Object
Dim ns As Object 'Namespace
Dim fldr As Object 'MAPIFolder
Dim mItem As Object 'Outlook.MailItem
Dim sendTo As Object 'Outlook.Recipient
Dim bOutlookFound As Boolean
On Error Resume Next
Set oApp = GetObject(, "Outlook.Application")
bOutlookFound = Err.Number = 0
On Error GoTo 0
If Not bOutlookFound Then Set oApp = CreateObject("Outlook.Application") 'New Outlook.Application
'# Set the namespace and folder so you can add recipients
Set ns = oApp.GetNamespace("MAPI")
Set fldr = ns.GetDefaultFolder(6) 'olFolderInbox
'# create an outlook MailItem:
Set mItem = oApp.CreateItem(0) 'olMailItem
'# assign a recipient
Set sendTo = mItem.Recipients.Add("YourName#Company.Com")
sendTo.Type = 1 'To olTo
'# assign another recipient
Set sendTo = mItem.Recipients.Add("YourManager#Company.Com")
sendTo.Type = 1
'# Validate the recipients (not necessary if you qualify valid email addresses:
For Each sendTo In mItem.Recipients
sendTo.Resolve
Next
mItem.Subject = "A user has opened the Excel file"
mItem.Body = "This is an automated message to inform you that " & _
Environ("username") & " has downloaded and is using the file."
mItem.Save
mItem.Send
'If outlook was not already open, then quit
If Not bOutlookFound Then oApp.Quit
Set oApp = Nothing
End Sub
Expanding on David's answer you could also use a macro that auto-runs when the sheet is opened and it could write Environ("username") to the next available row in a hidden worksheet. I've used Environ("username") before and it is quite useful, quick, and easy.
This sub on any worksheet will automatically run (IIRC):
Private Sub Auto_Open()
End Sub
You could also put a time stamp in the next column to show when the spreadsheet was used...
I have an automated process that is mostly run in Access. But, in the middle, it puts some data in Excel to scrub it into the correct form (it's much faster than doing it in Access), and at the end it opens another Excel file and puts data from some Access queries into the Excel file. For these connections from Excel to Access, I accomplished them all by going into Excel and doing Data --> Get External Data --> From Access, then selecting the Access file and the query I want to get the data from and tell Excel to make it into a Table.
So, I do that one time and then I want to be able to run this automated process that simply refreshes the data. To do this refreshing of the data, I do a line like:
Worksheets("Data").Range("A1").ListObject.QueryTable.Refresh _
BackgroundQuery:=False
The problem is, half the time (and I can't figure out why it does it one time and not another), it says "Do you want to connect to path\filename?" Of course I do, how else would the table refresh? So, this stops the automation. Even if I click Yes, I still can't get it to continue on. If I click Yes, it opens up the Data Link Properties. After I click OK for that, it opens a window titled "Please Enter Microsoft Office Access Database Engine OLE DB Initialization Information". It has info in it, including the path and name of the data source I want to access, but if I click OK, it says, sorry that didn't work, would you like instead to connect to (and then it lists the exact same path and file name it just said didn't work). It repeats the steps I just mentioned, and after that it errors out.
In case it matters, here is the (basic idea) code I use to connect to Excel from Access:
Public Sub ExportToExcel()
Dim ObjXLApp As Object
Dim ObjXLBook As Object
Dim ExcelFilePath As String
ExcelFilePath = CurrentProject.Path & "\"
Set ObjXLApp = CreateObject("Excel.Application")
Set ObjXLBook = ObjXLApp.Workbooks.Open(ExcelFilePath & "filename.xlsm")
ObjXLApp.Visible = True
' Runs the "DataSetUp" macro in the Excel file.
ObjXLApp.Run ("DataSetUp")
' The DataSetUp macro saves the Excel file
' Quit Excel
ObjXLApp.Quit
' Free the memory
Set ObjXLBook = Nothing
Set ObjXLApp = Nothing
End Sub
I have no idea how to fix this! Any help would be much appreciated.
This may be happening because your access database is still open from which the new excel file needs to input data back into. The database cannot be open when this takes place, hense the reason why excel errors and asks for another location to connect to.
So, I would work on generating the needed scrubbing via vba inside access probably.