Zip files to archive from SQL Server Agent job - tsql

I've written a program in Access vba that goes to a fixed directory, zips all files in that directory (and subdirectories), and places the zip archive in a (typically) new directory for archival storage. It's the backup routine for my Access Front End and associated files. I've been running it from my client machine every day, using my personal credentials. Now I want to run it from my small SQL Server machine since it is more robust, and accountable. I'd prefer to do it all in T-SQL rather than "calling" the Access routines.
I've done some research, but can't find anything definitive that will help me with this. Can someone point me to some help? Here is the Access VBA code:
Function Zip_All_Files_in_Folder()
Dim FileNameZip, FolderName
Dim strDate As String, TargetPath As String
Dim oApp As Object
TargetPath = "H:\xxx\secure\Construction\Access\All Database Backup\" & Format(Date, "YYYY-MMM") & "_Backup\"
If Len(Dir(TargetPath)) = 0 Then
MkDir (TargetPath)
End If
FolderName = "H:\xxx\secure\Construction\Access\CPAS\"
strDate = Format(Date, "YY-MM-DD")
FileNameZip = TargetPath & strDate & ".zip"
'Create empty Zip File
NewZip (FileNameZip)
'Copy the files to the compressed folder
Set oApp = CreateObject("Shell.Application")
oApp.Namespace(FileNameZip).CopyHere oApp.Namespace(FolderName).items
'Keep script waiting until Compressing is done
On Error Resume Next
Dim time As Integer
Do Until (oApp.Namespace(FileNameZip).items.Count = _
oApp.Namespace(FolderName).items.Count) Or time > 180
Sleep (1000)
time = time + 1
Loop
On Error GoTo 0
'Send a message about the way the script ended
If time < 180 Then
SendEmail "xxxxxx#yyyyyy.com", "Looks like the zip backup worked." & vbCrLf & TargetPath
Else
SendEmail "xxxxxxx#yyyyy.com", "Better double check the Zip backup: " & time & " seconds" & vbCrLf & TargetPath
End If
DoCmd.Quit
End Function
Sub NewZip(sPath)
'Create empty Zip File
'Changed by keepITcool Dec-12-2005
If Len(Dir(sPath)) > 0 Then Kill sPath
Open sPath For Output As #1
Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
Close #1
End Sub

File operations or other shell operations from the shell are difficult from TSQL because there is no built-in support for them and permissions are a common problem (the SQL Server service accounts may not have permission to access the filesystem).
The easiest solution is simply to write a standalone script in your preferred language; not an Access-based script, because Microsoft recommends against server automation using Office. Then schedule it as a SQL Server job or using the Windows scheduler. Unfortunately you haven't mentioned either your version or edition of SQL Server, so it isn't clear what capabilities your server has (e.g. Express Edition does not include SQL Agent, so no scheduled jobs).

Related

Microsoft Form Update System

I'm working on creating a Front End for multiple users for MS Access, and I have come up with a method to update their forms if there are any changes that need to be made. Basically what my VBA code will do, is delete the old forms and import the new ones if there are any (approximately 10 forms).
There is one issue with my process... Every time a new form is being imported, it is asking the user to accept the security warning and it gets annoying when there are so many forms and sometimes it can be a lengthy process to sit and wait for each to import and click accept every time a new import comes in.
Is there a more logical way to do this? Does Access have a build in function that will detect any changes to a form and update it based on a separate database?
Private Function PullNewForms()
DoCmd.TransferDatabase acImport, "Microsoft Access", _
"LOCATION", _
acForm, "frmLogin", "frmLogin"
DoCmd.TransferDatabase acImport, "Microsoft Access", _
"LOCATIONb", _
acForm, "frmNewUser", "frmNewUser"
DoCmd.TransferDatabase acImport, "Microsoft Access", _
"LOCATION", _
acForm, "frmOptionsMenu", "frmOptionsMenu"
DoCmd.TransferDatabase acImport, "Microsoft Access", _
"LOCATION, _
acForm, "frmResetPassword", "frmResetPassword"
DoCmd.TransferDatabase acImport, "Microsoft Access", _
"LOCATION", _
acForm, "frmVendorMainForm", "frmVendorMainForm"
End Function
Can this be consolidated to one line of code?
Reconsider this current setup. You should not be importing application objects like forms, reports, even modules on the fly like this as corruption and crashing may occur. You need a more stable version control system among your user base. Only data should ever really be imported.
Consider the following when deploying an MS Access FrontEnd application to multiple users:
Give each user their own FrontEnd to run on their local machines.
Keep a Master FrontEnd on a shared network that they can all access but never directly use, still maintaining the split architecture:
Give each user their own batch file (.bat) that they can double click from their desktops or wherever to copy the latest Master FrontEnd to replace their older version.
Keep for yourself, the developer, a development FrontEnd copy that when tested and debugged and ready to deploy into production, you replace as the new Master FrontEnd. This is hard at first but try not to make development changes in Master or local copies since you may overwrite your own changes.
Finally, with every new form/report/macro/module change, inform every user of a new available FrontEnd and to have them simply click their batch file to replace previous version.
Batch file
(Save below text in Notepad but as a .bat file and not default .txt file which automatically makes it a double-click executable script with gear icon. Give each user their own batch file tailoring local paths accordingly and save to their desktop or wherever their FrontEnd is located)
#echo off
Copy "\\Server\Path\To\MasterFrontEnd.accdb" "C:\User\JaneDoe\LocalFrontEnd.accdb" /Y
start "" cmd /c "echo UPDATE COMPLETE!&echo(&pause"

