How to delete worksheets except those on a list? - excel

I have a workbook with 13 sheets. I'm trying to delete some of those worksheets.
I defined a list with the name of all sheets I want to keep. I am trying to make a condition so sheets with a name different from those in the list are deleted.
Sub PREPARE_FILE()
Dim ws As Variant
ws = Array("Sheet1", "Sheet2", "Sheet3") 'Reminder that the Workbook has 13 sheets total.
For Each ws In Sheets(ws)
If ws <> [SOMETHING] Then
Delete = True
Next
Application.DisplayAlerts = True
What could I replace [SOMETHING] with, or how could it be designed differently?

Edit: Didn't read properly, and only now I see you trying to keep those sheets. If so, then try:
Sub PREPARE_FILE()
Dim ws As Worksheet
Dim arr As Variant: arr = Array("Sheet1", "Sheet2", "Sheet3")
Application.DisplayAlerts = False
For Each ws In ThisWorkbook.Worksheets
If Not (IsNumeric(Application.Match(ws.Name, arr, 0))) Then ws.Delete
Next ws
Application.DisplayAlerts = True
End Sub

Assuming we want to retain Sheet1, Sheet2, Sheet3; give this a try:
Option Explicit
Sub SheetKiller()
Dim i As Long, nm As String, tot As Long
Application.DisplayAlerts = False
tot = Sheets.Count
For i = tot To 1 Step -1
nm = Sheets(i).Name
If nm = "Sheet1" Or nm = "Sheet2" Or nm = "Sheet3" Then
'Do nothing
Else
If Sheets.Count <> 1 Then
Sheets(i).Delete
End If
End If
Next i
End Sub
Note:
The If Sheets.Count <> 1 Then is there to prevent all sheets being deleted if there are no sheets meeting the "save" criteria.

Delete Sheets With Exceptions
The first procedure, deleteSheetsUsage, illustrates how to use the second (main) procedure, deleteSheets.
The third procedure, TESTdeleteSheetsExpected, tests the expected behavior of the second procedure. To run the test, add a new workbook containing sheets Sheet1, Sheet2 and Sheet3. Copy at least the second and third procedure into an added standard module, e.g. Module1.
The fourth procedure, Result, just shows the expected result of the third procedure in the Immediate window.
The Code
Option Explicit
Sub deleteSheetsUsage()
Const SheetNames As String = "Sheet1,Sheet2,Sheet3"
Dim wb As Workbook
Set wb = ThisWorkbook
Dim Keepers() As String
Keepers = Split(SheetNames, ",")
deleteSheets wb, Keepers
End Sub
Sub deleteSheets( _
aWorkbook As Workbook, _
SheetsToKeep() As String)
Const ProcName As String = "deleteSheets"
On Error GoTo clearError
If Not aWorkbook Is Nothing Then
On Error Resume Next
Evaluate LBound(SheetsToKeep)
If Err = False Then ' 'If Not Err Then' doesn't work!
On Error GoTo clearError
If UBound(SheetsToKeep) >= LBound(SheetsToKeep) Then
With CreateObject("Scripting.Dictionary")
Dim sh As Object
For Each sh In aWorkbook.Sheets
If IsError(Application.Match(sh.Name, _
SheetsToKeep, 0)) Then
.Item(sh.Name) = Empty
Else
' Sheet name found in SheetsToKeep.
' No action taken.
End If
Next sh
Select Case .Count
Case 0
Debug.Print "'" & ProcName & "': " _
& "No sheets to delete. " _
& "No action taken."
Case Is < aWorkbook.Sheets.Count
Application.DisplayAlerts = False
aWorkbook.Sheets(.Keys).Delete
Application.DisplayAlerts = True
If .Count > 1 Then
Debug.Print "'" & ProcName & "': " _
& "Deleted " & .Count & " sheets."
Else
Debug.Print "'" & ProcName & "': " _
& "Deleted 1 sheet."
End If
Case Else ' Case Is >= aWorkbook.Sheets.Count
Debug.Print "'" & ProcName & "': " _
& "Attempted to delete too many sheets. " _
& "No action taken."
End Select
End With
Else
' ('UBound(SheetsToKeep) gt LBound(SheetsToKeep)').
Debug.Print "'" & ProcName & "': " _
& "'Sheets To Keep Array' is empty. " _
& "No action taken."
End If
Else
On Error GoTo clearError
Debug.Print "'" & ProcName & "': " _
& "'Sheets To Keep Array' is only declared. " _
& "No action taken."
End If
Else
Debug.Print "'" & ProcName & "': " _
& "Workbook not defined ('Nothing'). " _
& "No action taken."
End If
ProcExit:
Exit Sub
clearError:
Debug.Print "'" & ProcName & "': Unexpected Error!" & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
Resume ProcExit
End Sub
Sub TESTdeleteSheetsExpected()
' Test "Workbook not defined ('Nothing')."
Dim wb As Workbook
Dim Keepers() As String
deleteSheets wb, Keepers
' Test "'Sheets To Keep Array' is only declared."
Set wb = ThisWorkbook
deleteSheets wb, Keepers
' Test "'Sheets To Keep Array' is empty."
Dim SheetNames As String
SheetNames = ""
Keepers = Split(SheetNames, ",")
deleteSheets wb, Keepers
' Test multiple sheets OK.
wb.Worksheets.Add Count:=2
SheetNames = "Sheet1,Sheet2,Sheet3"
Keepers = Split(SheetNames, ",")
deleteSheets wb, Keepers
' Test one sheet OK.
wb.Worksheets.Add
SheetNames = "Sheet1,Sheet2,Sheet3"
Keepers = Split(SheetNames, ",")
deleteSheets wb, Keepers
' Test 'No sheets to delete.'
SheetNames = "Sheet1,Sheet2,Sheet3"
Keepers = Split(SheetNames, ",")
deleteSheets wb, Keepers
' Test 'Attempting to delete too many sheets.'
SheetNames = "Sheet100"
Keepers = Split(SheetNames, ",")
deleteSheets wb, Keepers
End Sub
Sub Result()
'deleteSheets': Workbook not defined ('Nothing'). No action taken.
'deleteSheets': 'Sheets To Keep Array' is only declared. No action taken.
'deleteSheets': 'Sheets To Keep Array' is empty. No action taken.
'deleteSheets': Deleted 2 sheets.
'deleteSheets': Deleted 1 sheet.
'deleteSheets': No sheets to delete. No action taken.
'deleteSheets': Attempted to delete too many sheets. No action taken.
End Sub

