I'm working on automating a process with powershell for someone that is currently using an Excel sheet that utilizes macros and form control objects. I have the process mostly automated so far, but the sheet has a spot where the user has to click a button on the sheet which brings up a folder selection window where they select a folder for output files. The selection gets stored to a form control label object rather than in a cell. A macro then runs using the value stored in that label. I have been unable to track down any information on how I can modify the value for that label object through powershell.
Here is the VBA code that assigns the value to the label:
Private Sub SelectFolderButton_Click()
'Selects the folder (directory) for output files
Dim fd As FileDialog
Set fd = Application.FileDialog(msoFileDialogFolderPicker)
With fd
If (-1 = .Show) Then FolderLabel.Caption = .SelectedItems(1)
End With
End Sub
Unfortunately the user doesn't want the vba code to be changed. So I can't modify it to store the value in a cell and then have the macro use the cell instead, which would make this a lot easier.
If $wB would be the workbook object and the label "lblTest" is a Form Control shape of the worksheet "testSheet" you can try this in order to obtain the label value:
$wB.Worksheets.item("testSheet").Shapes.item("lblTest").Oleformat.Object.Object.Caption
Related
I am looking at inserting/pasting a range of text data (40 columns) from Excel into bookmarks in Word. Most of the answers are done using Excel VBA, which is so not practical for my use case as I will have the Word document open, add a button that would run this 'import data' macro. I actually already have a button in the doc that inserts images into bookmarks, so that's one more reason I don't want to do it via Excel VBA.
I know this is not great code, but for the lack of definite leads, I'm throwing it here and hope that this gives you an idea of what I'm trying to achieve:
Sub ImportData()
Workbooks.Open ("\Book2.xlsm")
ActiveWindow.WindowState = xlMinimized
ThisWorkbook.Activate
Windows("Book2.xlsm").Activate
Range("A1:AF1").Select
Selection.Copy
Documents("test.docm").Activate
Selection.GoTo What:=wdGoToBookmark, Name:="Overlay_1"
Selection.Paste
End Sub
PS: It would be great if I could sort of 'transpose' the 40 columns into rows as it is pasted in Word.
Here's an update to my code based off #Variatus 's advice:
Sub ImportData()
Dim wb As Workbooks
Dim ws As Worksheets
Dim objSheet As Object
Dim objWord As Object
Set objWord = CreateObject("Word.Application")
wb.Open ("C:\Users\pc\Documents\Book2.xlsm")
Set objSheet = CreateObject("Excel.Application")
ActiveWindow.WindowState = xlMinimized
Set ws = Workbooks("Book2.xlsm").Sheets("Sheet1")
ws.Range("A1").Value.Copy
With objWord.ActiveDocument
.Bookmarks("Bookmark_1").Range.Text = ws.Range("A1").Value
End With
End Sub
I'm getting this error:
Runtime Error '91':
Object variable or With block variable not set.
Notice how I stuck with a single cell reference for now (A1). I'll just update my code as I learn along the way :)
When you click the button in your Word document you want the following sequence to be initiated.
Create an Excel application object. Make sure that a reference to Excel has been set (VBE > Tools > References) so that Excel's VBA objects are available.
Using the Excel application object, open the workbook. Create an object. Place the object in an invisible window.
Definitely forget about activating or selecting anything in either the workbook or your Word document. The latter is active and remains active from beginning to end. The bookmarks are points in your document you can reference and manipulate by name without selecting them. The Excel workbook is invisible. You can access any part of it using the Range object.
The data you want from your workbook are contained in Worksheets. Be sure to create an object for the worksheet you are about to draw data from.
Excel tables don't translate very well into Word tables. If you do want to go that way I suggest that you use VBA to create the table you want in Excel (transpose the data before you import them into Word). However, you may find it easier to first create the tables you want in Word and then just copy values from your Excel source into the word tables. That would involve taking one cell value at a time and placing it into one Word table cell. Transposing would be done by the algorithm you employ.
Close the workbook. Quit the Excel application. Set the Excel application = Nothing. At the end of your macro everything is as it was before except that your document has data in it which it didn't have before.
Each of the above six points will lead you to at least one question which you can ask here after you have googled the subject and written some code. In fact, I strongly urge you to create one Main procedure (the one which responds to your button click) and let that procedure call various subs which carry out the individual tasks and functions to support the subs. The smaller the parts you create the easier it is to write the code, to find questions to ask and get answers to them. If you plan your project well expect to have about 12 procedures in it by the time you are done. Good luck!
I have a pre-defined Excel template which i would be filling it with data using .Net C# code.
I know the size of some columns but some of them i don't know, so when i export data into the excel, the presentation doesn't look good.
This xls sheet is sent to customer. 1000's of documents generated every day like this. It's a tiresome work to every time open a newly generated excel document and change the width of the column to autofit by double clicking the column.
Is it possible in Microsoft Excel to AutoFit the size some column and not for few other columns?
range("a2:d2").Columns.AutoFit
You could also use something like
range("a2").CurrentRegion.Columns.AutoFit
or
range("a:d, f:g").Columns.AutoFit
If you want the VBA for it is:
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Application.ScreenUpdating = False
For Each Value In Target.Columns
Worksheets(Sh.Name).Columns(Value.Column).AutoFit
Next Value
Application.ScreenUpdating = True
End Sub
Go to the Developer Tab (have to turn it on via File>Options>Customise Ribbon.
Open Visual Basic
Select Thisworkbook
Copy the Above VBA Code
Paste into the VBA Window
Close the VBA Window and the VBA editor
I've had a some success creating a project script that throws up some dialogues to take information, place it on a worksheet (activex box) and then print.
My code runs fine when located in Sheet1 object with the VB editor. However, I want it to run on excel open, so I paste it into the thisworkbook object within workbook_open(), but nothing works.
Can anyone explain to me how I can get this script to run upon excel open, or cease to receive the 424 error when running it from workbook_open()?
The debugger doesn't like my labelbatch and labelexpiry objects (but only when in thisworkbook), but it works fine otherwise.
Private Sub Workbook_Open()
ActiveWorkbook.Sheets("sheet1").Activate
'Clears label fields prior to data entry
labelbatch.Caption = ""
LabelExpiry.Caption = ""
'Auto input of batch code into batch field using input text.
BatchNo = InputBox("Enter batch code", " ")
labelbatch.Caption = BatchNo
'Auto input of expiry date into expiry field using input text.
ExpiryDate = InputBox("Enter expiry date", " ")
LabelExpiry.Caption = ExpiryDate
'Show print dialog box
Application.Dialogs(xlDialogPrint).Show
'Close without saving changes
ActiveWorkbook.Close False
End Sub
Assuming labelbatch and labelExpiry are objects on the worksheet, when the code is moved to ThisWorkbook VBA doesn't know where to look for those objects. Use e.g.
thisworkbook.worksheets("Sheet1").labelbatch
to refer to them.
When you use a method or property name without all its parents, VBA will either throw an error or will use a default depending on the context. For example, for Cells(), Range() and the like, that default is Application.ActiveSheet. That is generally risky: it's very hard to be sure what the active worksheet will be if you later change your code (or even if a user switches sheets while your code is running). Better to specify which worksheet you want.
This does make references to objects longer, but you can always use With...End With to help readability and save typing.
Is it possible to have a new Excel sheet created and then VB code automatically put in that sheet?
Here is what I have done so far. A sheet called Template has the input for all of the information that users need to input. I have various checks to make sure that all fields are filled out and are filled out correctly before anything else will execute. When they click on a certain cell to execute the script it will open a Word document and import all required information in it. Then a new sheet in Excel is created. A name is given to the new sheet, based on what was selected in the ComboBox (cboSites) from the Template sheet. I also have a check in place to make sure there already isn't a sheet with the same name. I have all of this working without any issues.
From here what I would like to do and can't think of how to do it, is when the new sheet is created I want VBA code automatically dumped in this new sheet. I know the code that I want to use, but I just have no idea how to get it so it will automatically put that code with that sheet.
Is this possible to do or can only a new sheet be created and formatted, without being able to import any code into it?
Here is a sample code which will insert
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
MsgBox "Hello World"
End Sub
in a new sheet in a new workbook.
Sub Sample()
Dim wb As Workbook, ws As Worksheet
Dim VBP As Object, VBC As Object, CM As Object
Dim strProcName As String
Set wb = Workbooks.Add
Set ws = wb.Sheets(1)
Set VBP = wb.VBProject
Set VBC = VBP.VBComponents(ws.Name)
Set CM = VBC.CodeModule
strProcName = "Worksheet_SelectionChange"
With wb.VBProject.VBComponents( _
wb.Worksheets(ws.Name).CodeName).CodeModule
.InsertLines Line:=.CreateEventProc("SelectionChange", "Worksheet") + 1, _
String:=vbCrLf & _
" Msgbox ""Hello World"""
End With
End Sub
Please amend it to suit your needs.
You need to ensure that Trust access to Visual Basic Project is selected. To select it, follow the steps mentioned in THIS LINK
I am not aware of an easy way to put code in an Excel file.
Someone might think about changing the XML structure directly (xlsx files are basically a zipped directory of xml and code files).
But did you consider using XLAM (Excel addin) files, that can contain code and be imported for all users, who ever need to use it. And would open up with Excel, when the users start it. Depending on your setup, this could help you?
Look into the VBProject property of the workbook you are generating. You should be able to manipulate it, adding new VBComponents items containing the code you want.
http://msdn.microsoft.com/en-us/library/office/ff194737.aspx
This will require the appropriate security settings to do.
Here's a thread on another site related to this topic:
http://www.mrexcel.com/forum/excel-questions/663848-access-vbulletin-project-not-trusted.html
I haven't tried it myself, so I can't give much more detail.
I've got an Access 2007 database on which I have created around 15 SQL queries to process specific data, I have created a main frame navigation menu using menus in Access, I now need to extract all th queries to Excel using VBA code, I have managed to do this with the code below by creating a button and specifying this code to it.
Private Sub query1_Click()
DoCmd.TransferSpreadsheet acExport, _
acSpreadsheetTypeExcel9, "Total Users and Sessions", _
"C:\UsersandSessions.xls", , "Total Users & Sessions"
End Sub
Now my problem at the moment is that fine the query is exported to Excel, but it is done so without any formatting applied at all, I would like to add some formatting at least to the headers and maybe a title inside the spreadsheet, and one thing I dont really like is that all records are being started from the first cell. Also I would prefer that if I hit that button again in Access and the Excel spreadsheet has already exists with that query output then when clicked again it will write again to a the next available sheet.
Any suggestions or ideas a very welcome.
The short story, is you can't. You might be able to do some scripting on the Excel side to format the resulting file. If you want something pretty, you probably want to create a report.
You could, instead mount the excel sheet as a table, and then on a separated sheet in the excel file, reference the first sheet, and format the second sheet for viewing.
if you use DoCmd.TransferSpreadsheet and create an original and then edit it so that the formatting is correct, you can then run DoCmd.TransferSpreadsheet again and it will update the file with the values but keep the formatting.
However, if a human then changes the file by adding new tabs, or adding calculations, etc, then the DoCmd.TransferSpreadsheet will no longer work and will fail with an ugly error message. So what we do in our enviroment is DoCmd.TransferSpreadsheet to an original file with formatting, and follow that up in the VBA by copying the file to the users desktop, and then opening that copy so the user doesn't mess up the original source excel file.
This approach is a minimum code, clean, and easy to maintain solution. But it does require a extra "source" or original file to be hanging around. Works in Access 2007.
You also would like the results to end up on a new tab. Unfortunately, I think it will take some excel automation to do that. The VBA inside Acccess can call a function inside the VBA in Excel. That VBA could then copy the tabs as needed.
My idea would be a hybrid of Excel automation from Access and creating a template in Excel as well that would have a data table linked to your query.
To start create your data table in Excel. You can start three rows down and two columns to the right if you want or wherever. Go to your data tab and click access, find your db, choose your query you want to link to, choose table as the radio button but click properties next instead of ok, uncheck the enable background refresh, this part is critical ... under the definition tab in the connection string you will see a part that says Mode=Share Deny Write change that to Mode=Read, this will make sure that the query refreshes without errors from an MS Access VBA while the db is open and will keep your users from writing back to the db in case your query is a writeable query. Once you set that up you can adjust the table formatting however you choose from the table design tab and it will keep that formatting.
For the purposes of this we are going to assume you started the table in cell B4 ,and your named the worksheet CurrentDay, for purpose of the following VBA example be sure to replace that reference with your actual placement.
Next go back to Access and write your VBA first ensure that in your VBA window you have the reference to Microsoft Excel 12.0 Object Library is selected by going to Tools > References and selecting it from the alphabetical listing.
Create your sub as follows:
Sub query1_click()
Dim xl as Excel.Application
Dim wbk as Excel.Workbook
Dim wks as Excel.Worksheet
Dim RC as Integer
Dim CC as Integer
Set xl = New Excel.Application
Set wbk = xl.wbk.Open "X:\Filelocation\FileName.xlsx" 'name and path you saved the file you previously created
xl.Visible = True
'The above is not necessary but you may want to see your process work the first few times and it will be easier than going to task manager to end Excel if something fails.
RC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("B:B")) + 3 'This will count the rows of data in your table including your header so you can copy the data to another tab dynamically as the size of your table expands and shrinks we add 3 to it because we started at row 4 and we need the location of the last row of the record set.
CC = xl.Application.CountA(xl.wbk.Worksheets("CurrentDay").Range("4:4")) + 1 'This counts the header row and adds one space because we will use this as a location holder for our copy / paste function
Set wks = xl.wbk.Worksheets.Add
wks.Name = format(date(),"MM_dd_yy") 'this will name the tab with today's date... you can eliminate this step if you just want the sheets to be the generic Sheet1, Sheet2, etc.
With xl.wbk
.Worksheets("CurrentDay").Range(Cells(4,2),Cells(RC,CC)).Copy
.wks.PasteSpecial xlPasteValues 'This pastes the values so that the table links do not paste otherwise every tab would just refresh everyday.
.wks.PasteSpecial xlPasteFormats 'This gets your formatting.
.RefreshAll 'This will refresh your table
Wend
With xl
.Save
.Close False
.Quit
Wend
Set xl = Nothing
Set wbk = Nothing
Set wks = Nothing
End Sub
That should get you to have your data to not start on A1 of your sheets, save your old data each time, and automate the steps from access.