AHK code to locate the residing folder and highlight the active file

It’s often requires to quick locate the folder location of open active file and highlight or select the active file while working on different software applications. Quick locating the residing folder needed for finding related files in same folder, rename of the opened files or residing folder or move the file to different related folder. Current options require navigating through the loads of folders to find and locate the specific folder where it’s buried with bunch of similar other files (similar to find needle in a haystack). Microsoft Office suite has built-in feature named “document location” which can be added to quick access toolbar. But it only allow to see the folder location or full path but no single click command or key available (AFAIK) to conveniently jump to that locating folder and highlight/identified the opened file so that further operation (e.g. rename, move) could be done on that specific file/folder. This is also the case for other software applications where native program have options to get full path but no way to jump to the specific file/folder. Considering one of Microsoft Office suites application (e.g. word) as test cases the processes I could imagine as follows;
1 Get the full path (D:\Folder\Subfolder\Mywordfile.docx) of currently opened word document
2 Close the file
3 Explorer command to select and highlight the file in folder given full path (process 1)
Operation on file/folder as desire manually and double click to return to file operating applications (e.g. word).
In my assessment for Implementation of above tasks following are possibilities
Task 1 Microsoft Word has a built-in function called "document location" to get the full path of the opened document and its currently possible to copy the file path in the clipboard.
Task 2 Close the file (Ctrl+W or Ctrl+F4)
Task 3 AHK code for Explorer command to select the file for a given full path (available in Task 1)
I am facing difficulties in Task 3 and I tried each of these but so far no luck
Clipboard := “fullpath” ; Full path (D:\Folder\Subfolder\Mywordfile.docx ) copied from Word
Run explorer /e, “Clipboard”
Run %COMSPEC% /c explorer.exe /select`, "%clipboard%"
So far above explorer command only take me to my documents folder not in the specific folder location (path in Task 1). I am curious know what would be the right explorer code to select the file for a given full path in clipboard. Appreciate for supporting AHK code or better way to do this task. Thank in advance.
I'm not clear on why your sample code doesn't work. I suspect it's because of the extra characters.
After running this command Windows Explorer will be open and have the desired file selected (if it exists).
FullPathFilename := "e:\temp\test.csv"
Explorer := "explorer /select," . FullPathFilename
Run, %Explorer%
I don't know if you tried the other approach, but I think this is simpler and shorter:
1) Store the full path of the document in a string: oldfile = ActiveDocument.FullName
2) SaveAs the document with ActiveDocument.SaveAs
3) Delete the old file with Kill oldfile
All this is from VBA directly, no need to use Explorer shell. The same exists for the other applications.
Here is a fully working code for the Word Documents:
Sub RenameActiveDoc()
Dim oldfile As String
Set myDoc = ActiveDocument
'1) store current file
oldfile = myDoc.FullName
'2) save as the active document (prompt user for file name)
myDoc.SaveAs FileName:=InputBox("Enter new name", "Rename current document", myDoc.Name)
'3) Delete the old file with
On Error GoTo FileLocked
Kill oldfile
On Error GoTo 0
Exit Sub
FileLocked:
MsgBox "Could not delete " & oldfile, vbInformation + vbOKOnly, "File is locked"
End Sub
With contribution of Ro Yo Mi I am able to come up with following solution. However I am assuming that there might better solution to this task.
;;; Customize Document Location (Choose form All Commands) in Quick Access Toolbar and get its position (#4 for my case)
#If WinActive("ahk_class OpusApp") || WinActive("ahk_class XLMAIN") || WinActive("PPTFrameClass")
#p:: ;Close Word/Excel/PowerPoint Document and Locate in Explorer Folder Location
clipboard = ;empty the clipboard
Send !4 ; Select full path while document location at #4 position in Quick Access toolbar
Send ^c ; copy the full path
ClipWait ; waits for the clipboard to have content
Send {esc}
Send, ^{f4} ; Close opened document only but keep Word/Excel/PPT program running
Explorer := "explorer /select," . clipboard
Run, %Explorer%\
return

Connect to a project server when opening MS Project

I have a vbscript that checks to see if MS Project is open. If it's already open it runs a macro if not it should open Project then run the macro. It works fine if Project is already open. If project isn't open the script successfully opens and runs the macro but fails half way through. Basically it fails because the macro that is being called opens files from project server. even with my default account set to the Project server url and 'when starting' set to 'choose my default account' it still fails.
vbscript to open & run macro:
dim pjApp
on error resume next
set pjApp = GetObject(, "MSProject.Application")
if err.Number = 0 then
pjApp.Visible = True
pjApp.macro "testsave"
else
Set pjApp = CreateObject("MSProject.Application")
pjApp.Visible = True
pjApp.macro "testsave"
end if
Set pjApp = Nothing
Is there a way of forcing it to connect to the project server site when Project opens?
Here is the real issue:
Basically it fails because the macro that is being called opens files from project server.
In order to automate MS Project and have it open to a project server, you need to launch winproj.exe using a command-line switch as follows:
VBScript
On Error Resume Next
Dim pjApp
Set pjApp = GetObject(, "MSProject.Application")
If Err.Number <> 0 Then
Dim ProjServer
ProjServer = Chr(34) & "enter project server name here" & Chr(34)
Set objShell = WScript.CreateObject("WScript.Shell")
objShell.Run "winproj /s " & ProjServer, 1, True
Set objShell = Nothing
WScript.Sleep 5000
Set pjApp = GetObject(, "MSProject.Application")
End If
pjApp.Macro "testsave"
The code first checks to see if MS Project is already open and if so, uses that instance. Otherwise it uses the shell command to open to a specific project server.
Note: Update sleep value as necessary to give MS Project enough time to open before trying to get a reference to it.
VBA version
On Error Resume Next
Dim pjApp As MSProject.Application
Set pjApp = GetObject(, "MSProject.Application")
If Err.Number <> 0 Then
Dim ProjServer As String
ProjServer = Chr$(34) & "enter project server name here" & Chr$(34)
Shell "C:\Program Files (x86)\Microsoft Office\Office14\Winproj.exe /s " & ProjServer, vbNormalFocus
Do While pjApp Is Nothing
DoEvents
Set pjApp = GetObject(, "MSProject.Application")
Loop
End If
pjApp.Macro "testsave"
Note: Update the path to Winproj.exe as necessary.
Documentation for command-line switches seems to have been removed from Microsoft's site. Here's a page that still provides the documentation:
Using Command-line switches for Project. Briefly:
/s "URL"
/u "username"
/p "password"
filename
-ProjectProfiles
In place of pjApp.macro try:
pjApp.Appllication.Run "testsave"
I know that it is weird that the .macro version works for the code above it; however, it is still worth a shot. This code should also work for both places where you are using the .macro method.

Automator: duplicate OR copy in place

I am trying to build the following services:
Change type of image, result in the same folder (image.jpg => image.jpg + image.png)
Change size of image, result in the same folder (image.jpg => image.jpg + image-800x600.jpg)
I am stuck on part where the original image is duplicated in the same folder, under a different name (the copy finder item workflow requires a hard coded destination or other option I am not familiar with).
Maybe I could use a shell script to perform the duplicating part. I know how to get the file paths passed to the run shell script workflow, but I can't figure out how to send valid paths out to the next task (change type or resize).
MAC OS version is Mountain lion 10.8.2.
You can duplicate the files before you scale them:
on run {input}
set newFiles to {}
repeat with aFile in input
tell application "Finder" to set myFile to duplicate aFile
set end of newFiles to myFile as alias
end repeat
delay 1
return newFiles
end run
You can add another AppleScript at the end to deal with the files names:
on run {input}
repeat with myFile in input
tell application "System Events" to set oldName to myFile's name
set newName to do shell script "echo " & quoted form of oldName & " | sed -E 's/ ?copy ?[0-9?]*//'"
tell application "System Events" to set myFile's name to newName
end repeat
end run

Remote execution process in batch mode

The following script is invoking the excel batch file in the remote machine. The batch file will open the excel workbook.
D:>psexec.exe \Host_name D:\Excel.bat
For the above case excel is opened in the background (process) but the workbook is not opened
Is there any way to open the excel book in the remote machine?
Schedule task has been created in remote PC to invoke the desired batch file
Batch file has been created to run the scheduled task (schtasks /run /tn taskname)
Run the batch file using psexec.exe \host_name
Running a GUI (excel) remotely to your machine is not that easy. The easier way, is to code vbscript in your Excel.bat to "open" the excel file programmatically and display the cell values to you on the command line. Of course, charts and such would not be available to you then. The other way, get the excel file to your local machine and open it locally
http://motevich.blogspot.com/2007/11/execute-program-on-remote-computer.html
strComputer = "."
strCommand = "notepad.exe"
Const INTERVAL = "n"
Const MINUTES = 1
Set objWMIService = GetObject("winmgmts:\" & strComputer & "\root\cimv2")
Set objScheduledJob = objWMIService.Get("Win32_ScheduledJob")
Set objSWbemDateTime = CreateObject("WbemScripting.SWbemDateTime")
objSWbemDateTime.SetVarDate(DateAdd(INTERVAL, MINUTES, Now()))
errReturn = objScheduledJob.Create(strCommand, objSWbemDateTime.Value, False, 0, 0, True, intJobID)
If errReturn = 0 Then
Wscript.Echo "notepad.exe was started with a process ID: " & intJobID
Else
Wscript.Echo "notepad.exe could not be started due to error: " & errReturn
End If
String strComputer = "." means "local computer",
On remote computer strComputer = "servername"