PascalScript in Syncovery

Syncovery 8 adds the PascalScript language, allowing you to customize your profile’s behavior in many ways.

To change a particular behavior, you need to write a hook function and write some code. In most cases, our tech support will write the code for you when we receive a feature request that is best implemented with a customized script. However, we will try to document the available hooks and functions fully so you can experiment on your own.

The script is specified in the profile via the “Pascal Script…” checkmark on the Job settings category tab sheet.

Since version 9.36b, PascalScripts have access to all profile settings and can read and modify them using the utility functions GetProfileProperty and SetProfileProperty.

Useful ready-to-use scripts

The following scripts can be used as it is, just paste the script into the PascalScript dialog.

Available PascalScript Hooks

The following hooks are currently available. Additional hooks will be added as needed to fulfill customer requests.

  • OnActionComplete
  • OnCanRunProfile
  • OnDownloadComplete
  • OnFileCopy
  • OnGetCustomHeaders
  • OnGetNextRunTime
  • OnGetProfilePathBeforeListing
  • OnGetProfilePathBeforeCopying
  • OnHttpPost
  • OnIncludeItem
  • OnProfileResults
  • OnMoveFileToDeletedFolder
  • OnReplaceFilenameLeftToRight
  • OnReplaceFilenameRightToLeft
  • OnScanFolder
  • OnSendEmail
  • OnUploadComplete
  • OnVolumeShadowComplete
  • OnBeforeFolderCreate
  • OnBeforeFileCopy

Available PascalScript Functions

