Hide/Unhide sheets using username - vba

I just want to ask if it's possible to create a VBA that detects the identity of the person opening the workbook using Environ$("username") and using that I can hide some of the worksheet and unhide other worksheet that only that person can see?. Then if another person opens up the same workbook it will then hide/unhide worksheets for that other person.

Example of what you want (for educational purposes only):
Private Sub Workbook_Open()
Select Case Environ("username")
Case "bloggsj"
Sheets(1).Visible = False
Sheets(2).Visible = True
Case "doej", "murphyp", "manm"
Sheets(2).Visible = True
Sheets(1).Visible = False
Case Else
'// Unknown, close workbook
ThisWorkbook.Close False
End Select
End Sub
Important: As already mentioned in the comments, this is not a secure way of protecting data, two quick reasons as an example:
The Environment variable "username" can easily be changed which would trick the code into thinking that the person is a different user.
The Workbook_Open event can be easily bypassed by holding the shift button when opening the file.

Related

Excel Userform to only show if linked worksheet is active

hoping someone can help. I'm very new to VB code.
I'm building a set of Userforms where the data input is linked to various different worksheets. What i want is for my Userform Continue command buttons to only proceed to a certain Userform if the corresponding worksheet is active.
Eg My "Buildings" Userform must only display if Sheet "Buildings" is active on the workbook.
If Sheet "Buildings" is not active then the code must look for the next active sheet and go to the Userform that is linked to that sheet.
Eg If Sheet "Contents" is active on the workbook then the code must show my "Contents" Userform I created.
My first Userform asks the user to select which worksheets must be active by clicking on Toggle Buttons that activate sheets in the workbook.
From there the user clicks on a "Continue" button and then I need my code to look at which sheets are active.
I have this so far but I know its incorrect...
Private Sub CommandButton1_Click()
Dim answer As Integer
answer = MsgBox("Have you selected all your sections?", vbYesNo +
vbQuestion, "Selection Query")
If answer = vbYes And Sheets("Buildings") = Active Then
Me.Hide
Buildings_UF.Show
Else
Exit Sub
End If
End Sub
Thanking in advance
Patrick
UserForm.Show will stop the sub execution while the userform is opened, so the following code should suffice (untested code):
If answer = vbYes Then
Me.Hide
If Worksheets("Buildings").Visible then Buildings_UF.Show
If Worksheets("OtherSheet").Visible then OtherSheet_UF.Show
...
End If

Hide a worksheet based on username

I already have a macro below that un-hides a worksheet at the click of a button and works okay. However I want this macro to be changed so that ONLY two users (whose usernames are "JSMITH" AND "DTAYLOR") are able to unhide this sheet called "Rates".
If someone else (whose username is not one of the two mentioned above) tries to unhide the sheet, I want Excel to display a message "you're not authorised to open this".
Moreover, I need to make sure that only those two users are able to un-hide in a traditional way without vba (eg by right-clicking on a visible worksheet tab and choose Unhide or from any worksheet tab, choose Format, Sheet, and then Unhide).
Can you please advise how to modify the following code to do the all the things described above?
Sub Hide_AllRatesSheet()
Worksheets("Rates").Visible = False
ThisWorkbook.Sheets("Names").Activate
End Sub
Note: you could use xlSheetVeryHidden property to allow unhiding it only from code (and not by mouse right-click).
Try something like the code below:
Sub Hide_AllRatesSheet()
Select Case Environ$("username") '<-- check username
Case "JSMITH", "DTAYLOR"
If ActiveSheet.Name <> "Rates" Then '<-- make sure "Rates" is not the ActiveSheet
Worksheets("Rates").Visible = False
Else
ThisWorkbook.Sheets("Names").Activate
Worksheets("Rates").Visible = False
End If
Case Else
MsgBox "you're not authorised to open this"
End Select
End Sub

Hide specific sheets when closing workbook

