Run SAS programs from a scheduled task on windows

From sasCommunity
Jump to: navigation, search

Preparation

  1. Copy and paste the below script code into a new text file in your favorite editor.
  2. Change the two constants on lines 32 and 33 to indicate a valid SMTP server, and 'from' address at your site.
  3. Save the text file as "SasMail.wsf".
  4. To schedule a sas job, specify this as the Run: line:
cscript "x:\your\path\here\SasMail.wsf" /resultsto:president@whitehouse.gov /sasprog:"x:\another\path\here\my_program.sas"

Script Code

<package>
  <job id="SAS Call Wrapper/E-Mailer">
  <?job error="true" debug="false" ?>
  <runtime>
     <description>
        Submits the SAS program specified in the argument as a batch SAS job, scans
        the .log file For errors and e-mails the results to the address named in the
        "resultsto" parameter.
     </description>
     <named
        name="resultsto"
        helpstring="internet-style e-mail address"
        type="string"
        required="true"
     />
     <named
        name="sasprog"
        helpstring="Path/filename of the SAS Program you want to run."
        type="string"
        required="true"
     />
     <example>
        Example: WScript SasMail.wsf /sasprog:"c:\myprog.sas" /resultsto:president@whitehouse.gov
     </example>
  </runtime>
  <object ID="WinShell" progid="WScript.Shell"/>
  <object ID="Network" progid="WScript.Network"/>
  <object ID="FSO" progid="Scripting.FileSystemObject"/>
     <script language="VBScript">
        Option Explicit
        ' Change these to values that will be valid at your site!
        Const SMTP_SERVER    = "mail.yourdomain.tld"
        Const FROM_ADDRESS   = "nobody@nowhere.com"
        Const DQ = """"
        Call main
        WScript.Echo "Done!"
        ' ================================================
        Sub SendMail(Attachments, subj)
           Dim objEmail
           Dim f
           Set objEmail = CreateObject("CDO.Message")
           With objEmail
              .From = "SAS Mail script <" & FROM_ADDRESS & ">"
              .To = WScript.Arguments.Named("resultsto")
              .Subject = subj
              .Textbody = "Attached please find the results of your sas job."
              For each f in Attachments
                 ' For some reason this only works if I eat the doublequote delimiters.  Weird!
                 .AddAttachment replace(f, """", "")
              Next ' f
              ' .AddAttachment "\\home\pardre1\scripttest.lst"
              .Configuration.Fields.Item _
               ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
              .Configuration.Fields.Item _
               ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = _
                   SMTP_SERVER
              .Configuration.Fields.Item _
               ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
              .Configuration.Fields.Update
              .Send
           End With
        End Sub
        ' ================================================
        Sub main
           Dim SASProg
           Dim SASVer
           Dim SASexe
           Dim WorkingDir
           Dim BaseFileName
           Dim LogFile
           Dim ListFile
           Dim RunLine
           Dim FilesToSend(2)
           Dim MessageSubject
           Const SHOWNORMAL = 1
           Const SHOWMINIMIZED = 7
           If WScript.Arguments.Count <> 2 Then
              With WScript
                 .Arguments.ShowUsage
                 .Quit
               End With
           End If
           SASProg = WScript.Arguments.Named("sasprog")
           If Not FSO.FileExists(SASProg) Then
              With WScript
                 .Echo "Problem--I don't find any such file as " & SASProg & "!"
                 .Quit
              End With
           End If
           If LCase(FSO.GetExtensionName(SASProg)) <> "sas" Then
              With WScript
                 .Echo "Problem--" & SASProg & " isn't a SAS Program!"
                 .Quit
              End With
           End If
           BaseFileName = FSO.GetParentFolderName(SASProg) & "\" & FSO.GetBaseName(SASProg)
           LogFile = BaseFileName & ".log"
           ListFile = BaseFileName & ".lst"
           SASVer = WinShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\SAS Institute Inc.\The SAS System\CurrentVersion\CurrentVersion")
           ' msgbox("Current sas version is " & SASVer)
           SASExe = WinShell.RegRead("HKEY_LOCAL_MACHINE\SOFTWARE\SAS Institute Inc.\The SAS System\" & SASVer & "\DefaultRoot") & "\sas.exe"
           If Not FSO.FileExists(SASExe) Then
              WScript.Echo "Problem--sas.exe is not found where the registry says it should be!"
           Else
              RunLine =         DQ & SASExe   & DQ _
                 & " -sysin " & DQ & SASProg  & DQ _
                 & " -log   " & DQ & LogFile  & DQ _
                 & " -print " & DQ & ListFile & DQ _
                 & " -nologo " _
                 & " -noovp " _
                 & " -rsasuser " _
                 & " -unbuflog"
              ' MsgBox RunLine
              Call WinShell.Run(RunLine, SHOWMINIMIZED, True)
              ' MsgBox("sas return code: " &  WinShell.Run(RunLine, SHOWMINIMIZED, True))
              If CheckLog(LogFile) Then
                 ' MsgBox FSO.GetFileName(SASProg) & " ran with errors--check your log file!", vbOKOnly + vbCritical, "Uh-oh!"
                 MessageSubject = FSO.GetFileName(SASProg) &  " RAN WITH ERRORS!"
              Else
                 ' MsgBox FSO.GetFileName(SASProg) & " ran successfully!", vbOkOnly + vbInformation, "Yay!"
                 MessageSubject = FSO.GetFileName(SASProg) &  " ran successfully!"
              End If
              If FSO.FileExists(ListFile) Then
                 ' WinShell.Run(DQ & ListFile & DQ)
                 FilesToSend(0) = DQ & ListFile & DQ
              End If
              ' WinShell.Run(DQ & LogFile & DQ)
              FilesToSend(1) = DQ & LogFile & DQ
              SendMail FilesToSend, MessageSubject
           End If
        End Sub
        ' ================================================
        Public Function CheckLog(LogFilePath)
        Dim booReturn
        Dim LogFile
        Dim Contents
        Dim Rgx
        Const FORREADING = 1
           booReturn = True
           Set LogFile = FSO.OpenTextFile(LogFilePath, FORREADING)
           Contents = LogFile.ReadAll
           Set Rgx = New RegExp
           With Rgx
              .Pattern = "(error:|warning:|uninitialized)(?! (the .{4,15} product with which|your system is scheduled))"
              .Global = False
              .IgnoreCase = True
              booReturn = .Test(Contents)
           End With
            CheckLog = booReturn
        End Function
        ' ================================================
        ' WScript.Echo "Finished running " & WScript.ScriptName
     </script>
  </job>
</package>