I used to run 3 SAS EG Projects on a daily basis. Since a couple of days, we have a "SAS Scheduler" that is basically running those latter during the night (the first one at 00:00 AM, second one at 01:00 AM, third one at 03:00 AM). Each SAS Project has multiple SAS Programs.
All in all, that is great news, but this also mean I can't check the logs directly anymore.
To keep track of the night jobs, I am trying to find what could be the best way to export the log files for each project. I found out about the SAS Project Log recently, which basically summarize the logs from all the programs within a SAS Project.
I discovered CaseySmith's answer on the SAS Community forum, basically tweaking the .vbs script to save the SAS Project log file to a .txt using the following code:
Set objProjectLog = objProject.ProjectLog
objProjectLog.Clear()
objProjectLog.Enabled = True
'strProjectLog = objProjectLog.Text
objProjectLog.SaveAs "c:\temp\projectLog.txt"
But, 1) It is a .txt file not a log file and 2) I don't know where to add it in my current .vbs script:
Option Explicit
Dim app
Call dowork
'shut down the app
If not (app Is Nothing) Then
app.Quit
Set app = Nothing
End If
Sub dowork()
On Error Resume Next
'----
' Start up Enterprise Guide using the project name
'----
Dim prjName
Dim prjObject
prjName = "C:\Users\kermit\Desktop\Project.egp" 'Project Name
Set app = CreateObject("SASEGObjectModel.Application.8.1")
If Checkerror("CreateObject") = True Then
Exit Sub
End If
'-----
' open the project
'-----
Set prjObject = app.Open(prjName,"")
If Checkerror("app.Open") = True Then
Exit Sub
End If
'-----
' run the project
'-----
prjObject.run
If Checkerror("Project.run") = True Then
Exit Sub
End If
'-----
' Save the new project
'-----
prjObject.Save
If Checkerror("Project.Save") = True Then
Exit Sub
End If
'-----
' Close the project
'-----
prjObject.Close
If Checkerror("Project.Close") = True Then
Exit Sub
End If
End Sub
Function Checkerror(fnName)
Checkerror = False
Dim strmsg
Dim errNum
If Err.Number <> 0 Then
strmsg = "Error #" & Hex(Err.Number) & vbCrLf & "In Function " & fnName & vbCrLf & Err.Description
'MsgBox strmsg 'Uncomment this line if you want to be notified via MessageBox of Errors in the script.
Checkerror = True
End If
End Function
In the end, what I would like is that on the morning, I run a program that scan the 3 project log files for Notes, Warning and Errors and send to myself an email with the results. Hence, is there a way to export the SAS Project Log (not manually) in a folder?
So, first, what is this code doing?
Set objProjectLog = objProject.ProjectLog
objProjectLog.Clear()
This clears the project log. This needs to be done before your project is run - otherwise the log contains data from past runs. So put this before the prjOBject.Run().
objProjectLog.Enabled = True
'strProjectLog = objProjectLog.Text
objProjectLog.SaveAs "c:\temp\projectLog.txt"
This then exports the project log to a text file. You of course can call that text file whatever you want. You need this code to appear after your program runs, and somewhere before it closes. Right after PrjObject.Run() is probably fine.
You will need to update the names to match your vbs file's names - they use objproject and your vbs uses prjObject, but those are the same thing, just match the names.
Second - what else could you do? If VBS isn't your thing, you have a lot of other ways you could do this.
Export your EG project to a .sas file, then schedule this in base SAS with the normal output options. This may also be possible via the scheduling interface.
Use PROC PRINTTO to redirect your log inside your SAS code.
Copy your EG project to a location you can see. The EG project does contain the log of everything that was run - so there's no reason you couldn't just open the .egp and look at it, just make sure you're not doing that with the production file since you might forget to close out.
My preference is not to schedule EG projects, but to schedule .sas programs; use EG as the development environment and then export to .sas. This gives you more flexibility. But there are a lot of different ways to skin this cat.
Related
I'm having a strange problem with VBScript. I'd like to implement some other code with a following test:
If there is a file named like [that] in the [folder], do not copy it into the [folder].
Thing is, I found a strange relation in oFS.FileExists, I'm able to use it in a manually created folder, as long as I manually copy and paste a file into it. Then oFS.FileExists works like a charm.
Dim oFS
Set oFS = CreateObject("Scripting.FileSystemObject")
filestr = "C:\where\file\is\file.file"
If (oFS.FileExists(filestr)) Then
WScript.Echo("File exists!")
WScript.Quit()
Else
WScript.Echo("File does not exist!")
End If
But it's not exactly my point. I'd like to test if a file is already in the desired folder, and such folder will be generated automatically with oFS.CreateFolder. But when it comes to testing an automatically generated folder, it's a different story.
Dim oFS
Set oFS = CreateObject("Scripting.FileSystemObject")
oFS.CreateFolder(destination & objFoldername)
Initially I thought it might be something wrong with the file I'm looking for. I moved it to some other place and the oFS.FileExists found it. So I figured it might be the case of the folder itself. I can see the folder is a Read Only folder. I tested it in other manually created Read Only folder, also found it.
Finally I manually created the folder exactly like oFS.CreateFolder would do it, pasted manually a file into it and... it also found a file just fine.
As I witnessed, every test I conduct in a generated folder is failed, but done in a manually created one, pass.
Remarkable!
Had anyone such a case? Do you know why oFS.FileExists puts a blind eye on something created itself?
I'm using 64-bit Windows 10 Home, and I wrote both scrips in Visual Studio Code if that would be relevant.
Cheers guys, I can't be the first one.
EDIT for leeharvey1
Thank you leeharvey1 that you took a minute to have a look at this. This is the code that creates the directories:
Dim oFS, oFile, objShell, objFolder, sFolderPathspec, destination, file
Set oFS = CreateObject("Scripting.FileSystemObject")
sFolderPathspec = "C:\folder\where\files\are\"
Set objShell = CreateObject ("Shell.Application")
destination = "C:\folder\where\new\folders\with\files\are\intended\to\be\"
Set objFolder = objShell.Namespace(sFolderPathspec)
For Each file In objFolder.Items
name = file.Name
wykonano = objFolder.GetDetailsOf(file, 12)
If wykonano = "" Then
wykonano = objFolder.GetDetailsOf(file, 3)
End If
arr = Split(wykonano, " ")
brr = Split(arr(0), "-")
rok = brr(0)
miesiac = brr(1)
objFoldername = rok & "-" & miesiac
If CStr(oFS.FolderExists(destination & objFoldername)) >< "Prawda" Then
oFS.CreateFolder(destination & objFoldername)
End If
newdestination = destination & objFoldername & "\" & name
oFS.CopyFile sFolderPathspec & name, newdestination, False
Next
The whole testing for file existence started because I could not have the following to run:
oFS.CopyFile sFolderPathspec & name, newdestination, False
I would love it to copy but not overwrite. False, is however syntax correct, opposing to "Fałsz" (which would be correct in my Windows language). But the code crashes as soon as it hits the file that is already in the destination folder. Maybe should I have some kind of code which will let the sequence of code continue over the crashes caused by already existing files? (Like Python has)
So it took me to the following problem of testing for existence.
I figured I'll use the following method of the Files collection. As mentioned above, I get fails every time I conduct a test in generated folder, but done in a manually created one, pass.
That's the code (so far in a different VBScript file):
filestr = "C:\where\file\is\file.file"
Dim oFS
Set oFS = CreateObject("Scripting.FileSystemObject")
If oFS.FileExists(filestr) Then
MsgBox("Jest plik")
Else
MsgBox("Nie ma pliku")
End If
Function FileExists(FilePath)
Set oFS = CreateObject("Scripting.FileSystemObject")
If oFS.FileExists(FilePath) Then
FileExists=CBool(1)
Else
FileExists=CBool(0)
End If
End Function
If FileExists(filestr) Then
WScript.Echo "Does Exist"
Else
WScript.Echo "Does not exist"
End If
If (oFS.FileExists(filestr)) Then
WScript.Echo("File exists!")
WScript.Quit()
Else
WScript.Echo("File does not exist!")
End If
So, there are some details you wanted to know:
No, I am not working against a network shared file. It's all locally on my PC's ssd.
Have you tried disabling your anti-virus? No, if I'll need to do so in order to use it, I don't need the code.
I think I need to look for a file not for a folder, there is some kind of problem to locate the file. Do you think there could be also a problem to locate the folder itself?
Check folder Owner. Well, as far as I can see in Windows folder properties, it looks and have just the same settings as any other folder over there.
Thanks again leeharvey1 for your time!
So the setup on this WinServer 2012 R2 64bit is:
Windows Task Scheduler -> cscript .vbs file -> opening excel and run a sub in the main module
This runs fine in the background when I double click the .vbs file, but when I trigger the .vbs via the task scheduler, excel opens, but doesn't load the file or run the sub (not sure which). The task runs under an domain user that has administration rights on the machine. I use the same user when i try clicking on the .vbs
Code that is being run, in order:
Task scheduler launches:
C:\WINDOWS\system32\cscript.exe "D:\xyz\trigger.vbs"
.vbs does:
Option Explicit
Dim xlApp, xlBook, xlsheets, xlcopy
Set xlApp = CreateObject("Excel.Application")
xlapp.Interactive = False
xlapp.DisplayAlerts = False
xlapp.AskToUpdateLinks = False
xlapp.AlertBeforeOverwriting = False
Set xlBook = xlApp.Workbooks.Open("D:\xyz\excelfile.xlsm")
On Error Resume Next
Call xlBook.Application.Run("Main.Extrnal_Trigger")
xlbook.Saved = True
xlBook.Close
xlApp.Quit
Set xlBook = Nothing
Set xlcopy = Nothing
Set xlApp = Nothing
WScript.Quit(1)
Excel code:
Sub Extrnal_Trigger()
Application.EnableEvents = False
Application.AskToUpdateLinks = False
Application.DisplayAlerts = False
Application.AlertBeforeOverwriting = False
Call update_button
Call MainProgram
Call ReportSave
End Sub
How can I find out where the .vbs or the excel hangs and why? A very similar setup on another machine does run without troubles. It is virtually identical to the code quoted here.
I realize there are several bad practices (like not cleaning up xlapp settings), but I'd like to get the process running before cleaning up.
/edit:
Removing
On Error Resume Next
from the .vbs does not display an error.
/edit2:
I tried reverting as far back as possible.
Option Explicit
Dim fso, f, s, log
Set fso = CreateObject("Scripting.FileSystemObject")
Set log = fso.CreateTextFile("D:\xyz\TESTlog.txt")
log.WriteLine "before fso"
Set f = fso.GetFile("D:\xyz\excel.xlsm")
s = f.Path & " "
s = s & "Created: " & f.DateCreated & " "
s = s & "Last Accessed: " & f.DateLastAccessed & " "
s = s & "Last Modified: " & f.DateLastModified
log.WriteLine "after fso"
log.writeline "fso content"
log.writeline s
This works when being triggered by the task scheduler via cscript.exe.
I will try to modify to log what's happening around the call to the excel file.
/edit3:
Debugging showed that this
Set xlBook = xlApp.Workbooks.Open("D:\xyz\excel.xlsm")
never happens. I put out error numbers and got error 1004 for this call. Still not sure what's the issue, but at least I got an error number now.
/edit4:
error 1004 when trying to run this as a scheduled tasks persists. When I am running it by double clicking the .vbs, everything works.
The key was to create both these folders:
C:\Windows\System32\config\systemprofile\Desktop
and
C:\Windows\SysWOW64\config\systemprofile\Desktop
Excel apparently has troubles running in non-interactive mode when these folders are not present (not sure why). Creating them got rid ofthe 1004 error when opening the workbook via vbs.
I have VBScript that I wrote a long while back to identify PDF based on the file name. It then appended data to the file name and moved it to the proper directory. I did it as a Select Case in order for it to loop for many file names. I am now attempting to modify the script to check if the file with the new name is already at the destination directory, and if so, delete the old file, and copy the new one (also if the file is open and can't be overwritten, ignore and move to the next). I've been searching on many forums, and have been able to find pieces of what I am attempting, but have been unable to successfully integrate the processes into my script. Here is what I have for my select case, this section is what gets repeated with the "VariableAddedtoFileName" changed.
Select Case Pname
Case "FileName"
sDestinationFolder = "\\Server\FileDir\"
sDestinationName = "VariableAddedtoFileName"
Set oFSO = CreateObject("Scripting.FileSystemObject")
sSourceFile = objStartFolder & "\" & objFile.Name
sDestinationFile = sDestinationFolder & "\" & Pname & " " & _
sDestinationName & Right(objFile.Name, 4)
If oFSO.FileExists(sDestinationFile) Then
Set oFSO = Nothing
Else
oFSO.MoveFile sSourceFile, sDestinationFile
Set oFSO = Nothing
End If
Case "StatementScriptTest"
Case Else
End Select
So if I change theSet oFSO line in the If oFSO.FileExists group to oFSO.DeleteFile sDestinationFile It deletes the file, but won't copy the new one. If Rerun, it then copies the file, since it is no longer there. I have tried multiple combinations of attempting to manipulate the if statements and then with no luck. I also attempted to delete the file prior to the if section with no avail. Any assistance would be greatly appreciated.
If the full script is needed I can provide, I only listed this section as it is the part that gets rerun numerous times. Also I am aware that there are multiple posts similar to this, but I want to figure out how to update my code to work.
Update: I have fixed the overwriting by using CopyFile:
If oFSO.FileExists(sDestinationFile) Then
oFSO.CopyFile sSourceFile, sDestinationFile, True
Else
oFSO.CopyFile sSourceFile, sDestinationFile, True
Set oFSO = Nothing
End If
But I am still getting errors if the file is open when the attempt to overwrite is made.
First, you won't need the IF statement if you will have the same code in each branch. Just use the oFSO.CopyFile sSourceFile, sDestinationFile, True and it will do the work for you.
Second, in order to catch the error, you will have to use On Error Resume Next declaration before the copy command and check if some error triggered:
On Error Resume Next ' this tells VB to not throw errors and to populate the Err object when an error occurs
oFSO.CopyFile sSourceFile, sDestinationFile, True
IF Err.Number <> 0 Then
' do something when error occurs
' ...
Err.Clear ' clears the error so it will not trigger this on the loop if no more errors occur
End IF
' When you want to stop ignoring the errors
On Error GoTo 0
I have set up the following Sub to run shell commands quickly and easily.
This script works for the login scripts at my company without fail.
I am currently developing a script to add a large batch of users to our domain.
When I used this Sub in my new script I receive an error saying that the file cannot be found.
I have tried using the fix in this stackoverflow post, but I recieve the same error even with this code.
VBScript WScript.Shell Run() - The system cannot find the file specified
The part I find puzzling is that this sub works just fine when run from the netlogon folder of our domain controller.
What am I doing wrong?
Thanks,
Sub runcommand(strCommand)
Dim objWshShell, intRC
set objWshShell = WScript.CreateObject("WScript.Shell")
intRC = objWshShell.Run(strCommand, 0, TRUE)
call reportError(intRC,strCommand)
set objWshShell = nothing
end Sub
function reportError(intRC, command)
if intRC <> 0 then
WScript.Echo "Error Code: " & intRC
WScript.Echo "Command: " & command
end if
end function
The previous values for strCommand had no spaces and were very straightforward. Your new script is passing more complex variables to your Sub so you need additional conditional handling, as Alex K. pointed out in his Collusion (i.e., "Comment/Solution") above. Alex K.'s sample above is perfect, so, being a Point Pimp tonight, will post it as the solution:
objWshShell.Run("cmd /k echo Hello World", 1, TRUE)
I am very new to vb script and i need a script to delete couple of thrid level subfolders based on starting name _SA and 2 days old
example
C:\abc\user1\temp\ _SA123
c:\abc\user2\temp_SA2345
c:\abc\user3\temp_SA4567
I want to delete the folder starting with _SA older than 2 days and I have 50+ users folder. please hlep
Thanks,
Chilli
Based upon the example data, this should work though I'd consider this the 4th level:
Edit: Because you asked nicely, I updated this to build a log in a variable that will list the path of the folder deleted, the date it was created, and the date you deleted it. This information shows up in a msgbox, but you could easily modify to print the data to a file instead.
Dim rootFolder
Dim fld
Dim subFld
Dim subsubFld
Dim Log
Set fso = CreateObject("Scripting.FileSystemObject")
Set rootFolder = fso.GetFolder("C:\abc\")
For Each fld In rootFolder.SubFolders
For Each subFld In fld.SubFolders
For Each subsubFld In subFld.SubFolders
If Len(subsubFld.Name) >= 3 Then
If Left(subsubFld.Name, 3) = "_SA" And subsubFld.DateCreated < Now() - 2 Then
Log = subsubFld.Path & ", Created " & subsubFld.DateCreated & ",Deleted" & Now & vbNewLine
subsubFld.Delete
End If
End If
Next
Next
Next
MsgBox Log
'Or you could print the log to a file.
It has no error trapping, (other than making sure the folder name is atleast 3 characters long) and will get permission denied if you don't have permission.
Note: the code I posted has indentations, it's just not display for some reason. If you want to see the indented code, hit the edit button.