How to protect Excel workbook using VBA? - excel

With a trigger like a check box I want to protect my work book. I tried Excel 2003:
thisworkbook.protect("password",true,true)
thisworkbook.unprotect("password")
It's not working. Any suggestions?

I agree with #Richard Morgan ... what you are doing should be working, so more information may be needed.
Microsoft has some suggestions on options to protect your Excel 2003 worksheets.
Here is a little more info ...
From help files (Protect Method):
expression.Protect(Password, Structure, Windows)
expression Required. An expression that returns a Workbook object.
Password Optional Variant. A string that specifies a case-sensitive password for the worksheet or workbook. If this argument is omitted, you can unprotect the worksheet or workbook without using a password. Otherwise, you must specify the password to unprotect the worksheet or workbook. If you forget the password, you cannot unprotect the worksheet or workbook. It's a good idea to keep a list of your passwords and their corresponding document names in a safe place.
Structure Optional Variant. True to protect the structure of the workbook (the relative position of the sheets). The default value is False.
Windows Optional Variant. True to protect the workbook windows. If this argument is omitted, the windows aren’t protected.
ActiveWorkbook.Protect Password:="password", Structure:=True, Windows:=True
If you want to work at the worksheet level, I used something similar years ago when I needed to protect/unprotect:
Sub ProtectSheet()
ActiveSheet.Protect "password", True, True
End Sub
Sub UnProtectSheet()
ActiveSheet.Unprotect "password"
End Sub
Sub protectAll()
Dim myCount
Dim i
myCount = Application.Sheets.Count
Sheets(1).Select
For i = 1 To myCount
ActiveSheet.Protect "password", true, true
If i = myCount Then
End
End If
ActiveSheet.Next.Select
Next i
End Sub

in your sample code you must remove the brackets, because it's not a functional assignment; also for documentary reasons I would suggest you use the := notation (see code sample below)
Application.Thisworkbook refers to the book containing the VBA code, not necessarily the book containing the data, so be cautious.
Express the sheet you're working on as a sheet object and pass it, together with a logical variable to the following sub:
Sub SetProtectionMode(MySheet As Worksheet, ProtectionMode As Boolean)
If ProtectionMode Then
MySheet.Protect DrawingObjects:=True, Contents:=True, _
AllowSorting:=True, AllowFiltering:=True
Else
MySheet.Unprotect
End If
End Sub
Within the .Protect method you can define what you want to allow/disallow. This code block will switch protection on/off - without password in this example, you can add it as a parameter or hardcoded within the Sub. Anyway somewhere the PW will be hardcoded. If you don't want this, just call the Protection Dialog window and let the user decide what to do:
Application.Dialogs(xlDialogProtectDocument).Show
Hope that helps
Good luck - MikeD

To lock whole workbook from opening, Thisworkbook.password option can be used in VBA.
If you want to Protect Worksheets, then you have to first Lock the cells with option Thisworkbook.sheets.cells.locked = True and then use the option Thisworkbook.sheets.protect password:="pwd".
Primarily search for these keywords: Thisworkbook.password or Thisworkbook.Sheets.Cells.Locked

Related

Is there a VBA process that can check for cell property change