I'm creating some VBA code which should do the following:
Users press a button a are required to input a code.
When the input the correct code the team relevant code they get access to certain sheets.
The sheets they get access to differs according to the team number and code they enter. So when they enter he password "banana": the sheets "Team_1" & Team_1_sub become visible.
I now created the following code to achieve this:
Sub filter_tabs()
Dim answer As String
answer = InputBox("Please enter your password")
If answer = "Password" Then
MsgBox "Correct, je krijgt nu de goede tabs te zien!"
Worksheets("Team_1").Visible = True
Worksheets("Team_1_sub").Visible = True
Else
MsgBox "Wrong password"
End If
End Sub
Two questions about the code above:
When the users close the document all sheet should "disappear" again. Does anybody know how to do this? So when opening the document sheets "Team_1" and "Team_1_sub" should be be standard
Worksheets("Team_1").Visible = False
Worksheets("Team_1_sub").Visible = False
Could you guys give me some feedback on whether the procedure I follow above (different if statements where users are prompted for a password and then get to see certain tabs) is the most efficient one to reach my goal? End goal is to make sure certain team leader can only see certain sheets.
Here for setting visible false, you can use Workbook_BeforeClose method as follow:
Private Sub Workbook_BeforeClose(Cancel As Boolean)
Worksheets("Team_1").Visible = False
Worksheets("Team_1_sub").Visible = False
'must save, if not save, it is not effect.
Me.Save
End Sub
Reference for that method is here.
One thing is that this method must have in the ThisWorkBook module.
For next question, you should say more like, which sheets for which user and password. Because you code is enough for your question. It can use for your requirement.
As you aren't using passwords you should at least make the sheets VeryHidden rather than Hidden - much harder for the average user to unhide.
The Me.Save proposed by the other answer also isn't necessary.
Private Sub Workbook_BeforeClose(Cancel As Boolean)
On Error Resume Next
Worksheets("Team_1").Visible = VeryHidden
Worksheets("Team_1_sub").Visible = VeryHidden
End Sub
ad 1)
you best use a Workbook_BeforeSave() routine to code the hiding of all sheets ... in the VBAProject view you find this under ThisWorkbook
ad 2)
The code you post looks very nice - my point of concern would be the hard coding of user names vs. sheet names. I would consider putting this in a sheet/table using headers /code/ /sheetname/ ... this way you can adapt your logic at any time without having to modify the code.
With such a table at hand (in an all time hidden sheet if need be) you traverse it (one single piece of code) and - upon code entering - you unhide If CodeInTable = CodeEntered ... in the other case you unconditionally hide that sheet ... because hiding/unhiding differs only by 2 simple conditions.

Secure Timestamp - VBA

I want to create a secure timestamp on my Excel sheet. The VBA I am using will automatically add the current users user name, the time, and the date when a user puts information into column A. So if the users puts something into cell A1 then B1 automatically gets filled with their username and C1 gets filled with the time and date. The only problem is that this method isn’t secure because the user could alter the information after it is automatically populated. I would like to add code to this VBA so it will lock all three cells after the information is populated.
I was planning on using the Protect Sheet feature and only allowing users to “Select unlocked cells” So if the VBA could auto lock the cells then the users would not be able to alter the information.
Moreover I have used Me.Unprotect before changing cells and Me.Protect after that still it is not working
Any help would be much appreciated!
Assume that we start with all the cells on the worksheet unlocked and the sheet password-protected with the password:
6LgSdHjc2uOssv0e1LDI
The following Event Macro will:
unprotect the workbook
detect entries in column A
place the username in column B and the date/timestamp in column C
lock the entries in columns A,B,C
re-protect the worksheet.
This goes in the Worksheet code area:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim A As Range, MyPass As String, sh As Worksheet
Dim unit As Range
Set A = Range("A:A")
MyPass = "6LgSdHjc2uOssv0e1LDI"
Set sh = ActiveSheet
If Intersect(Target, A) Is Nothing Then Exit Sub
Set unit = Union(Target, Target.Offset(0, 1), Target.Offset(0, 2))
Application.EnableEvents = False
sh.Unprotect (MyPass)
unit.Locked = False
Target.Offset(0, 1) = Environ("Username")
Target.Offset(0, 2) = Now()
unit.Locked = True
sh.Protect (MyPass)
Application.EnableEvents = True
End Sub
Because it is worksheet code, it is very easy to install and automatic to use:
right-click the tab name near the bottom of the Excel window
select View Code - this brings up a VBE window
paste the stuff in and close the VBE window
If you have any concerns, first try it on a trial worksheet.
If you save the workbook, the macro will be saved with it.
If you are using a version of Excel later then 2003, you must save
the file as .xlsm rather than .xlsx
To remove the macro:
bring up the VBE windows as above
clear the code out
close the VBE window
To learn more about macros in general, see:
http://www.mvps.org/dmcritchie/excel/getstarted.htm
and
http://msdn.microsoft.com/en-us/library/ee814735(v=office.14).aspx
To learn more about Event Macros (worksheet code), see:
http://www.mvps.org/dmcritchie/excel/event.htm
Macros must be enabled for this to work!

How to capture worksheet being added through Copy/Paste in Excel VBA

