Using Windows PowerShell to download a file from a SAS Workspace session

10

In a previous article, I described how to use Windows PowerShell to connect to a remote SAS Workspace, run a SAS program, and retrieve the results. In that example, the only results I retrieved were the SAS log and SAS listing (text) output, if any.

When you run a SAS program on a remote session, sometimes the expected result is more substantial than just a text-based listing. What if your program creates Output Delivery System (ODS) files such as HTML or graphics? To retrieve those results, you need to download the files from the SAS session to your local machine, where your application can access them. Consider this program, implemented in a PowerShell script, which creates an image with PROC SGPLOT:

# change these to your own SAS-session-based
# file path and file name
# Note that $destImg can't be > 7 chars
$destPath = "/projects/results"
$destImg = "hist"

# program to run
# could be read from external file
$program =  
       "ods graphics / imagename='$destImg';
        ods listing gpath='$destPath' style=plateau;
        proc sgplot data=sashelp.cars;
        histogram msrp;
        density msrp;
        run;"

# run the program
$objSAS.LanguageService.Submit($program);

When the program runs, it creates a file named hist.png in the /projects/results folder within the SAS session.

Downloading a file with FileService

The SAS Workspace provides the FileService API, which allows you to transfer file-based content between your local application and the SAS session. As with most file-based operations in SAS, the FileService relies on the use of a SAS fileref, or the name that SAS uses to reference your file within a program. For a file download operation, these are the basic steps:

  • Obtain a SAS reference to the file (FileService AssignFileref method.
  • Tell SAS to open the remote file for reading (OpenBinaryStream method).
  • Read the contents of the file into a local array of bytes (Read method, repeating in 1K increments).
  • Write the contents into a local file (PowerShell objects).
  • When completed, close the local and remote file handles, and unassign the SAS file reference (Close method and DeassignFileref method).

Here's a PowerShell program snippet that implements these steps. (The complete example is available on GitHub.)

# local directory for downloaded file
$localPath = "c:\temp"

# now download the image file
$fileref = ""

# assign a Fileref so we can use FileService from IOM
$objFile = $objSAS.FileService.AssignFileref(
     "img", "DISK", "$destPath/$destImg.png", 
     "", [ref] $fileref);

$StreamOpenModeForReading = 1
$objStream = $objFile.OpenBinaryStream($StreamOpenModeForReading)

# define an array of bytes
[Byte[]] $bytes = 0x0

$endOfFile = $false
$byteCount = 0
$outStream = [System.IO.StreamWriter] "$localPath\$destImg.png"
do
{
  # read bytes from source file, 1K at a time
  $objStream.Read(1024, [ref]$bytes)
  
  # write bytes to destination file
  $outStream.Write($bytes)
  # if less than requested bytes, we're at EOF
  $endOfFile = $bytes.Length -lt 1024
  
  # add to byte count for tally
  $byteCount = $byteCount + $bytes.Length
  
} while (-not $endOfFile)

# close input and output files
$objStream.Close()
$outStream.Close()

# free the SAS fileref
$objSAS.FileService.DeassignFileref($objFile.FilerefName)

Write-Output "Downloaded $localPath\$destImg.png: SIZE = $byteCount bytes"

Here's an excerpt from the output when the script runs:
NOTE: PROCEDURE SGPLOT used (Total process time):
      real time           13.18 seconds
      cpu time            0.12 seconds
      
NOTE: Listing image output written to /projects/result/hist.png.
NOTE: There were 428 observations read from the data set SASHELP.CARS.

Downloaded c:\temp\hist.png: SIZE = 15092 bytes

Related links

Share

About Author

Chris Hemedinger

Director, SAS User Engagement

+Chris Hemedinger is the Director of SAS User Engagement, which includes our SAS Communities and SAS User Groups. Since 1993, Chris has worked for SAS as an author, a software developer, an R&D manager and a consultant. Inexplicably, Chris is still coasting on the limited fame he earned as an author of SAS For Dummies

10 Comments

  1. Pingback: Using Windows PowerShell to connect to a SAS Workspace server - The SAS Dummy

  2. Would I be able to register the script as an object in the EG process flow?

    Suppose, I were to write some ODS output to a temporary location, so that the residual output is not retained on the server...much like EG's result destination. I would need to download the result before the server releases the WORK library. So, as part of the process flow, I might better able to insure the server does not timeout before I return to run the download script externally.

    Alternatively, I have the ideal that I might be able schedule a process flow and then insert the your download script into the scheduling script before the project is saved and closed (and the server shutdown). Ideas or problems (like does your script start a separate server)?

    Thanks.

  3. Adeline Wilcox on

    Chris,
    I would like to know how to use PowerShell to convert an XML file I've output from SAS (run in batch of course) to xlsx without manually opening it by Point and Click means. Running Invoke-item amounts to almost the same thing and isn't what I have in mind. I'm talking about an XML file I've produced with the ExcelXP tagset.
    Adeline.

    • Chris Hemedinger
      Chris Hemedinger on

      Adeline, you could use PowerShell to automate the Excel application, open the XML file that you created from ExcelXP, and then automate the SaveAs operation...thus converting the file into the native file format. Something like this:

      $Excel = New-Object -Com Excel.Application
      $Excel.Visible = $false
      $Excel.DisplayAlerts = $false
      $WorkBook = $Excel.Workbooks.Open("$localPath\out.xml")
      $WorkBook.SaveAs("$localPath\out.xlsx",51)
      $WorkBook.Close
      

  4. Chris,
    I would like to know how to use Powershell to upload a ".csv" or ".xls" file to a Workspace Server running on unix system. I would find a basetable (.sas7bdat) into workarea on the remote server.
    Thanks in advance.

    Kind regards.
    pippa

    • Chris Hemedinger
      Chris Hemedinger on

      Pippa, The technique is similar to the example here, except that you need to open the stream for writing, not reading:

      $StreamOpenModeForWriting = 2
      $objStream = $objFile.OpenBinaryStream($StreamOpenModeForWriting)
      

      Then of course you'll have to reverse all of the stream copy activity so that the SAS fileref is the destination, rather than the source.

  5. Pingback: An FTP-style task in SAS Enterprise Guide: user-driven fixes - The SAS Dummy

  6. Pingback: Viewing SAS catalogs and formats in SAS Enterprise Guide - The SAS Dummy

Back to Top