I have a spreadsheet where all entry must be entered and edited via vba Userform. I have a process that checks if the user types directly in a cell and tells them that's a no-no and undoes their typing. This trap still allows the user to change the attributes of the cell, like color and text bolding. Is there a way to trap for that as well as direct typing in the cell?
I use the Worksheet_Change(ByVal Target As Range) to trap typing as below. The "updateIND" is a value (1 or 0) that toggles this function on or off:
Private Sub Worksheet_Change(ByVal Target As Range)
If ThisWorkbook.Sheets("Updates").Range("updateIND") = 0 Then
With Application
.EnableEvents = False
.Undo
.EnableEvents = True
End With
MsgBox ("No direct typing please")
End If
End Sub
What I would like is for my process to catch any direct change to the cell by the user.
The better solution was as suggested - use Protect for the worksheet. (I enhanced the protect routine to allow Autofilter to work from the headings and to allow the hiding and unhiding of columns.1):
Sub ProtectIt()
Dim myPassword As String
myPassword = "openopen"
Sheets("DataTable").Protect Password:=myPassword, _
DrawingObjects:=True, _
Contents:=True, _
Scenarios:=True, _
AllowSorting:=True, _
AllowFiltering:=True, _
AllowUsingPivotTables:=True, _
AllowFormattingColumns:=True
End Sub
Sub UnprotectIt()
Dim myPassword As String
myPassword = "openopen"
Sheets("DataTable").Unprotect Password:=myPassword
End Sub
There are some many elegant and smart suggestions here. I do understand that some applications need passwords well hidden from the users. In my case, I just want them to follow the data entry rules. If they were to find the password, unprotect the tab, and save it, it wouldn't make any changes to the server copy because saves are only done via the macro, manual saves are discarded with the a replication macro that refreshes the table in the client copy. I still appreciate the comments on passwords if I should need a better method in the future.
The comments have already alluded to the use of protection. In your OP you suggest admonishing the user if they tried to enter anything, but a better approach is to stop them from doing it at all.
From the Microsoft site, the syntax for the Protect command is:
expression.Protect (Password, DrawingObjects, Contents, Scenarios,
UserInterfaceOnly, AllowFormattingCells, AllowFormattingColumns,
AllowFormattingRows, AllowInsertingColumns, AllowInsertingRows,
AllowInsertingHyperlinks, AllowDeletingColumns, AllowDeletingRows,
AllowSorting, AllowFiltering, AllowUsingPivotTables)
I have bolded one of the parameters because this is important to what I am about to suggest.
You completely lock the sheet for any user entry, but you allow macros to make the change. This way, if they tried to edit anything they just can't; but when they use the form, the changes are made.
Private Const UPDATES_PASSWORD As String = "DumbPassword"
Sub ProtectUpdateSheet(Optional private as Boolean)
ThisWorkbook.Sheets("Updates").Protect UPDATES_PASSWORD, True, True, True, _
True, False, False, False, False, False, False, False, False, _
False, False, False)
' The True on the second line sets it to user interface only
Sub UnprotectProtectUpdateSheet(Optional private as Boolean)
ThisWorkbook.Sheets("Updates").Unprotect Password:=UPDATES_PASSWORD
End Sub
This is an important note: When you save an Excel file with protected sheets, it does not save the "interface only" flag! So this has to be reset every time you open the workbook - which is now very simple:
' In ThisWorkbook code module
Private Sub Workbook_Open()
ProtectUpdateSheet
End Sub
With this in place, you can run code whenever you want to change the sheet, but the user can't do anything directly!
Testing note: I have coded the above from memory. but I have used this approach on a work system and it is quite robust and user-safe.
#MathieuGuindon has highlighted the use of Option Private Module. The use of the Optional Boolean above is another way of preventing the routines from showing the "Macros" dialog on the developer's ribbon. This way the routines are still available to other projects but not visible to the users.

How to block cells when file opens?

I have some formulas set via vba to change the value in columns H, J, K, L and N. Those changes are based on G column value and a Submit button, this works fine.
When I do the process to lock them to avoid the user from editing, that says to unlock the whole sheet then lock the ones I need, after this I modify the G column and get:
"Autofit Method of Range Class Failed".
I use it on H column.
This get highlighted:
Sheet1.Range("H11:H50").Rows.EntireRow.AutoFit
You are trying to change protected cells using VBA while the protection is on. You can work around this various ways, however, the most simple solution is something like the following:
Sub Example()
Sheet1.Unprotect "YOURPASSWORD" 'if no password was used, you don't need to include it
Sheet1.Range("H11:H50").Rows.EntireRow.AutoFit
Sheet1.Protect "YOURPASSWORD"
End Sub
Alternative solution:
By using this in the on open procedure of your workbook. VBA can make changes on locked cells, but users can not.
One Caveat: if an error occurs in the code, this will reset and you need to close and reopen the worksheet in order for this to function again
Private Sub Workbook_Open()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Protect UserInterfaceOnly:=True
Next ws
End Sub