The following functions are available for you to call.

  • standard functions such as Pos, Copy, Length, Ord
  • function GetProfileProperty(const fieldname:UnicodeString):UnicodeString;
  • function SetProfileProperty(const fieldname:UnicodeString;const val:UnicodeString):Boolean;
    (these functions use the same field names as the XML format and the command line. See the settings dictionary at the end of the Syncovery Command Line page)

  • function ConcatPath(const a,b:UnicodeString; const t: Int64):UnicodeString;
  • function ConcatPathWithDelim(const a,b,delim:UnicodeString):UnicodeString;
  • function ExtractFileName(const s: UnicodeString):UnicodeString;
  • function ExtractFilePath(const s: UnicodeString):UnicodeString;
  • function ExtractURLPartAfterServer(const s: UnicodeString):UnicodeString;
  • function ExtractFileExt(const s: UnicodeString):UnicodeString;
  • function ChangeFileExt(const s,t: UnicodeString):UnicodeString;
  • function FileExists(const FileName: UnicodeString):Boolean;
  • function EntryExists(const FileName: UnicodeString):Boolean;
  • function FileAge(const FileName: UnicodeString):Double;
  • function FileCopy(const ASource,ADest:UnicodeString):Int64;
  • function ProfileRunning(const s: UnicodeString):Boolean;
  • procedure Log(const s:UnicodeString);
  • procedure MessageBox(const s:UnicodeString);
  • function Execute(const s:UnicodeString; const TimeOutSeconds: Int64):Int64;
  • function GetProfileName:UnicodeString;
  • procedure SetProfileResult(const AResultText:UnicodeString);
  • function CreateS3Connector(const BucketName,AccessID,SecretKey:UnicodeString;const Options:Integer):Opaque;
  • function UploadFile(const LocalPath,DestinationPath:UnicodeString;const Connector:Opaque):Int64;
  • function CloseConnector(const Connector:Opaque):Int64;
  • function ConnFileExists(const Connector:Opaque; const FileName: UnicodeString):Boolean;
  • function ConnDirectoryExists(const Connector:Opaque; const Name: UnicodeString):Boolean;
  • function ConnCustomFTPCommand(const Connector:Opaque; const ACommand: UnicodeString;
         const AOkResponse1,AOkResponse2,AOkResponse3:Integer;
         var ResponseText: UnicodeString):Integer;
  • function ConnProcessWebForm(const Connector:Opaque;
         const URL, AFormName, AField1, AValue1, AField2, AValue2: AnsiString;
         const SaveResultPage: Boolean;
         const SavePageFileName: UnicodeString): Boolean;
  • function ConnRenameFile(const Connector:Opaque; const AFromFileName,AToFileName: UnicodeString):Boolean;
  • function ConnDeleteFile(const Connector:Opaque; const AFileName: UnicodeString):Boolean;
  • function ConnDeleteFiles(const Connector:Opaque; const APath,AMask: UnicodeString):Integer;
  • function ConnDeleteFilesOlderThan(const Connector:Opaque; const APath,AMask: UnicodeString;const AWhen:Double):Integer;
  • function StringReplace(const Source, OldPattern, NewPattern: UnicodeString;const CaseSensitive:Boolean): UnicodeString;
  • function EncodeBase64(const s: UnicodeString):UnicodeString;
  • function DecodeBase64(const s: UnicodeString):UnicodeString;
  • function Utf8Encode(const s: UnicodeString):AnsiString;
  • function Utf8Decode(const s: AnsiString):UnicodeString;
  • function UnicodeStringMD5Hex(const s: UnicodeString):UnicodeString;
  • function EightBitStringMD5Hex(const s: AnsiString):AnsiString;
  • function UnicodeStringMD5Base64(const s: UnicodeString):UnicodeString;
  • function EightBitStringMD5Base64(const s: AnsiString):AnsiString;
  • function SimpleEncrypt(const s: UnicodeString):UnicodeString;
  • function SimpleDecrypt(const s: UnicodeString):UnicodeString;
  • function AESEncrypt(const s,passphrase: UnicodeString):UnicodeString;
  • function AESDecrypt(const s,passphrase: UnicodeString):UnicodeString;
  • function ChooseFile(const Prompt,Extension:UnicodeString):UnicodeString;
  • function OpenIniFile(const AFileName:UnicodeString):Int64;
  • procedure CloseIniFile(const AnIni:Int64);
  • function ReadIniString(const AnIni:Int64;const Section,Ident,Default:UnicodeString):UnicodeString;
  • function GetInput(const s: UnicodeString):UnicodeString;
  • function GetPassword(const s: UnicodeString):UnicodeString;
  • function ReadRegistryString(const Key,OptName:UnicodeString):UnicodeString;
  • procedure WriteRegistryString(const Key,OptName,Value:UnicodeString);
  • function GetProfileRunID:UnicodeString;
  • procedure ClearBody;
  • function GetBodyLine(const i:Integer):UnicodeString;
  • procedure SetBodyLine(const i:Integer;const s:UnicodeString);
  • procedure DeleteBodyLine(const i:Integer);
  • procedure AddBodyText(const s:UnicodeString);
  • function GetActionList:UnicodeString;
  • function GetProfileSettings:UnicodeString;
  • function Now:Double;
  • function NowUTC:Double;
  • function OffsetFromUTC:Double;
  • function TimeToStr(const DateTime: Double):UnicodeString;
  • function DateTimeToStr(const DateTime: Double):UnicodeString;
  • function DateToStr(const DateTime: Double):UnicodeString’;
  • function DateTimeToStrWithFormat(const DateTime: Double;const FormatString:UnicodeString):UnicodeString;
  • function MakeSurePathExists(const s:UnicodeString;const isRightSide:Boolean):Boolean;
  • function PathDelim:UnicodeString;
  • function GetDelim(const Connector: Opaque):UnicodeString;
  • function IncludeLeadingPathDelim(const s: UnicodeString):UnicodeString;
  • function OpenTextFile(const s:UnicodeString):Opaque;
  • function AppendTextFile(const s:UnicodeString):Opaque;
  • function CreateTextFile(const s:UnicodeString):Opaque;
  • procedure WriteLine(const F:Opaque;const ALine:UnicodeString);
  • function ReadLine(const F:Opaque):UnicodeString;
  • procedure CloseFile(const F:Opaque);
  • function AtomicAppendTextFileLine(const APath,ALine:UnicodeString):Boolean;
    (appends a line in a multi-thread and multi-process safe way)
  • function YearOf(const dt:Double):Integer;
  • function MonthOf(const dt:Double):Integer;
  • function WeekOf(const dt:Double):Integer;
  • function DayOf(const dt:Double):Integer;
  • function DayOfTheWeek(const dt:Double):Integer;
  • function SecondOf(const dt:Double):Integer;
  • function HourOf(const dt:Double):Integer;
  • function MinuteOf(const dt:Double):Integer;
  • function EncodeDateTime(const AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Integer): Double;

Available Global Variables

These global variables allow direct access to Syncovery’s internal fields. Some of them should be considered read-only while others are meant to be changed as needed.

  • ProfileTempDir: UnicodeString;
  • LeftBasePath: UnicodeString;
  • RightBasePath: UnicodeString;
  • ProfileName: UnicodeString;
  • ResultSummary: UnicodeString;
  • MinimumFreeSpaceLeft: Int64;
  • MinimumFreeSpaceRight: Int64;
  • MaxWaitWhenFreeSpaceLowSeconds: Integer;
  • MinDate: Double;
  • MaxDate: Double;
  • FilterTimestamps: Boolean;
  • UseBinaryCompToAvoidCopying: Boolean