I am trying to capture worksheets being copied in to a workbook from another workbook.
Workbook_NewSheet event does not trigger when the sheets are copied from another workbook.
It is triggered only if the user manually inserts them through (Insert->Worksheet menu option), or when you add a new sheet through VBA as ThisWorkbook.Worksheets.Add.
What I am trying to capture is basically a Paste operation which is resulting in a new sheet.
This might be from any of the below user actions:
User copies an existing sheet by dragging it holding Control Key (which adds a new sheet)
User copies sheet/s from another workbook
user moved sheets from another workbook
or any of the below VBA code:
SourceWorkbook.Sheets(“SourceSheet”).Copy Before:=TargetWorkbook.worksheets(“SheetNameIn Target”) 'copy across workbook'
SourceWorkbook.Sheets(“SourceSheet”).Move Before:=TargetWorkbook.worksheets(“SheetNameIn Target”) 'move across workbook'
ThisWorkbook. Sheets(“SheetName”).Copy 'copy within workbook'
If you know any way of capturing this action/macro results within VBA that would be greatly helpful.
Please note that I do not want to avoid such an user action (so i do not want to secure the workbook) but I want to handle the pasted sheet programatically to verify the data, and if the similar sheet already exists then update the existing sheet rather than having same data in two sheets.
When a sheet is copied, its name will always end with "(2)", or at least ")". You could check on that like this
Private Sub Workbook_SheetActivate(ByVal Sh As Object)
If Sh.Name Like "*(2)" Then
Application.DisplayAlerts = False
Sh.Delete
Application.DisplayAlerts = True
End If
End Sub
The SheetActivate event will fire under all of those circumstances. Obviously it will fire under a lot of other circumstances too. This sounds like a royal pain, but you could maintain your own collection of worksheets and compare your collection to the ThisWorkbook.Sheets collection to see if something was added/deleted.
If you're trying to prevent it, you might consider protecting the workbook structure instead of doing it in code.
The way I have it implimented is
Private Sub Workbook_WindowActivate(ByVal Wn As Window)
ToggleMenuOptions False, 848, 889
End Sub
Private Sub Workbook_WindowDeactivate(ByVal Wn As Window)
ToggleMenuOptions True, 847, 848, 889
End Sub
Public Function ToggleMenuOptions(bToggle As Boolean, ParamArray ControlID() As Variant) As Boolean
'848 Move or Copy Sheet...
'889 Rename Sheet
'847 Delete Sheet
On Error GoTo lblError
Dim oControl As CommandBarControl, oControls As CommandBarControls, iControl As Integer
If IsMissing(ControlID) Then
ToggleMenuOptions = False
Exit Function
End If
For iControl = LBound(ControlID) To UBound(ControlID)
For Each oControl In Application.CommandBars.FindControls(ID:=ControlID(iControl))
oControl.Enabled = bToggle
Next
Next
ToggleMenuOptions = True
Exit Function
lblError:
If Err.Number Then
ToggleMenuOptions = False
Exit Function
End If
End Function
Private Sub Workbook_NewSheet(ByVal Sh As Object)
MsgBox "Please use Add New Project option in custom Toolbar to add new sheets!!", vbExclamation, "Not Supported"
Application.DisplayAlerts = False
Sh.Delete
Application.DisplayAlerts = True
End Sub
So my users wont be able to rename, add or delete sheets. This is working pretty well for now.
The only way I can think of doing this without maintaining a separate sheets collection is to maintain a static array of sheet names (or sheet codenames) and compare this to the actual sheets in the workbook each time the SheetActivate event fires to detect any additions. If you don't want to/can't keep the list in an array you could always use a hidden sheet to store the list. Whether this is any more or less of a pain than maintaining a separate collection is debatable :)
I am working on something similar but cannot block any of the user menu actions. I have sheets whose type are important - each sheet is either a Master or Slave - each Master sheet sums over the Slave sheets beneath it and I need to keep these formula clean.
Rather than maintain a list of sheets in an extra hidden sheet, I am defining 2 hidden names on each sheet recording the offset of the index of the Sheet to its linked Master sheet, and a reference to the linked Master sheet. So if my sheet is (say) +2 tabs from its Master sheet, then on Sheet activate/deactivate (not sure which of these is better to track at this stage) this offset will have changed if anything gets inserted, deleted or moved. This covers most or all of the events that would arise from moving or copying sheets.
If the sheet has been moved, I cycle through the workbook and calculate new Master/Slave index references for every sheet.
Will post code when I get this reasonably stable but it seems like a scheme that would work in a wide variety of circumstances.