VBA Help - Script to run 3 macros via Call function will not run all macros

Apologies if this question is elementary, i'm not great at VBA. I have 3 separate codes that i want to run one after the other at the click of a button. So i have the master code titled UpdateLinks that is supposed to call them. The first 2 (PreSelect & UpdateLinksCode)run the 3rd (PostSelect) doesn't. Individually they all work.
The purpose is to update links to external excel workbooks without having to manually enter the password. That is what the UpdateLinksCode macro is for. However, if the linked source does not require a password the UpdateLinksCode will drop the password in whatever cell was selected before running. Hence the PreSelect & PostSelect - supposed to delete the password and prevent exposure.
This is the master code:
Sub UpdateLinks()
Call PreSelect
Call UpDateLinksCode
Call PostSelect
End Sub
The individual ones are as below:
Sub PreSelect()
Sheets("Sheet1").Select
Range("A1").Select
End Sub
Sub UpDateLinksCode()
Const PWord As String = "password"
Dim xlLinks
Dim i As Integer
xlLinks = ThisWorkbook.LinkSources(xlExcelLinks)
If Not IsEmpty(xlLinks) Then
For i = 1 To UBound(xlLinks)
SendKeys PWord & "{Enter}"
ThisWorkbook.UpdateLink Name:=xlLinks(i)
Next i
End If
End Sub
Sub PostSelect()
Sheets("Sheet1").Select
Range("A1").Select
Selection.ClearContents
End Sub
It seems simple but i can't hack it.
Update: Appreciate all the input. I've now changed the code to sit in a module and refer to the worksheet by name. I've removed the call functions and separate codes and condensed it to the one. There are no errors when debugging or running through step by step.
However, same issue exists in that no further code will run following the 'send keys''. The "Range("A1").Select" needs to be in there because, something to do with the timing of the password request box popping up and the send keys inputting the password, causes half of the password to be typed into whichever cell is highlighted when the code is run. Therefore, i force it into cell A1 which has both background and text set to white.
Current code is as below:
Sub Update_links()
Worksheets("Staff Rota 2019").Unprotect "broncko"
Range("A1").Select
Dim PWord As String
PWord = "stevefinnan"
SendKeys PWord & "{Enter}"
ActiveWorkbook.UpdateLink Name:= _
"Y:\a - Staff Rota\Staff Rota 2019.xlsm", _
Type:=xlExcelLinks
Worksheets("Staff Rota 2019").Protect "broncko", DrawingObjects:=True,
Contents:=True, Scenarios:=True
end sub
This code must be in a worksheet code instead of a module since you are responding to a button event. The problem is that you select a different worksheet Sheets("Sheet1").Select and there must be some other code that gets run at that point.
Move the code to a module, and reference the specific worksheets directly (do not use the select statement).
for example:
Worksheets("Sheet1").Range("A1").ClearContents

How to lock specific cells but allow filtering and sorting