OnActionComplete Sample Script

This hook is called after any type of file or folder related action has been carried out, such as a file copied, moved, or deleted and so forth. The example just logs the action. The function result is ignored by Syncovery.

function OnActionComplete(const StartTimeUTC, CompletionTimeUTC: Double;
        const Success: Boolean;
        const ActionStr, DirectionStr, Filename,
              LeftFile, RightFile, Subfolder, MovedTo,
              ErrorMsg: UnicodeString;
        const ResultCode: Int64;
        const ErrorSide: UnicodeString;
        const ASize,ACompressedSize:Int64):Boolean;
  Log('Action Complete: '+ActionStr+' '+DirectionStr+' '+Filename);

OnCanRunProfile Sample Script

This hook is called when the scheduler is about to run a profile. You can decide if it should actually run now, or be postponed. The example uses the hook to prevent two particular profiles from running at the same time, or overlapping. This script must be entered as a Global PascalScript via the Program Settings dialog, tab sheet Advanced.

const p1='Profile Name 1';
      p2='Profile Name 2';

function OnCanRunProfile(const ProfileName:UnicodeString; var PostponeBySeconds:Integer):Boolean;
  if ProfileName=p1 then
     Result:=not ProfileRunning(p2)
     if ProfileName=p2 then
       Result:=not ProfileRunning(p1)
  if not Result then

OnFileCopy Sample Script

This hook allows you to replace the file copying logic. Return 0 on success, -1 if Syncovery should do the copying a usual, or any other value as an error code.

function OnFileCopy(const DirectionIsL2R:Boolean;
        const Source,Dest,DestPath,LeftSubPath,RightSubPath:UnicodeString;
        const SourceConnector,DestConnector: Opaque):Int64;
  Result:=Execute('XCOPY.EXE "'+Source+'" "'+DestPath+'"',60);

OnGetCustomHeaders Sample Script

This hook allows you to add custom HTTP headers to Amazon S3 requests. In future Syncovery versions, this feature can be added to other cloud storages and protocols (on customer request – just ask for it).

function OnGetCustomHeaders(const RelativePath: UnicodeString;
        const URL:AnsiString;var MIMEType, Headers: AnsiString;
        const Connector:Opaque):Boolean;
var strDate:string;
  Headers:='Cache-Control: 10';
  Log('Headers Added to '+RelativePath);

OnGetNextRunTime Sample Script

This hook allows you to modify the scheduling. The best way to use it is to give the profile a regular, simple schedule, and use the hook to skip undesired run times. This example is intended for a profile that is scheduled to run “every day at XX:YY”. The hook ensures that in fact it runs only on the first weekday in a month.

function OnGetNextRunTime(const LastRun, ProposedNextRun: Double):Double;
var DidItRunThisMonth:Boolean;
  DidItRunThisMonth:=(MonthOf(LastRun)=MonthOf(Now)) and
      (MonthOf(LastRun)=MonthOf(ProposedNextRun)) and
  if DidItRunThisMonth then begin
    // go to the next month
    while DayOf(Result)>1 do
  else begin
    // go to the next month if we are beyond week #1
    while DayOf(Result)>7 do
  // second, advance further until it's not a weekend
  while DayOfTheWeek(Result)>=6 do

OnIncludeItem Sample Scripts

The OnIncludeItem hook is called individually for each side of the synchronization. The isRightSide parameter indicates which side we are currently looking at.

The following script serves to exclude files without filename extension. Such an exclusion is not possible via the Exclusion Masks.

function OnIncludeItem(const FileName, RelativePath: UnicodeString;
        const isRightSide, isFolder:Boolean;
        const FileSize:Int64; const FileAttr:LongWord;
        const Connector: Opaque):Boolean;
  Result:=isFolder or (Pos('.',FileName)>0);

The second example for OnIncludeItem will only process subfolders that contain the file READY.toprocess, as well as any subfolders that exist on the right-hand side.

function OnIncludeItem(const FileName, RelativePath: UnicodeString;
        const isRightSide, isFolder:Boolean;
        const FileSize:Int64; const FileAttr:LongWord;
        const Connector: Opaque):Boolean;
  Result:=isRightSide or not isFolder or

OnScanFolder Sample Script

This is probably a better way to look for ‘READY.toprocess’. The OnScanFolder hook is called just before the folder would be scanned, and knowledge of both sides can be used in the hook.