Related

Why do I get run-time error 9 message: Expecting object to be local when I run this code?

I am in need of assistance in resolving an issue I have ‎been experiencing when running certain codes, ‎particularly the one listed below. While I ‎comprehend why this error message may appear, I ‎am unsure as to why it is occurring with this ‎particular code. I have been receiving the 'expecting ‎object to be local' error message and 'subscript out ‎of range error message when no sheet with the ‎name is declared in the, despite the code's purpose ‎being to determine if the sheet is already present or ‎not and create it if it does not exist.‎
I'll be thankful to those who would put a hand into ‎this.‎
By the way, the code stops at the step of setting the WS.
Sub Check_Sheet_Exists()
Dim WS As Worksheet
Dim SheetName As String
SheetName = "ABCD"
' On Error Resume Next
Set WS = ThisWorkbook.Sheets(SheetName)
If WS Is Nothing Then
Sheets.Add before:=Sheets(Sheets.Count)
ActiveSheet.Name = SheetName
MsgBox "The sheet '" & SheetName & "' was created."
Else
MsgBox "The sheet '" & SheetName & "' already exists."
End If
End Sub
Code stuck here
Someone help me solve this issue, please.
Added an explicit Workbook reference, and cancelling the OERN as suggested by VBasic2008
Sub Check_Sheet_Exists()
Dim WS As Worksheet, wb As Workbook
Dim SheetName As String 'Use Const if the name is fixed...
SheetName = "ABCD"
Set wb = ThisWorkbook
On Error Resume Next 'ignore errors
Set WS = wb.Sheets(SheetName)
On Error GoTo 0 'stop ignoring errors
If WS Is Nothing Then
Set WS = wb.Worksheets.Add(before:=wb.Sheets(wb.Sheets.Count))
WS.Name = SheetName
MsgBox "The sheet '" & SheetName & "' was created."
Else
MsgBox "The sheet '" & SheetName & "' already exists."
End If
End Sub
Add Worksheet With Specific Name
Sub AddWorksheet()
On Error GoTo ClearError
Const PROC_TITLE As String = "Add Worksheet"
Const SHEET_NAME As String = "A\BCD"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
' Check if sheet name is taken.
Dim sh As Object
On Error Resume Next
Set sh = wb.Sheets(SHEET_NAME)
On Error GoTo ClearError
If Not sh Is Nothing Then
MsgBox "The sheet """ & SHEET_NAME & """ already exists.", _
vbExclamation, PROC_TITLE
Exit Sub
End If
' Add the worksheet.
Dim ws As Worksheet
Set ws = wb.Sheets.Add(Before:=wb.Sheets(wb.Sheets.Count)) ' before last
'Set ws = wb.Sheets.Add(After:=wb.Sheets(wb.Sheets.Count)) ' last
'Set ws = wb.Sheets.Add(Before:=wb.Sheets(1)) ' first
' Rename the worksheet.
Dim ErrNumber As Long, ErrDescription As String
' Atempt to rename.
On Error Resume Next
ws.Name = SHEET_NAME
ErrNumber = Err.Number
ErrDescription = Err.Description
On Error GoTo ClearError
' Invalid Sheet Name.
If ErrNumber <> 0 Then
Application.DisplayAlerts = False ' to delete without confirmation
ws.Delete
Application.DisplayAlerts = True
MsgBox "Run-time error '" & ErrNumber & vbLf & vbLf _
& ErrDescription & vbLf & vbLf & vbLf & PROC_TITLE & " Info" _
& vbLf & "The name """ & SHEET_NAME & _
""" is invalid. Worksheet not added.", vbCritical, PROC_TITLE
Exit Sub
End If
' Valid Sheet Name
MsgBox "The worksheet """ & SHEET_NAME & """ was added.", _
vbInformation, PROC_TITLE
ProcExit:
Exit Sub
ClearError:
MsgBox "Run-time error '" & Err.Number & vbLf & vbLf _
& Err.Description & vbLf & vbLf & vbLf & PROC_TITLE & " Info" _
& vbLf & "An unexpected error occurred.", _
vbCritical, PROC_TITLE
Resume ProcExit
End Sub

Rename Multiple sheets in Excel with cell value from same sheet in VBA

I am currently working on a VBA project. I have a workbook with multiple tabs from different workbooks. The names of all the tabs are the same, however since they come from different files, I would like to name them based on the filenames they are extracted from. The filenames are present in the cell EC1 of every tab. I would like to name all the sheets in the workbook based on the value present in cell EC1 of each individual sheet.
I have the following code:
Sub RenameSheet()
Dim rs As Worksheet
For Each rs In Sheets
rs.Name = rs.Range("EC1")
Next rs
End Sub
I have been getting a 1004 error from the above code.
I tried this code too:
Sub RenameSheet()
Dim xWs As Worksheet
Dim xRngAddress As String
Dim xName As String
Dim xSSh As Worksheet
Dim xInt As Integer
xRngAddress = Application.ActiveCell.Address
On Error Resume Next
Application.ScreenUpdating = False
For Each xWs In Application.ActiveWorkbook.Sheets
xName = xWs.Range(xRngAddress).Value
If xName <> "" Then
xInt = 0
Set xSSh = Nothing
Set xSSh = Worksheets(xName)
While Not (xSSh Is Nothing)
Set xSSh = Nothing
Set xSSh = Worksheets(xName & "(" & xInt & ")")
xInt = xInt + 1
Wend
If xInt = 0 Then
xWs.Name = xName
Else
If xWs.Name <> xName Then
xWs.Name = xName & "(" & xInt & ")"
End If
End If
End If
Next
Application.ScreenUpdating = True
End Sub
Some sheets do get renamed, however some do not. I have checked for duplicate sheet names, and there are none. I have also checked if the filename is in the correct range (cell), and it is present.
There might be problems with the value if it contains some special characters. The excel sheets can have some restrictions for their names, if thats the problem, my code could be the solution.
It cuts the string to a maximum length of 31 chars and deletes all the special chars which are not allowed in names.
Sub RenameSheet()
Dim rs As Worksheet
For Each rs In Sheets
sheetName = without_special_chars(rs.Range("EC1").Value)
If Len(sheetName) > 31 Then
sheetName = Left(sheetName, 31)
End If
rs.Name = sheetName
Next rs
End Sub
Function without_special_chars(text As String) As String
Dim i As Integer
Const special_chars As String = "-.,:;#+ß'*?=)(/&%$§!~\}][{"
For i = 1 To Len(special_chars)
text = Replace(text, Mid(special_chars, i, 1), "")
Next i
without_special_chars = text
End Function
Rename Multiple Worksheets
A Quick Fix
Your first code should have been something like this:
Sub renameWorksheetsQF()
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Name = ws.Range("EC1").Value
Next ws
End Sub
Note the not so subtile differences.
In Depth
Option Explicit
Sub renameWorksheets()
On Error GoTo clearError
Const cAddress As String = "A1" ' "EC1"
Dim wb As Workbook: Set wb = ThisWorkbook ' workbook containing this code
Dim ws As Worksheet
Dim cel As Range
Dim oName As String
Dim nName As String
For Each ws In wb.Worksheets
oName = ws.Name
Set cel = ws.Range(cAddress)
If IsError(cel) Then
Debug.Print "Cell '" & cAddress & "' in worksheet '" _
& oName & "' contains the error value '" & cel.Text & "'."
Else
If IsEmpty(cel) Then
Debug.Print "Cell '" & cAddress & "' in worksheet '" _
& oName & "' is an empty cell."
Else
nName = CStr(cel.Value)
On Error GoTo RenameError
If oName <> nName Then
ws.Name = nName
Else
Debug.Print "Worksheet '" & oName _
& "' had previously been renamed."
End If
On Error GoTo clearError
End If
End If
Next ws
ProcExit:
Exit Sub
RenameError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Debug.Print " Could not rename '" & oName & "' to '" & nName & "'."
Resume Next
clearError:
Debug.Print "Run-time error '" & Err.Number & "': " & Err.Description
Debug.Print " Unexpected error."
Resume ProcExit
End Sub

Efficient way to copy images and data from multiple source workbook to a single workbook

I have the following code to copy images from one workbook to another. The code opens the source workbook/sheet, copies the image then closes the workbook. This process repeats multiple times. Is there a more efficient way to do this? maybe bypassing the clipboard?
I only need to copy 1 image(named "Picture 4") and 2-3 cell values per source workbook/sheet. I have 7-8 source workbook.
Set srcWB = Workbooks.Open(ThisWorkbook.Path & "\testWS1.xlsx", True, True)
Set srcWS = srcWB.Sheets("sheetwithimage")
srcWS.Pictures(4).Copy
dstWS.Range("B7").PasteSpecial
Set srcWB = Workbooks.Open(ThisWorkbook.Path & "\testWS2.xlsx", True, True)
Set srcWS = srcWB.Sheets("sheetwithimage")
srcWS.Pictures(4).Copy
dstWS.Range("G8").PasteSpecial
So the fast solution is here:
Turn off Screen Updating and then turn it on again afterwards, I implemented some time measurement in my code to visualize this:
Option Explicit
Sub copy_images_original()
Dim dstWS As Worksheet
Set dstWS = ThisWorkbook.Sheets(1)
Dim srcWB As Workbook
Dim srcWS As Worksheet
Set srcWB = Workbooks.Open(ThisWorkbook.Path & "\testWS1.xlsx", True, True)
Set srcWS = srcWB.Sheets("sheetwithimage")
srcWS.Pictures(4).Copy
dstWS.Range("B7").PasteSpecial
srcWB.Close
Set srcWB = Workbooks.Open(ThisWorkbook.Path & "\testWS2.xlsx", True, True)
Set srcWS = srcWB.Sheets("sheetwithimage")
srcWS.Pictures(4).Copy
dstWS.Range("G8").PasteSpecial
srcWB.Close
End Sub
Sub CalculateRunTime_Seconds()
'PURPOSE: Determine how many seconds it took for code to completely run
'SOURCE: www.TheSpreadsheetGuru.com/the-code-vault
Dim StartTime As Double
Dim SecondsElapsed As Double
'Remember time when macro starts
StartTime = Timer
'*****************************
Call turn_app_off
Call copy_images_original
Call turn_app_on
'*****************************
'Determine how many seconds code took to run
SecondsElapsed = Round(Timer - StartTime, 2)
'Notify user in seconds
MsgBox "This code ran successfully in " & SecondsElapsed & " seconds", vbInformation
End Sub
Sub turn_app_off()
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
End Sub
Sub turn_app_on()
With Application
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
End With
End Sub
What has now improved?
Your srcWBs will now be closed, your original source code didnt do that.
In my scenario here, the execution time improved from 2 Secs to 1,4 Secs.
So your Code runs 25% faster without much effort.
Hope you find my suggestion fair enough.
With best regards
Create a Report
I was assuming that the destination workbook and the workbook containing this code, ThisWorkbook, are the same.
Adjust the values in the constants section.
Run only the createReport procedure. The function getFilePathsInFolder is being called by it.
Since ThisWorkbook will not have an "xlsx" extension, the statement If StrComp(FilePaths(fp), dstFilePath, vbTextCompare) <> 0 Then is redundant, but I'm leaving it because you might one day change the file extension to "xls*" when the code could do some damage.
Abstract
It will look in the specified folder and write all .xlsx files to an array. It will loop through the array and open each workbook to copy the picture, specified by its index, and paste it and write the specified cell values, to the specified locations of the destination workbook, closing each source workbook afterwards.
The Code
Option Explicit
Sub createReport()
Const ProcName As String = "createReport"
On Error GoTo clearError
' Source
Const Extension As String = "xlsx"
Const srcName As String = "sheetwithimage"
Const srcList As String = "A1,A2,A3" ' add more
Const picIndex As Long = 1
' Destination
Const dstName As String = "Sheet1"
Const dstList As String = "B1,B2,B3" ' add more
Const picAddress As String = "B7"
Const colOffset As Long = 5
' Write file paths from Source Folder Path to File Paths array.
Dim wbDst As Workbook: Set wbDst = ThisWorkbook
Dim srcFolderPath As String: srcFolderPath = wbDst.Path
Dim FilePaths As Variant
FilePaths = getFilePathsInFolder(srcFolderPath, Extension)
Dim srcCells() As String: srcCells = Split(srcList, ",")
Dim dstCells() As String: dstCells = Split(dstList, ",")
' Use a variable for lower and upper if inside another loop.
' Split ensures that lower is 0, so no need for lower variable.
Dim CellsUB As Long: CellsUB = UBound(srcCells) ' or 'Ubound(dstCells)'
Dim dst As Worksheet: Set dst = wbDst.Worksheets(dstName)
Dim dstFilePath As String: dstFilePath = wbDst.FullName
' Declare new variables occurring in the following loop.
Dim wbSrc As Workbook
Dim src As Worksheet
Dim srcCount As Long
Dim fp As Long
Dim n As Long
Application.ScreenUpdating = False
' We don't care if 'FilePaths' is zero, one or five-based, since we
' cannot use fp because of 'ThisWorkbook'; hence 'srcCount'.
For fp = LBound(FilePaths) To UBound(FilePaths)
' We have to skip 'ThisWorkbook'. Using 'StrComp' with 'vbTextCompare'
' is a great way for comparing strings case-insensitively i.e. 'A=a'.
' '0' means it is a match.
If StrComp(FilePaths(fp), dstFilePath, vbTextCompare) <> 0 Then
Set wbSrc = Workbooks.Open(FilePaths(fp), True, True)
Set src = wbSrc.Worksheets(srcName)
src.Pictures(picIndex).Copy
dst.Range(picAddress).Offset(, srcCount * colOffset).PasteSpecial
For n = 0 To CellsUB ' 'Split'
dst.Range(dstCells(n)).Offset(, srcCount * colOffset).Value _
= src.Range(srcCells(n)).Value
Next n
wbSrc.Close SaveChanges:=False
srcCount = srcCount + 1
End If
Next fp
' Save and/or inform user.
If srcCount > 0 Then
dst.Range("A1").Select
wbDst.Save
Application.ScreenUpdating = True
If srcCount = 1 Then
MsgBox "Data from 1 workbook transferred.", vbInformation, "Success"
Else
MsgBox "Data from " & srcCount & " workbooks transferred.", _
vbInformation, "Success"
End If
Else
MsgBox "No matching workbooks found in folder '" & srcFolderPath _
& "'!", vbCritical, "Fail"
End If
ProcExit:
Exit Sub
clearError:
Debug.Print "'" & ProcName & "': Unexpected Error!" & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
Resume ProcExit
End Sub
Function getFilePathsInFolder( _
FolderPath As String, _
Optional ByVal ExtensionPattern As String = "", _
Optional ByVal FirstIndex As Long = 0) _
As Variant
Const ProcName As String = "listFilePathsInFolder"
On Error GoTo clearError
With CreateObject("Scripting.FileSystemObject")
Dim fsoFolder As Object
Set fsoFolder = .GetFolder(FolderPath)
Dim FilesCount As Long
FilesCount = fsoFolder.Files.Count
If FilesCount > 0 Then
Dim n As Long
n = FirstIndex - 1
Dim OneD As Variant
ReDim OneD(FirstIndex To FilesCount + n)
Dim fsoFile As Object
If ExtensionPattern = "" Then
For Each fsoFile In fsoFolder.Files
n = n + 1
OneD(n) = fsoFile.Path
Next fsoFile
getFilePathsInFolder = OneD
Else
For Each fsoFile In fsoFolder.Files
If LCase(.GetExtensionName(fsoFile)) _
Like LCase(ExtensionPattern) Then
n = n + 1
OneD(n) = fsoFile.Path
End If
Next fsoFile
If n > FirstIndex - 1 Then
ReDim Preserve OneD(FirstIndex To n)
getFilePathsInFolder = OneD
Else
Debug.Print "'" & ProcName & "': " _
& "No '" & ExtensionPattern & "'-files found."
End If
End If
Else
Debug.Print "'" & ProcName & "': " _
& "No files found."
End If
End With
ProcExit:
Exit Function
clearError:
Debug.Print "'" & ProcName & "': Unexpected error!" & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
Resume ProcExit
End Function

VBA Loop directory removing (by sheet name) all sheets but one from each workbook

I have previously posted on here about using VBA to loop through a folder and remove known passwords from each workbook therein. Thought I could use the same code and just insert code the removes all sheets except one (by reference to sheet name), but no such luck.
Any VBA pros out there that can help?
Sub loop_sheets_del()
Dim MyFile as String, str As String, MyDir = "[directory]"
MyFile = Dir(MyDir & "*.xlsx")
ChDir MyDir
Application.ScreenUpdating = 0
Application.DisplayAlerts = 0
Do While Myfile <> ""
Workbooks.Open (MyFile)
If ws.Name <> "name of sheet to keep" Then
ws.Delete
End If
Next ws (error indicates problem is here)
ActiveWorkbook.Close True
End With
MyFile = Dir()
Loop
End Sub
Delete Sheets
In the current setup, the following will delete all sheets except the one named Master in all files with the xls* extension (e.g. xls, xlsx, xlsm: do not use wild characters in the code; it is covered by Instr) in the specified folder F:\Test\2020\64504925 and all of its subfolders.
The Code
Option Explicit
' Run only this sub after you have adjusted the path, the worksheet name
' and the file extension.
Sub loopSubFolders()
Application.ScreenUpdating = False
loopSubFoldersInitialize "F:\Test\2020\64504925", "Master", "xls"
Application.ScreenUpdating = True
MsgBox "Sheets deleted.", vbInformation, "Success"
End Sub
Sub loopSubFoldersInitialize(ByVal FolderPath As String, _
ByVal SheetName As String, _
Optional ByVal FileExtension As String = "")
Dim fso As Object
Set fso = CreateObject("Scripting.FileSystemObject")
loopSubFoldersRecursion fso, fso.GetFolder(FolderPath), SheetName, _
FileExtension
End Sub
Sub loopSubFoldersRecursion(fso As Object, _
fsoFolder As Object, _
ByVal SheetName As String, _
Optional ByVal FileExtension As String = "")
Dim fsoSubFolder As Object
Dim fsofile As Object
For Each fsoSubFolder In fsoFolder.SubFolders
loopSubFoldersRecursion fso, fsoSubFolder, SheetName, FileExtension
Next
If FileExtension = "" Then
For Each fsofile In fsoFolder.Files
'Debug.Print fsofile.Path
Next
Else
For Each fsofile In fsoFolder.Files
If InStr(1, fso.GetExtensionName(fsofile.Path), _
FileExtension, vbTextCompare) > 0 Then
Dim wb As Workbook
Set wb = Workbooks.Open(fsofile.Path)
deleteSheetsExceptOneByName wb, SheetName
Debug.Print fsofile.Path
wb.Close SaveChanges:=True
End If
Next fsofile
End If
End Sub
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Purpose: Deletes all sheets in a workbook except the one specified
' by its name.
' Remarks: The code uses the dictionary to hold all the sheet names.
' Only if the specified sheet exists, it will be removed from
' the dictionary and the remaining sheets in it will be deleted
' in one go. Otherwise no action will be taken.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Function deleteSheetsExceptOneByName(Book As Workbook, _
ByVal SheetName As String) _
As Long
' Initialize error handling.
Const ProcName As String = "deleteSheetsExceptOneByName"
On Error GoTo clearError ' Turn on error trapping.
' Validate workbook.
If Book Is Nothing Then
GoTo NoWorkbook
End If
' Define dictionary.
With CreateObject("Scripting.Dictionary")
.CompareMode = vbTextCompare
' Write sheet names to dictionary.
Dim sh As Object
For Each sh In Book.Sheets
.Add sh.Name, Empty
Next sh
' Validate sheet name string.
If Not .Exists(SheetName) Then
GoTo NoSheet
End If
' Remove sheet name string from the dictionary.
.Remove (SheetName)
' Validate number of sheets.
If .Count = 0 Then
GoTo OneSheet
End If
' Delete sheets.
Application.DisplayAlerts = False
Book.Sheets(.Keys).Delete
Application.DisplayAlerts = True
deleteSheetsExceptOneByName = .Count
GoTo SheetsDeleted
End With
NoWorkbook:
Debug.Print "'" & ProcName & "': No workbook ('Nothing')."
GoTo ProcExit
NoSheet:
Debug.Print "'" & ProcName & "': No sheet named '" & SheetName _
& "' in workbook."
GoTo ProcExit
OneSheet:
Debug.Print "'" & ProcName & "': Sheet '" & Book.Sheets(SheetName).Name _
& "' is the only sheet in workbook."
GoTo ProcExit
SheetsDeleted:
If deleteSheetsExceptOneByName > 1 Then
Debug.Print "'" & ProcName & "': Deleted " _
& deleteSheetsExceptOneByName & " sheets in workbook."
Else
Debug.Print "'" & ProcName & "': Deleted 1 sheet in workbook."
End If
GoTo ProcExit
clearError:
Debug.Print "'" & ProcName & "': " & vbLf _
& " " & "Run-time error '" & Err.Number & "':" & vbLf _
& " " & Err.Description
On Error GoTo 0 ' Turn off error trapping.
GoTo ProcExit
ProcExit:
End Function
You're missing the first part of the requisite For Each loop.
Also best to use a Workbook variable to refer to each workbook being opened and modified:
Do While Myfile <> ""
Dim MyWB As Workbook
Set MyWB = Workbooks.Open(MyFile)
For Each ws in MyWB.Worksheets
If ws.Name <> "name of sheet to keep" Then
ws.Delete
End If
Next
myWB.Close True
MyFile = Dir
Loop
Just for the sake of completeness I added the code and checked if the sheet to be kept exists so in case it doesn't, there isn't an error raised.
Read the code's comments.
Public Sub DeleteSheetsExceptInFiles()
Dim targetFile As String
Dim targetDirectory As String
Dim keepSheetName As String
Dim str As String
' Basic error handling
On Error GoTo CleanFail
' Define directory, file and sheet name
targetDirectory = "C:\Temp\"
targetFile = Dir(targetDirectory & "*.xlsx")
keepSheetName = "name of sheet to keep"
' Speed up process
Application.ScreenUpdating = False
Application.DisplayAlerts = False
' Loop through files
Do While targetFile <> ""
Dim targetWorkbook As Workbook
Set targetWorkbook = Workbooks.Open(targetDirectory & targetFile)
' Check if sheet to keep exists
Dim targetSheet As Worksheet
Dim keepSheetExists As Boolean
On Error Resume Next
keepSheetExists = targetWorkbook.Worksheets(keepSheetName)
On Error GoTo CleanFail
' Proceed if sheet exists
If keepSheetExists = True Then
For Each targetSheet In targetWorkbook.Worksheets
' Delete all sheets except the one to keep
If targetSheet.Name <> keepSheetName Then
targetSheet.Delete
End If
Next targetSheet
End If
targetWorkbook.Close True
targetFile = Dir()
Loop
CleanExit:
Application.ScreenUpdating = True
Application.DisplayAlerts = True
Exit Sub
CleanFail:
Debug.Print "Something went wrong: " & Err.Description
Resume CleanExit
End Sub

Renaming Sheets from cells with a loop

The code below is what i use to rename a bunch of sheets within a workbook. it works perfectly. It renames the sheet based off of a cell in that sheet. but now i have two sheets trying to use the same name. So i want to keep the same code but add a loop so if that happens, it will add a "2" to the second sheet. Ie cell contains "John Doe". Sheet will rename to "John Doe" and the next sheet that tries to use it will rename "John Doe 2"
Thank you
Sub RenameLaborLog()
Dim rs As Worksheet
For Each rs In Sheets
rs.Name = Split(rs.Range("H4").Value, " ")(1) & ", " & Left(Split(rs.Range("H4").Value)(0), 1) & "."
Next rs
End Sub
just to show another way you can reach your goal
Sub RenameLaborLog()
Dim rs As Worksheet, i As Long, str As String
On Error Resume Next
For Each rs In Sheets
str = Split(rs.Range("H4").Value, " ")(1) & ", " & Left(Split(rs.Range("H4").Value)(0), 1) & "."
rs.Name = str
i = 1
While Err.Number <> 0 And i < 20
Err.Clear: i = i + 1
rs.Name = str & i
Wend
If Err.Number <> 0 Then MsgBox "Error: " & rs.Name & " cant be set to any " & str: Exit Sub
Next rs
End Sub
it tries to set the name (and if that is not working it sets the name & 2 - 19 (if that doesnt work, it pops up a message box and exits the sub)
Use a controlled error to adjust the string containing the worksheet name until it find something it can use.
Sub RenameLaborLog()
Dim rs As Worksheet, snam As String, idupe As Long
On Error GoTo bm_Dupe_WS_Name
For Each rs In Sheets
idupe = 1
snam = Split(rs.Range("H4").Value, " ")(1) & ", " & _
Left(Split(rs.Range("H4").Value)(0), 1) & "."
rs.Name = snam
Next rs
bm_Dupe_WS_Name:
If idupe > 8 Then
Debug.Print Err.Number & ": " & snam & " - " & Err.Description
Exit Sub
ElseIf Right(snam, 1) = CStr(idupe) Then
snam = Trim(Left(snam, Len(snam) - 1))
End If
idupe = idupe + 1
snam = snam & Chr(32) & idupe
Resume
End Sub
I have it set yo attempt a numerical suffix up to 9. It it reaches that, it reports the error and exits the sub. I would not recommend running this without an escape clause. If nothing else, you may run into an illegal character when parsing the string for the worksheet name.
Based on the link #Scott Craner provided in his comment, I am providing another solution that I believe is a bit more functional and cleaner and easier to read.
Sub RenameLaborLog()
Dim rs As Worksheet, sName As String
For Each rs In Sheets
sName = Split(rs.Range("H4").Value, " ")(1) & ", " & Left(Split(rs.Range("H4").Value)(0), 1) & "."
i = 1
Do
If Not WorksheetExist(sName) Then
rs.Name = sName
Exit Do
Else: sName = sName & "_" & i + 1
End If
Loop
Next rs
End Sub
Function WorksheetExist(sName As String, Optional wb As Workbook) As Boolean
Dim wbCheck As Workbook, ws As Worksheet
If wb Is Nothing Then Set wbCheck = ThisWorkbook Else: Set wbCheck = wb
WorksheetExist = False
For Each ws In wbCheck.Worksheets
If ws.Name = sName Then
WorksheetExist = True
Exit For
End If
Next
End Function
Jeeped beat me to it, but here is another possible adjustment you could make:
Sub RenameLaborLog()
Dim rs As Worksheet, wsName As String, wsCheck As Worksheet, i As Integer
For Each rs In Sheets
' Get the sheet name
wsName = Split(rs.Range("H4").Value, " ")(1) & ", " & Left(Split(rs.Range("H4").Value)(0), 1) & "."
' Check if it exists
Set wsCheck = Nothing: On Error Resume Next: Set wsCheck = wsName: On Error GoTo 0
' Check if multiples already exist
While Not wsCheck Is Nothing
' If even one exits, "i" will be iterated
i = i + 1
Set wsCheck = Nothing: On Error Resume Next: Set wsCheck = wsName & "_" & i: On Error GoTo 0
Wend
' If at least one name already existed, name it with the current iteration.
If Not i = 0 Then wsName = wsName & "_" & i
rs.Name = wsName
Next rs
Set rs = Nothing: Set wsCheck = Nothing
End Sub

Resources