I'm using the following code to lock the content of certain cells
Sub LockCell(ws As Worksheet, strCellRng As String)
With ws
.Unprotect
.Cells.Locked = False
.Range(strCellRng).Locked = True
.Protect Contents:=True, AllowFormattingCells:=True, AllowFormattingColumns:=True, AllowFormattingRows:=True, AllowInsertingColumns:=True, AllowInsertingRows:=True, AllowSorting:=True, AllowFiltering:=True, AllowUsingPivotTables:=True, DrawingObjects:=True
End With
End Sub
It locks the content of those specific columns. The problem is users cannot sort, neither filter, nor apply borders to the cells since those Excel menu items are disabled.
I thought the AllowSorting:=True, AllowFiltering:=True and DrawingObjects:=True would allow that the same way the AllowFormattingColumns:=True and AllowFormattingRows:=True allowed resizing.
There are a number of people with this difficulty. The prevailing answer is that you can't protect content from editing while allowing unhindered sorting. Your options are:
1) Allow editing and sorting :(
2) Apply protection and create buttons with code to sort using VBA. There are other posts explaining how to do this. I think there are two methods, either (1) get the code to unprotect the sheet, apply the sort, then re-protect the sheet, or (2) have the sheet protected using UserInterfaceOnly:=True.
3) Lorie's answer which does not allow users to select cells (https://stackoverflow.com/a/15390698/269953)
4) One solution that I haven't seen discussed is using VBA to provide some basic protection. For example, detect and revert changes using Worksheet_Change. It's far from an ideal solution however.
5) You could keep the sheet protected when the user is selecting the data and unprotected when the user has the header is selected. This leaves countless ways the users could mess up the data while also causing some usability issues, but at least reduces the odds of pesky co-workers thoughtlessly making unwanted changes.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If (Target.row = HEADER_ROW) Then
wsMainTable.Unprotect Password:=PROTECTION_PASSWORD
Else
wsMainTable.Protect Password:=PROTECTION_PASSWORD, UserInterfaceOnly:=True
End If
End Sub
This was a major problem for me and I found the following link with a relatively simple answer. Thanks Voyager!!!
Note that I named the range I wanted others to be able to sort
Unprotect worksheet
Go to "Protection"--- "Allow Users to Edit Ranges" (if Excel 2007, "Review" tab)
Add "New" range
Select the range you want allow users to sort
Click "Protect Sheet"
This time, *do not allow users to select "locked cells"**
OK
http://answers.yahoo.com/question/index?qid=20090419000032AAs5VRR
I just came up with a tricky way to get almost the same functionality. Instead of protecting the sheet the normal way, use an event handler to undo anything the user tries to do.
Add the following to the worksheet's module:
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Locked = True Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
End If
End Sub
If the user does anything to change a cell that's locked, the action will get immediately undone. The temporary disabling of events is to keep the undoing itself from triggering this event, resulting in an infinite loop.
Sorting and filtering do not trigger the Change event, so those functions remain enabled.
Note that this solution prevents changing or clearing cell contents, but does not prevent changing formats. A determined user could get around it by simply setting the cells to be unlocked.
Here is an article that explains the problem and solution with alot more detail:
Sorting Locked Cells in Protected Worksheets
The thing to understand is that the purpose of locking cells is to prevent them from being changed, and sorting permanently changes cell values. You can write a macro, but a much better solution is to use the "Allow Users to Edit Ranges" feature. This makes the cells editable so sorting can work, but because the cells are still technically locked you can prevent users from selecting them.
I know this is super old, but comes up whenever I google this issue. You can unprotect the range as given in the above cells and then add data validation to the unprotected cells to reference something outrageous like "423fdgfdsg3254fer" and then if users try to edit any those cells, they will be unable to, but you're sorting and filtering will now work.
Lorie's answer is good, but if a user selects a range that contains locked and unlocked cells, the data in the locked/protected cells can be deleted.
Isaac's answer is great, but doesn't work if the user highlights a range that has both locked and unlocked cells.
I modified Isaac's code a bit to undo changes if ANY of the cells in the target range are locked. It also displays a message explaining why the action was undone. Combined with Lorie's answer, I was able to achieve the desired result of being able to sort/filter a protected sheet, while still allowing a user to make changes to an unprotected cell.
Follow the instructions in Lorie's answer, then put the following code in the worksheet module:
Private Sub Worksheet_Change(ByVal Target As Range)
For Each i In Target
If i.Locked = True Then
Application.EnableEvents = False
Application.Undo
Application.EnableEvents = True
MsgBox "Your action was undone because it made changes to a locked cell.", , "Action Undone"
Exit For
End If
Next i
End Sub
If the autofiltering is part of a subroutine operation, you could use
BioSum.Unprotect "letmein"
'<Your function here>
BioSum.Cells(1, 1).Activate
BioSum.Protect "letmein"
to momentarily unprotect the sheet, filter the cells, and reprotect afterwards.
This is a very old, but still very useful thread. I came here recently with the same issue. I suggest protecting the sheet when appropriate and unprotecting it when the filter row (eg Row 1) is selected. My solution doesn't use password protection - I don't need it (its a safeguard, not a security feature). I can't find an event handler that recognizes selection of a filter button - so I gave the instruction to my users to first select the filter cell then click the filter button. Here's what I advocate, (I only change protection if it needs to be changed, that may or may not save time - I don't know, but it "feels" right):
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Const FilterRow = 1
Dim c As Range
Dim NotFilterRow As Boolean
Dim oldstate As Boolean
Dim ws As Worksheet
Set ws = ActiveSheet
oldstate = ws.ProtectContents
NotFilterRow = False
For Each c In Target.Cells
NotFilterRow = c.Row <> FilterRow
If NotFilterRow Then Exit For
Next c
If NotFilterRow <> oldstate Then
If NotFilterRow Then
ws.Protect
Else
ws.Unprotect
End If
End If
Set ws = Nothing
End Sub
In Excel 2007, unlock the cells that you want enter your data into. Go to Review
> Protect Sheet
> Select Locked Cells (already selected)
> Select unlocked Cells (already selected)
> (and either) select Sort (or) Auto Filter
No VB required
I had a simular problem. I wanted the user to be able to filter "Table3" in a
protected worksheet. But the user is not able to edit the table. I accomplished above,
using the vba code below:
Range("Table3").Select
Selection.Locked = True
Selection.FormulaHidden = False
ActiveSheet.Protect DrawingObjects:=True, Contents:=True, Scenarios:=True _
, allowfiltering:=True
In the following code I filtered the code using VBA:
Range("Table3[[#Headers],[Aantal4]]").Select
ActiveSheet.ListObjects("Table3").Range.AutoFilter Field:=8, Criteria1:= _
Array("1", "12", "2", "24", "4", "6"), Operator:=xlFilterValues

Lock all the cells of a worksheet when specified text entered

I have an Excel sheet which has fields to enter data.
Let's say the total fields is 20. Ten of them are locked by default whenever the user opens the workbook. Now, one of the fields is asking the user to enter a password. If the password was "AAA", then five fields (of the ten locked ones) will be unlocked . If the user inputs a password as "BBB", then all the cells of the worksheet will be read-only and locked.
I am focusing on the case when the user inputs "BBB". I tried this code:
if Range("Password").value="BBB" then
cells.select
selection.locked=true
end if
It gives me an error as " Overflow".
If Range("Password").Value = "BBB" Then
ActiveSheet.UsedRange.Locked = True
End If
It gives me an error as " Overflow".
I doubt you should get an overflow error with this code. An overflow may occur if you use something like Cells.Count in Excel 2007 onwards. CountLarge was introduced just because Cells.Count returns an Integer value which errors out in Excel 2007 because of increased rows/columns. Cells.CountLarge returns a Long value.
Now back to your query.
You do not need to SELECT all cells. In fact you should avoid the use of Select. You may want to see How to avoid using Select in Excel VBA
Also locking all the cells of the worksheet will be ineffective if you do not protect your worksheet. You can change your code to
If Range("Password").Value = "BBB" Then
With ActiveSheet
.Cells.Locked = True
.Protect "Password"
End With
End If
And if you do not want to use Activesheet then use something like this
Option Explicit
Sub Sample()
Dim ws As Worksheet
'~~> Change this to the relevant sheet
Set ws = Sheet1
With ws
If .Range("Password").Value = "BBB" Then
.Cells.Locked = True
.Protect "Password"
'~~> To unprotect, uncomment the below
'.UnProtect "Password"
End If
End With
End Sub

Resources