function OnScanFolder(const FolderLevel: Integer;
        const RelativePath, LeftCompletePath, RightCompletePath: UnicodeString;
        const LeftExists,RightExists:Boolean;
        const LeftConnector, RightConnector: Opaque):Boolean;
  Result:=RightExists or ConnFileExists(LeftConnector,LeftCompletePath+'\READY.toprocess');

OnProfileResults Sample Script

This script does nothing, but the function is called with some statistics when a profile completes. An example with some real use can be downloaded near the top of this page (“Send E-Mail Notifications Depending on Profile Results”). This functions return value (“Result”) is ignored.

function OnProfileResults(const FilesCopiedL2R,FilesCopiedR2L:Integer;
        const FilesToCopyL2R,FilesToCopyR2L:Integer;
        const BytesCopiedL2R,BytesCopiedR2L:Int64;
        const ResultString:UnicodeString;
        const Error:Boolean):Boolean;

OnReplaceFilenameLeftToRight Sample Script

This script will rename files when the file is copied from left to right. In our example, ‘-draft’ is added before the filename extension.

function OnReplaceFilenameLeftToRight(const FileName: UnicodeString;
        const isFolder: Boolean):UnicodeString;
  if isFolder then

OnReplaceFilenameRightToLeft Sample Script

If you do a two-way sync, and new files might appear on the right-hand side, we also need a way to rename in the other direction. This sample script removes the ‘-draft’ insert from the names.

function OnReplaceFilenameRightToLeft(const FileName: UnicodeString;
        const isFolder: Boolean):UnicodeString;
var ToFind:UnicodeString;
  if isFolder then
  else begin
    if p>0 then

OnUploadComplete Sample Script

This script will set permissions for files uploaded via FTP to 777.

function OnUploadComplete(const FileName, LocalFilePath, CompleteURL: UnicodeString;
        const isRightSide:Boolean;
        const FileSize:Int64;
        const Connector: Opaque):Boolean;
var CmdRes:Int64;
  CmdRes:=ConnCustomFTPCommand(Connector,'SITE CHMOD 777 '+FileName,200,200,200,ResponseText);
  Log('Set Permissions for '+FileName+': '+ResponseText);

OnDownloadComplete Sample Script

This script will rename downloaded files by adding an additional “.downloaded” extension.

function OnDownloadComplete(const FileName, CompleteURL, LocalFilePath: UnicodeString;
        const isRightSide:Boolean;
        const FileSize:Int64;
        const Connector: Opaque):Boolean;
  if ConnRenameFile(Connector,CompleteURL,FileName+'.downloaded') then
    Log('Renamed '+FileName+' to '+FileName+'.downloaded')
    Log('Rename failed: '+FileName+' to '+FileName+'.downloaded');

OnVolumeShadowComplete Sample Script

This script will execute an external command (batch or CMD file) just after a volume shadow has been created.

function OnVolumeShadowComplete(const Volume,ShadowPath:UnicodeString):Boolean;

OnBeforeFolderCreate Sample Script

This script will prevent any folder creation except where necessary to copy files to the destination. You can also use this hook to manipulate folder paths on the destination.

function OnBeforeFolderCreate(const DirectionIsL2R:Boolean;
        var Source,Dest,Reason:UnicodeString):Boolean;

OnBeforeFileCopySample Script

This script will manipulate the destination paths for copying (left to right), by adding an additional subfolder ‘archive’ which is not present on the source side.

function OnBeforeFileCopy(const DirectionIsL2R:Boolean;
        var Source,Dest,DestPath,LeftSubPath,RightSubPath:UnicodeString):Boolean;
var AddFolderName,NewDestPath,NewDest,NewRightSubPath:UnicodeString;
  if not DirectionIsL2R then
  if not MakeSurePathExists(NewDestPath,true) then begin
    Log('Could not create '+NewDestPath);
  Log('DestPath:'+DestPath+' changed to '+NewDestPath);
  Log('Dest:'+Dest+' changed to '+NewDest);
  Log('RightSubPath:'+RightSubPath+' changed to '+NewRightSubPath);

OnGetProfilePathBeforeListing Sample Script

This script uses this hook to specify an individual TEMP folder for the profile. The original purpose of the function is to modify the left or right path and/or the credentials.

function OnGetProfilePathBeforeListing(const isRightSide:Boolean;
        var Path,UserName,Password:UnicodeString;
        var AuthKey,AuthKeyPassword:AnsiString;
        var Port:Integer):Boolean;