├── .gitignore ├── LICENSE ├── README.md ├── SCPDemo.dpr ├── SCPDemo.dproj ├── SCPDemo.res ├── SSHCommand.pas ├── SSHCommandDemo.dpr ├── SSHCommandDemo.dproj ├── SSHCommandDemo.res ├── TSSHCommand.groupproj ├── Test ├── Test.dpr ├── Test.dproj ├── Test.res └── uTest.pas └── Thorsten Maxeiner Vortrag ssh Forentage 2019.pdf /.gitignore: -------------------------------------------------------------------------------- 1 | # Uncomment these types if you want even more clean repository. But be careful. 2 | # It can make harm to an existing project source. Read explanations below. 3 | # 4 | # Resource files are binaries containing manifest, project icon and version info. 5 | # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. 6 | #*.res 7 | # 8 | # Type library file (binary). In old Delphi versions it should be stored. 9 | # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. 10 | #*.tlb 11 | # 12 | # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. 13 | # Uncomment this if you are not using diagrams or use newer Delphi version. 14 | #*.ddp 15 | # 16 | # Visual LiveBindings file. Added in Delphi XE2. 17 | # Uncomment this if you are not using LiveBindings Designer. 18 | #*.vlb 19 | # 20 | # Deployment Manager configuration file for your project. Added in Delphi XE2. 21 | # Uncomment this if it is not mobile development and you do not use remote debug feature. 22 | #*.deployproj 23 | # 24 | # C++ object files produced when C/C++ Output file generation is configured. 25 | # Uncomment this if you are not using external objects (zlib library for example). 26 | #*.obj 27 | # 28 | 29 | # Delphi compiler-generated binaries (safe to delete) 30 | *.exe 31 | *.dll 32 | *.bpl 33 | *.bpi 34 | *.dcp 35 | *.so 36 | *.apk 37 | *.drc 38 | *.map 39 | *.dres 40 | *.rsm 41 | *.tds 42 | *.dcu 43 | *.lib 44 | *.a 45 | *.o 46 | *.ocx 47 | 48 | # Delphi autogenerated files (duplicated info) 49 | *.cfg 50 | *.hpp 51 | *Resource.rc 52 | 53 | # Delphi local files (user-specific info) 54 | *.local 55 | *.identcache 56 | *.projdata 57 | *.tvsconfig 58 | *.dsk 59 | 60 | # Delphi history and backups 61 | __history/ 62 | __recovery/ 63 | *.~* 64 | 65 | # Castalia statistics file (since XE7 Castalia is distributed with Delphi) 66 | *.stat 67 | 68 | # Output directory 69 | Win32/ 70 | 71 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Thorsten Maxeiner 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TSSHCommand 2 | Send commands over ssh with Delphi. This is no implementation of ssh protocol in Delphi but a Wrapper to use ssh in a Delphi way. Since Openssh is a part of Windows 10, usage is easy without installing putty or something else. 3 | --- 4 | 5 | # Description 6 | TSSHCommand is a wrapper for Delphi to use built in openssh in Windows 10 to: 7 | - send commands to a remote ssh server 8 | - send files with scp to a remote server 9 | - receive files with scp from a remote server 10 | 11 | # Advantage 12 | Openssh is available in windows 10 since 1803 and I think standard install since 1809. 13 | Using ssh with Delphi gives out of the box encryption and authentication mechanism. 14 | Openssh in Windows is key compatible with openssh key in Linux. 15 | Command line options are compatible in Windows and Linux. 16 | 17 | # Prerequisites 18 | This wrapper uses shellexecute to start ssh.exe. Normally ssh is located in c:\windows\system32\Openssh\. 19 | I don't know why but shellexecute can't open the Openssh folder. If you start cmd.exe and navigate to c:\windows\system32\, you see no folder Openssh. If you use powershell, you see the folder and can enter it. 20 | So my detour is to copy ssh.exe from Openssh folder to my application folder or to a other folder e.g. c:\tools\ 21 | To use the scp function, same is for scp.exe. 22 | 23 | # Repo Contens 24 | Included is the wrapper as Delphi record (file SSHCommand.pas), demo application and test. 25 | 26 | # Usage 27 | Evertything is visible in the demo application. 28 | After entering basic settings like: 29 | - hostname 30 | - port (if set other than 22) 31 | - username 32 | - keyfile 33 | you can perform as many commands and scp copy action with one line of code each. 34 | 35 | Attention: Before connecting with this wrapper, first make manuell connection e.g. with powershell to have a host entry in known_hosts! 36 | 37 | 38 | '''' 39 | -------------------------------------------------------------------------------- /SCPDemo.dpr: -------------------------------------------------------------------------------- 1 | program SCPDemo; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | SSHCommand; 10 | 11 | var 12 | MySSHCommander : TSSHCommand; 13 | MyResult : integer; 14 | begin 15 | try 16 | MySSHCommander.HostName := 'www.example.com'; 17 | MySSHCommander.PortNum := 12322; 18 | MySSHCommander.UserName := 'myuser'; 19 | MySSHCommander.KeyFile := '~/.ssh/myuserkey'; 20 | 21 | MyResult := MySSHCommander.SCPFromRemote( '/home/bill/list*.*', 'c:\tools\' ); 22 | if MyResult > 32 then Writeln('Copy from remote OK') 23 | else Writeln('Error Nr.: ' + MyResult.ToString); 24 | 25 | MyResult := MySSHCommander.SCPToRemote( 'c:\tools\liste2.txt' , '/home/bill/' ); 26 | if MyResult > 32 then Writeln('Copy to remote OK') 27 | else Writeln('Error Nr.: ' + MyResult.ToString); 28 | 29 | Writeln('Press Enter...'); 30 | Readln; 31 | except 32 | on E: Exception do 33 | Writeln(E.ClassName, ': ', E.Message); 34 | end; 35 | end. 36 | -------------------------------------------------------------------------------- /SCPDemo.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {F113DDEA-B2F9-4677-B7EE-B36965605396} 4 | 18.3 5 | None 6 | SCPDemo.dpr 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Console 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | .\$(Platform)\$(Config) 44 | .\$(Platform)\$(Config) 45 | false 46 | false 47 | false 48 | false 49 | false 50 | RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACIBDriver;emsclient;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;aurelius;$(DCC_UsePackage) 51 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 52 | SCPDemo 53 | 54 | 55 | DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;AbkStdRAD10_2;tethering;svnui;FireDACADSDriver;frxe25;vacommpkgdXE11;FireDACMSSQLDriver;hotxls250;vcltouch;tmsxlsdXE11;vcldb;bindcompfmx;svn;Intraweb;inetdb;TMSCryptoPkgDXE11;RaizeComponentsVcl;vcwdedXE11;vcwdXE11;FmxTeeUI;emsedge;RaizeComponentsVclDb;fmx;fmxdae;frxDB25;tmsdXE11;RadiantShapesFmx;frxTee25;tmsexdXE11;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;fsTee25;IcsVclD102Run;VCLRESTComponents;IcsFmxD102Run;vclie;fs25;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;advchartdedxe11;AbkDBStdRAD10_2;vcl;IndyIPServer;IndySystem;FireDACDb2Driver;advchartdxe11;dsnapcon;inetwinsockets;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;fsADO25;TeeDB;vacommpkgdedXE11;emshosting;FireDACPgDriver;FireDACASADriver;frxADO25;FireDACTDataDriver;FMXTee;DbxCommonDriver;AsyncProDR;Tee;xmlrtl;frx25;fmxobj;vclwinx;FireDACDSDriver;rtl;DelphiModbus102Tokyo;DbxClientDriver;CustomIPTransport;vcldsnap;CodeSiteExpressPkg;fsDB25;bindcomp;appanalytics;tmswizdXE11;IndyIPClient;frxDBX25;bindcompvcl;TeeUI;TMSFMXPackPkgDXE11;dbxcds;VclSmp;adortl;FireDACODBCDriver;RadiantShapesFmx_Design;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;IcsCommonD102Run;TMSCryptoPkgDEDXE11;fmxase;$(DCC_UsePackage) 56 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 57 | Debug 58 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 59 | 1033 60 | true 61 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 62 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 63 | 64 | 65 | DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;AbkStdRAD10_2;tethering;FireDACADSDriver;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;inetdb;RaizeComponentsVcl;vcwdXE11;FmxTeeUI;emsedge;RaizeComponentsVclDb;fmx;fmxdae;tmsdXE11;RadiantShapesFmx;tmsexdXE11;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;IcsVclD102Run;VCLRESTComponents;IcsFmxD102Run;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;AbkDBStdRAD10_2;vcl;IndyIPServer;IndySystem;FireDACDb2Driver;advchartdxe11;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;emshosting;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;FMXTee;DbxCommonDriver;AsyncProDR;Tee;xmlrtl;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;IcsCommonD102Run;fmxase;$(DCC_UsePackage) 66 | true 67 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 68 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 69 | 70 | 71 | DEBUG;$(DCC_Define) 72 | true 73 | false 74 | true 75 | true 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | RELEASE;$(DCC_Define) 84 | 0 85 | 0 86 | 87 | 88 | 89 | MainSource 90 | 91 | 92 | Cfg_2 93 | Base 94 | 95 | 96 | Base 97 | 98 | 99 | Cfg_1 100 | Base 101 | 102 | 103 | 104 | Delphi.Personality.12 105 | Application 106 | 107 | 108 | 109 | SCPDemo.dpr 110 | 111 | 112 | 113 | 114 | 115 | true 116 | 117 | 118 | 119 | 120 | true 121 | 122 | 123 | 124 | 125 | true 126 | 127 | 128 | 129 | 130 | true 131 | 132 | 133 | 134 | 135 | SCPDemo.exe 136 | true 137 | 138 | 139 | 140 | 141 | 1 142 | 143 | 144 | Contents\MacOS 145 | 1 146 | 147 | 148 | Contents\MacOS 149 | 0 150 | 151 | 152 | 153 | 154 | classes 155 | 1 156 | 157 | 158 | 159 | 160 | library\lib\armeabi-v7a 161 | 1 162 | 163 | 164 | 165 | 166 | library\lib\armeabi 167 | 1 168 | 169 | 170 | 171 | 172 | library\lib\mips 173 | 1 174 | 175 | 176 | 177 | 178 | library\lib\armeabi-v7a 179 | 1 180 | 181 | 182 | 183 | 184 | res\drawable 185 | 1 186 | 187 | 188 | 189 | 190 | res\values 191 | 1 192 | 193 | 194 | 195 | 196 | res\drawable 197 | 1 198 | 199 | 200 | 201 | 202 | res\drawable-xxhdpi 203 | 1 204 | 205 | 206 | 207 | 208 | res\drawable-ldpi 209 | 1 210 | 211 | 212 | 213 | 214 | res\drawable-mdpi 215 | 1 216 | 217 | 218 | 219 | 220 | res\drawable-hdpi 221 | 1 222 | 223 | 224 | 225 | 226 | res\drawable-xhdpi 227 | 1 228 | 229 | 230 | 231 | 232 | res\drawable-small 233 | 1 234 | 235 | 236 | 237 | 238 | res\drawable-normal 239 | 1 240 | 241 | 242 | 243 | 244 | res\drawable-large 245 | 1 246 | 247 | 248 | 249 | 250 | res\drawable-xlarge 251 | 1 252 | 253 | 254 | 255 | 256 | 1 257 | 258 | 259 | Contents\MacOS 260 | 1 261 | 262 | 263 | 0 264 | 265 | 266 | 267 | 268 | Contents\MacOS 269 | 1 270 | .framework 271 | 272 | 273 | 0 274 | 275 | 276 | 277 | 278 | 1 279 | .dylib 280 | 281 | 282 | 1 283 | .dylib 284 | 285 | 286 | 1 287 | .dylib 288 | 289 | 290 | Contents\MacOS 291 | 1 292 | .dylib 293 | 294 | 295 | 0 296 | .dll;.bpl 297 | 298 | 299 | 300 | 301 | 1 302 | .dylib 303 | 304 | 305 | 1 306 | .dylib 307 | 308 | 309 | 1 310 | .dylib 311 | 312 | 313 | Contents\MacOS 314 | 1 315 | .dylib 316 | 317 | 318 | 0 319 | .bpl 320 | 321 | 322 | 323 | 324 | 0 325 | 326 | 327 | 0 328 | 329 | 330 | 0 331 | 332 | 333 | 0 334 | 335 | 336 | Contents\Resources\StartUp\ 337 | 0 338 | 339 | 340 | 0 341 | 342 | 343 | 344 | 345 | 1 346 | 347 | 348 | 1 349 | 350 | 351 | 1 352 | 353 | 354 | 355 | 356 | 1 357 | 358 | 359 | 1 360 | 361 | 362 | 1 363 | 364 | 365 | 366 | 367 | 1 368 | 369 | 370 | 1 371 | 372 | 373 | 1 374 | 375 | 376 | 377 | 378 | 1 379 | 380 | 381 | 1 382 | 383 | 384 | 1 385 | 386 | 387 | 388 | 389 | 1 390 | 391 | 392 | 1 393 | 394 | 395 | 1 396 | 397 | 398 | 399 | 400 | 1 401 | 402 | 403 | 1 404 | 405 | 406 | 1 407 | 408 | 409 | 410 | 411 | 1 412 | 413 | 414 | 1 415 | 416 | 417 | 1 418 | 419 | 420 | 421 | 422 | 1 423 | 424 | 425 | 426 | 427 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 428 | 1 429 | 430 | 431 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 432 | 1 433 | 434 | 435 | 436 | 437 | 1 438 | 439 | 440 | 1 441 | 442 | 443 | 444 | 445 | ..\ 446 | 1 447 | 448 | 449 | ..\ 450 | 1 451 | 452 | 453 | 454 | 455 | 1 456 | 457 | 458 | 1 459 | 460 | 461 | 1 462 | 463 | 464 | 465 | 466 | 1 467 | 468 | 469 | 1 470 | 471 | 472 | 1 473 | 474 | 475 | 476 | 477 | ..\ 478 | 1 479 | 480 | 481 | 482 | 483 | Contents 484 | 1 485 | 486 | 487 | 488 | 489 | Contents\Resources 490 | 1 491 | 492 | 493 | 494 | 495 | library\lib\armeabi-v7a 496 | 1 497 | 498 | 499 | 1 500 | 501 | 502 | 1 503 | 504 | 505 | 1 506 | 507 | 508 | 1 509 | 510 | 511 | Contents\MacOS 512 | 1 513 | 514 | 515 | 0 516 | 517 | 518 | 519 | 520 | 1 521 | 522 | 523 | 1 524 | 525 | 526 | 527 | 528 | Assets 529 | 1 530 | 531 | 532 | Assets 533 | 1 534 | 535 | 536 | 537 | 538 | Assets 539 | 1 540 | 541 | 542 | Assets 543 | 1 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | True 557 | False 558 | 559 | 560 | 12 561 | 562 | 563 | 564 | 565 | 566 | -------------------------------------------------------------------------------- /SCPDemo.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmaxeiner/TSSHCommand/fc24b7ca6844f0f1dcbe2258c3879675f6175c57/SCPDemo.res -------------------------------------------------------------------------------- /SSHCommand.pas: -------------------------------------------------------------------------------- 1 | unit SSHCommand; 2 | { 3 | unit : SSHCommand.pas 4 | Author : tmaxeiner 5 | License : MIT, see License file 6 | Version : 0.1 7 | } 8 | 9 | interface 10 | 11 | 12 | uses 13 | System.SysUtils, 14 | shellapi, 15 | Winapi.Windows; 16 | 17 | type 18 | TSSHCommand = record 19 | strict private 20 | FSSHClient : string; 21 | FHostName : string; 22 | FPortNum : integer; 23 | FUserName : string; 24 | FKeyFile : string; 25 | FCommand : string; 26 | FCommandParameter : string; 27 | FSource : string; 28 | FDestination : string; 29 | FSCPParameterLine : string; 30 | function GetPortNum : integer; 31 | procedure SetHostName( const Value : string ); 32 | procedure SetKeyFile( const Value : string ); 33 | procedure SetPortNum( const Value : integer ); 34 | procedure SetSSHClient( const Value : string ); 35 | procedure SetUserName( const Value : string ); 36 | private 37 | procedure SetCommand(const Value: string); 38 | procedure SetCommandParameter(const Value: string); 39 | procedure SetDestination(const Value: string); 40 | procedure SetSource(const Value: string); 41 | public 42 | /// 43 | /// Set a ssh client exe. Can be in application directory. 44 | /// Don't use original path in windows wich is 45 | /// c:\windows\system32\Openssh because it won't work with this wrapper! 46 | /// Leave blank if ssh.exe is in your application directory or in other searchpath. 47 | /// 48 | property SSHClient : string read FSSHClient write SetSSHClient; 49 | /// 50 | /// Hostname like www.excample.com or IP address. 51 | /// 52 | property HostName : string read FHostName write SetHostName; 53 | /// 54 | /// Leave blank if you use standard port 22. 55 | /// 56 | property PortNum : integer read GetPortNum write SetPortNum; 57 | /// 58 | /// Username on remote host. Needs login access rights. 59 | /// 60 | property UserName : string read FUserName write SetUserName; 61 | /// 62 | /// Full path of your private key file. 63 | /// 64 | property KeyFile : string read FKeyFile write SetKeyFile; 65 | /// 66 | /// Command to be run on remote host. 67 | /// 68 | property Command : string read FCommand write SetCommand; 69 | /// 70 | /// Command line parameter fpr the command to be run on remote host. 71 | /// 72 | property CommandParameter : string read FCommandParameter write SetCommandParameter; 73 | /// 74 | /// Destination for scp. 75 | /// This property is there for testing purpose. 76 | /// 77 | property Source : string read FSource write SetSource; 78 | /// 79 | /// Destination for scp. 80 | /// This property is there for testing purpose. 81 | /// 82 | property Destination : string read FDestination write SetDestination; 83 | /// 84 | /// Gives the parameter line for command execution. 85 | /// Can be used for testing. 86 | /// Set properties Source and Destionation first. 87 | /// 88 | function GetCommandParameterLine : string; 89 | /// 90 | /// Gives the parameter line for copy from remote action. 91 | /// Set properties Source and Destionation first. 92 | /// Can be used for testing. 93 | /// 94 | function GetSCPToRemoteParameterLine : string; 95 | /// 96 | /// Gives the parameter line for copy to remote action. 97 | /// Set properties Source and Destionation first. 98 | /// Can be used for testing. 99 | /// 100 | function GetSCPFromRemoteParameterLine : string; 101 | /// 102 | /// Send ACommand with AParameter to the remote host. 103 | /// All remote settings need to be set first. 104 | /// 105 | function SendCommand( const ACommand : string; const AParameter : string) : integer; 106 | /// 107 | /// Copy a local ASource to the remote host to ADestination. 108 | /// Uses scp. All remote settings need to be set first. 109 | /// If ADestination has trailing / then last part is a directory und filename of sourceparameter will copy into it. 110 | /// If ADestination has no trailing / then last part will be the new filename as copy destination. 111 | /// ASource can contain wildcards. Then give a trailing / as ADestination. 112 | /// 113 | function SCPToRemote( const ASource : string; const ADestination : string) : integer; 114 | /// 115 | /// Copy from ASource at remote host to a local ADestination 116 | /// All remote settings need to be set first. 117 | /// If ADestination has trailing / then last part is a directory und filename of sourceparameter will copy into it. 118 | /// If ADestination has no trailing / then last part will be the new filename as copy destination. 119 | /// ASource can contain wildcards. Then give a trailing / as ADestination. 120 | /// 121 | function SCPFromRemote( const ASource : string; const ADestination : string) : integer; 122 | end; 123 | 124 | 125 | 126 | implementation 127 | 128 | { TSSHCommand } 129 | 130 | {################################################################################################} 131 | 132 | function TSSHCommand.GetPortNum : integer; 133 | begin 134 | result := FPortNum; 135 | end; 136 | 137 | {################################################################################################} 138 | 139 | function TSSHCommand.GetSCPFromRemoteParameterLine: string; 140 | begin 141 | if FPortNum = 0 then FPortNum := 22; 142 | // scp -P 12322 -i keyfile user@remotehost:/home/user/file1.csv c:\tools\ 143 | result := '-P ' + 144 | FPortNum.ToString + 145 | ' -i ' + 146 | FKeyFile + 147 | ' ' + 148 | FUserName + 149 | '@' + 150 | FHostName + 151 | ':' + 152 | FSource + 153 | ' ' + 154 | FDestination; 155 | end; 156 | 157 | {################################################################################################} 158 | 159 | function TSSHCommand.GetSCPToRemoteParameterLine: string; 160 | begin 161 | if FPortNum = 0 then FPortNum := 22; 162 | // scp -P 12322 -i keyfile ASource user@remotehost:ADestination 163 | result := '-P ' + 164 | FPortNum.ToString + 165 | ' -i ' + 166 | FKeyFile + 167 | ' ' + 168 | FSource + 169 | ' ' + 170 | FUserName + 171 | '@' + 172 | FHostName + 173 | ':' + 174 | FDestination; 175 | end; 176 | 177 | {################################################################################################} 178 | 179 | function TSSHCommand.GetCommandParameterLine : string; 180 | begin 181 | if FPortNum = 0 then FPortNum := 22; 182 | // ssh remotehost -p 12322 -i keyfile -l user -t "command commandparameter" 183 | result := FHostName + 184 | ' -p ' + 185 | FPortNum.ToString + 186 | ' -i ' + 187 | FKeyFile + 188 | ' -l ' + 189 | FUserName + 190 | ' -t "' + 191 | FCommand + 192 | ' ' + 193 | FCommandParameter + '"'; 194 | end; 195 | 196 | {################################################################################################} 197 | 198 | function TSSHCommand.SCPFromRemote(const ASource, ADestination: string): integer; 199 | var 200 | LSCPParameterLine : string; 201 | begin 202 | if FSSHClient.IsEmpty then FSSHClient := 'scp.exe'; 203 | FSource := ASource; 204 | FDestination := ADestination; 205 | LSCPParameterLine := GetSCPFromRemoteParameterLine; 206 | result := ShellExecute( 0, 'open', PCHar( FSSHClient ), PCHar( LSCPParameterLine ), nil, SW_HIDE ); 207 | end; 208 | 209 | {################################################################################################} 210 | 211 | function TSSHCommand.SCPToRemote(const ASource, ADestination: string): integer; 212 | var 213 | LSCPParameterLine : string; 214 | begin 215 | if FSSHClient.IsEmpty then FSSHClient := 'scp.exe'; 216 | FSource := ASource; 217 | FDestination := ADestination; 218 | LSCPParameterLine := GetSCPToRemoteParameterLine; 219 | result := ShellExecute( 0, 'open', PCHar( FSSHClient ), PCHar( LSCPParameterLine ), nil, SW_HIDE ); 220 | end; 221 | 222 | {################################################################################################} 223 | 224 | function TSSHCommand.SendCommand ( const ACommand : string; const AParameter : string) : integer; 225 | var 226 | LCommandWithParameter : string; 227 | begin 228 | if FSSHClient.IsEmpty then FSSHClient := 'ssh.exe'; 229 | FCommand := ACommand; 230 | FCommandParameter := AParameter; 231 | LCommandWithParameter := GetCommandParameterLine; 232 | result := ShellExecute( 0, 'open', PCHar( FSSHClient ), PCHar( LCommandWithParameter ), nil, SW_HIDE ); 233 | end; 234 | 235 | {################################################################################################} 236 | 237 | procedure TSSHCommand.SetCommand(const Value: string); 238 | begin 239 | FCommand := Value; 240 | end; 241 | 242 | {################################################################################################} 243 | 244 | procedure TSSHCommand.SetCommandParameter(const Value: string); 245 | begin 246 | FCommandParameter := Value; 247 | end; 248 | 249 | {################################################################################################} 250 | 251 | procedure TSSHCommand.SetDestination(const Value: string); 252 | begin 253 | FDestination := Value; 254 | end; 255 | 256 | {################################################################################################} 257 | 258 | procedure TSSHCommand.SetHostName( const Value : string ); 259 | begin 260 | FHostName := Value; 261 | end; 262 | 263 | {################################################################################################} 264 | 265 | procedure TSSHCommand.SetKeyFile( const Value : string ); 266 | begin 267 | FKeyFile := Value; 268 | end; 269 | 270 | {################################################################################################} 271 | 272 | procedure TSSHCommand.SetPortNum( const Value : integer ); 273 | begin 274 | FPortNum := Value; 275 | end; 276 | 277 | {################################################################################################} 278 | 279 | procedure TSSHCommand.SetSource(const Value: string); 280 | begin 281 | FSource := Value; 282 | end; 283 | 284 | procedure TSSHCommand.SetSSHClient( const Value : string ); 285 | begin 286 | FSSHClient := Value; 287 | end; 288 | 289 | {################################################################################################} 290 | 291 | procedure TSSHCommand.SetUserName( const Value : string ); 292 | begin 293 | FUserName := Value; 294 | end; 295 | 296 | 297 | end. 298 | -------------------------------------------------------------------------------- /SSHCommandDemo.dpr: -------------------------------------------------------------------------------- 1 | program SSHCommandDemo; 2 | 3 | {$APPTYPE CONSOLE} 4 | 5 | {$R *.res} 6 | 7 | uses 8 | System.SysUtils, 9 | SSHCommand; 10 | 11 | var 12 | MySSHCommander : TSSHCommand; 13 | MyResult : integer; 14 | begin 15 | try 16 | MySSHCommander.HostName := 'www.example.com'; 17 | MySSHCommander.PortNum := 12322; 18 | MySSHCommander.UserName := 'myuser'; 19 | MySSHCommander.KeyFile := '~/.ssh/myuserkey'; 20 | 21 | MyResult := MySSHCommander.SendCommand( '~/testcommand.sh', 'newline123' ); 22 | if MyResult > 32 then Writeln('Command OK') 23 | else Writeln('Error Nr.: ' + MyResult.ToString); 24 | Writeln('Press Enter...'); 25 | Readln; 26 | except 27 | on E: Exception do 28 | Writeln(E.ClassName, ': ', E.Message); 29 | end; 30 | end. 31 | -------------------------------------------------------------------------------- /SSHCommandDemo.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {202634ED-F5FB-42B2-B949-79FE6D0F3FFB} 4 | 18.3 5 | None 6 | SSHCommandDemo.dpr 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Console 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | .\$(Platform)\$(Config) 44 | .\$(Platform)\$(Config) 45 | false 46 | false 47 | false 48 | false 49 | false 50 | RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACIBDriver;emsclient;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;aurelius;$(DCC_UsePackage) 51 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 52 | SSHCommandDemo 53 | 54 | 55 | DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;AbkStdRAD10_2;tethering;svnui;FireDACADSDriver;frxe25;vacommpkgdXE11;FireDACMSSQLDriver;hotxls250;vcltouch;tmsxlsdXE11;vcldb;bindcompfmx;svn;Intraweb;inetdb;TMSCryptoPkgDXE11;RaizeComponentsVcl;vcwdedXE11;vcwdXE11;FmxTeeUI;emsedge;RaizeComponentsVclDb;fmx;fmxdae;frxDB25;tmsdXE11;RadiantShapesFmx;frxTee25;tmsexdXE11;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;fsTee25;IcsVclD102Run;VCLRESTComponents;IcsFmxD102Run;vclie;fs25;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;advchartdedxe11;AbkDBStdRAD10_2;vcl;IndyIPServer;IndySystem;FireDACDb2Driver;advchartdxe11;dsnapcon;inetwinsockets;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;fsADO25;TeeDB;vacommpkgdedXE11;emshosting;FireDACPgDriver;FireDACASADriver;frxADO25;FireDACTDataDriver;FMXTee;DbxCommonDriver;AsyncProDR;Tee;xmlrtl;frx25;fmxobj;vclwinx;FireDACDSDriver;rtl;DelphiModbus102Tokyo;DbxClientDriver;CustomIPTransport;vcldsnap;CodeSiteExpressPkg;fsDB25;bindcomp;appanalytics;tmswizdXE11;IndyIPClient;frxDBX25;bindcompvcl;TeeUI;TMSFMXPackPkgDXE11;dbxcds;VclSmp;adortl;FireDACODBCDriver;RadiantShapesFmx_Design;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;IcsCommonD102Run;TMSCryptoPkgDEDXE11;fmxase;$(DCC_UsePackage) 56 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 57 | Debug 58 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 59 | 1033 60 | true 61 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 62 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 63 | 64 | 65 | DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;AbkStdRAD10_2;tethering;FireDACADSDriver;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;inetdb;RaizeComponentsVcl;vcwdXE11;FmxTeeUI;emsedge;RaizeComponentsVclDb;fmx;fmxdae;tmsdXE11;RadiantShapesFmx;tmsexdXE11;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;IcsVclD102Run;VCLRESTComponents;IcsFmxD102Run;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;AbkDBStdRAD10_2;vcl;IndyIPServer;IndySystem;FireDACDb2Driver;advchartdxe11;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;emshosting;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;FMXTee;DbxCommonDriver;AsyncProDR;Tee;xmlrtl;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;IcsCommonD102Run;fmxase;$(DCC_UsePackage) 66 | true 67 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png 68 | $(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png 69 | 70 | 71 | DEBUG;$(DCC_Define) 72 | true 73 | false 74 | true 75 | true 76 | true 77 | 78 | 79 | false 80 | 81 | 82 | false 83 | RELEASE;$(DCC_Define) 84 | 0 85 | 0 86 | 87 | 88 | 89 | MainSource 90 | 91 | 92 | Cfg_2 93 | Base 94 | 95 | 96 | Base 97 | 98 | 99 | Cfg_1 100 | Base 101 | 102 | 103 | 104 | Delphi.Personality.12 105 | Application 106 | 107 | 108 | 109 | SSHCommandDemo.dpr 110 | 111 | 112 | 113 | 114 | 115 | true 116 | 117 | 118 | 119 | 120 | true 121 | 122 | 123 | 124 | 125 | true 126 | 127 | 128 | 129 | 130 | true 131 | 132 | 133 | 134 | 135 | SSHCommandDemo.exe 136 | true 137 | 138 | 139 | 140 | 141 | 1 142 | 143 | 144 | Contents\MacOS 145 | 1 146 | 147 | 148 | Contents\MacOS 149 | 0 150 | 151 | 152 | 153 | 154 | classes 155 | 1 156 | 157 | 158 | 159 | 160 | library\lib\armeabi-v7a 161 | 1 162 | 163 | 164 | 165 | 166 | library\lib\armeabi 167 | 1 168 | 169 | 170 | 171 | 172 | library\lib\mips 173 | 1 174 | 175 | 176 | 177 | 178 | library\lib\armeabi-v7a 179 | 1 180 | 181 | 182 | 183 | 184 | res\drawable 185 | 1 186 | 187 | 188 | 189 | 190 | res\values 191 | 1 192 | 193 | 194 | 195 | 196 | res\drawable 197 | 1 198 | 199 | 200 | 201 | 202 | res\drawable-xxhdpi 203 | 1 204 | 205 | 206 | 207 | 208 | res\drawable-ldpi 209 | 1 210 | 211 | 212 | 213 | 214 | res\drawable-mdpi 215 | 1 216 | 217 | 218 | 219 | 220 | res\drawable-hdpi 221 | 1 222 | 223 | 224 | 225 | 226 | res\drawable-xhdpi 227 | 1 228 | 229 | 230 | 231 | 232 | res\drawable-small 233 | 1 234 | 235 | 236 | 237 | 238 | res\drawable-normal 239 | 1 240 | 241 | 242 | 243 | 244 | res\drawable-large 245 | 1 246 | 247 | 248 | 249 | 250 | res\drawable-xlarge 251 | 1 252 | 253 | 254 | 255 | 256 | 1 257 | 258 | 259 | Contents\MacOS 260 | 1 261 | 262 | 263 | 0 264 | 265 | 266 | 267 | 268 | Contents\MacOS 269 | 1 270 | .framework 271 | 272 | 273 | 0 274 | 275 | 276 | 277 | 278 | 1 279 | .dylib 280 | 281 | 282 | 1 283 | .dylib 284 | 285 | 286 | 1 287 | .dylib 288 | 289 | 290 | Contents\MacOS 291 | 1 292 | .dylib 293 | 294 | 295 | 0 296 | .dll;.bpl 297 | 298 | 299 | 300 | 301 | 1 302 | .dylib 303 | 304 | 305 | 1 306 | .dylib 307 | 308 | 309 | 1 310 | .dylib 311 | 312 | 313 | Contents\MacOS 314 | 1 315 | .dylib 316 | 317 | 318 | 0 319 | .bpl 320 | 321 | 322 | 323 | 324 | 0 325 | 326 | 327 | 0 328 | 329 | 330 | 0 331 | 332 | 333 | 0 334 | 335 | 336 | Contents\Resources\StartUp\ 337 | 0 338 | 339 | 340 | 0 341 | 342 | 343 | 344 | 345 | 1 346 | 347 | 348 | 1 349 | 350 | 351 | 1 352 | 353 | 354 | 355 | 356 | 1 357 | 358 | 359 | 1 360 | 361 | 362 | 1 363 | 364 | 365 | 366 | 367 | 1 368 | 369 | 370 | 1 371 | 372 | 373 | 1 374 | 375 | 376 | 377 | 378 | 1 379 | 380 | 381 | 1 382 | 383 | 384 | 1 385 | 386 | 387 | 388 | 389 | 1 390 | 391 | 392 | 1 393 | 394 | 395 | 1 396 | 397 | 398 | 399 | 400 | 1 401 | 402 | 403 | 1 404 | 405 | 406 | 1 407 | 408 | 409 | 410 | 411 | 1 412 | 413 | 414 | 1 415 | 416 | 417 | 1 418 | 419 | 420 | 421 | 422 | 1 423 | 424 | 425 | 426 | 427 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 428 | 1 429 | 430 | 431 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 432 | 1 433 | 434 | 435 | 436 | 437 | 1 438 | 439 | 440 | 1 441 | 442 | 443 | 444 | 445 | ..\ 446 | 1 447 | 448 | 449 | ..\ 450 | 1 451 | 452 | 453 | 454 | 455 | 1 456 | 457 | 458 | 1 459 | 460 | 461 | 1 462 | 463 | 464 | 465 | 466 | 1 467 | 468 | 469 | 1 470 | 471 | 472 | 1 473 | 474 | 475 | 476 | 477 | ..\ 478 | 1 479 | 480 | 481 | 482 | 483 | Contents 484 | 1 485 | 486 | 487 | 488 | 489 | Contents\Resources 490 | 1 491 | 492 | 493 | 494 | 495 | library\lib\armeabi-v7a 496 | 1 497 | 498 | 499 | 1 500 | 501 | 502 | 1 503 | 504 | 505 | 1 506 | 507 | 508 | 1 509 | 510 | 511 | Contents\MacOS 512 | 1 513 | 514 | 515 | 0 516 | 517 | 518 | 519 | 520 | 1 521 | 522 | 523 | 1 524 | 525 | 526 | 527 | 528 | Assets 529 | 1 530 | 531 | 532 | Assets 533 | 1 534 | 535 | 536 | 537 | 538 | Assets 539 | 1 540 | 541 | 542 | Assets 543 | 1 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | True 557 | False 558 | 559 | 560 | 12 561 | 562 | 563 | 564 | 565 | 566 | -------------------------------------------------------------------------------- /SSHCommandDemo.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmaxeiner/TSSHCommand/fc24b7ca6844f0f1dcbe2258c3879675f6175c57/SSHCommandDemo.res -------------------------------------------------------------------------------- /TSSHCommand.groupproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {7B23765E-BF50-4CDF-B0CC-E011FA0BB03D} 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | Default.Personality.12 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Test/Test.dpr: -------------------------------------------------------------------------------- 1 | program Test; 2 | 3 | {$IFNDEF TESTINSIGHT} 4 | {$APPTYPE CONSOLE} 5 | {$ENDIF}{$STRONGLINKTYPES ON} 6 | uses 7 | System.SysUtils, 8 | {$IFDEF TESTINSIGHT} 9 | TestInsight.DUnitX, 10 | {$ENDIF } 11 | DUnitX.Loggers.Console, 12 | DUnitX.Loggers.Xml.NUnit, 13 | DUnitX.TestFramework, 14 | uTest in 'uTest.pas', 15 | SSHCommand in '..\SSHCommand.pas'; 16 | 17 | var 18 | runner : ITestRunner; 19 | results : IRunResults; 20 | logger : ITestLogger; 21 | nunitLogger : ITestLogger; 22 | begin 23 | {$IFDEF TESTINSIGHT} 24 | TestInsight.DUnitX.RunRegisteredTests; 25 | exit; 26 | {$ENDIF} 27 | try 28 | //Check command line options, will exit if invalid 29 | TDUnitX.CheckCommandLine; 30 | //Create the test runner 31 | runner := TDUnitX.CreateRunner; 32 | //Tell the runner to use RTTI to find Fixtures 33 | runner.UseRTTI := True; 34 | //tell the runner how we will log things 35 | //Log to the console window 36 | logger := TDUnitXConsoleLogger.Create(true); 37 | runner.AddLogger(logger); 38 | //Generate an NUnit compatible XML File 39 | nunitLogger := TDUnitXXMLNUnitFileLogger.Create(TDUnitX.Options.XMLOutputFile); 40 | runner.AddLogger(nunitLogger); 41 | runner.FailsOnNoAsserts := False; //When true, Assertions must be made during tests; 42 | 43 | //Run tests 44 | results := runner.Execute; 45 | if not results.AllPassed then 46 | System.ExitCode := EXIT_ERRORS; 47 | 48 | {$IFNDEF CI} 49 | //We don't want this happening when running under CI. 50 | if TDUnitX.Options.ExitBehavior = TDUnitXExitBehavior.Pause then 51 | begin 52 | System.Write('Done.. press key to quit.'); 53 | System.Readln; 54 | end; 55 | {$ENDIF} 56 | except 57 | on E: Exception do 58 | System.Writeln(E.ClassName, ': ', E.Message); 59 | end; 60 | end. 61 | -------------------------------------------------------------------------------- /Test/Test.dproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | {54792C7C-9F68-46A3-902F-B76AD9F2D1C4} 4 | 18.3 5 | None 6 | Test.dpr 7 | True 8 | Debug 9 | Win32 10 | 1 11 | Console 12 | 13 | 14 | true 15 | 16 | 17 | true 18 | Base 19 | true 20 | 21 | 22 | true 23 | Base 24 | true 25 | 26 | 27 | true 28 | Base 29 | true 30 | 31 | 32 | true 33 | Cfg_1 34 | true 35 | true 36 | 37 | 38 | true 39 | Base 40 | true 41 | 42 | 43 | .\$(Platform)\$(Config) 44 | .\$(Platform)\$(Config) 45 | false 46 | false 47 | false 48 | false 49 | false 50 | RESTComponents;emsclientfiredac;DataSnapFireDAC;FireDACIBDriver;emsclient;FireDACCommon;RESTBackendComponents;soapserver;CloudService;FireDACCommonDriver;inet;FireDAC;FireDACSqliteDriver;soaprtl;soapmidas;aurelius;$(DCC_UsePackage) 51 | System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace) 52 | true 53 | $(BDS)\bin\delphi_PROJECTICON.ico 54 | $(BDS)\bin\delphi_PROJECTICNS.icns 55 | $(DUnitX);$(DCC_UnitSearchPath) 56 | Test 57 | 58 | 59 | DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;AbkStdRAD10_2;tethering;svnui;FireDACADSDriver;frxe25;vacommpkgdXE11;FireDACMSSQLDriver;hotxls250;vcltouch;tmsxlsdXE11;vcldb;bindcompfmx;svn;Intraweb;inetdb;TMSCryptoPkgDXE11;RaizeComponentsVcl;vcwdedXE11;vcwdXE11;FmxTeeUI;emsedge;RaizeComponentsVclDb;fmx;fmxdae;frxDB25;tmsdXE11;RadiantShapesFmx;frxTee25;tmsexdXE11;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;fsTee25;IcsVclD102Run;VCLRESTComponents;IcsFmxD102Run;vclie;fs25;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;advchartdedxe11;AbkDBStdRAD10_2;vcl;IndyIPServer;IndySystem;FireDACDb2Driver;advchartdxe11;dsnapcon;inetwinsockets;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;fsADO25;TeeDB;vacommpkgdedXE11;emshosting;FireDACPgDriver;FireDACASADriver;frxADO25;FireDACTDataDriver;FMXTee;DbxCommonDriver;AsyncProDR;Tee;xmlrtl;frx25;fmxobj;vclwinx;FireDACDSDriver;rtl;DelphiModbus102Tokyo;DbxClientDriver;CustomIPTransport;vcldsnap;CodeSiteExpressPkg;fsDB25;bindcomp;appanalytics;tmswizdXE11;IndyIPClient;frxDBX25;bindcompvcl;TeeUI;TMSFMXPackPkgDXE11;dbxcds;VclSmp;adortl;FireDACODBCDriver;RadiantShapesFmx_Design;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;IcsCommonD102Run;TMSCryptoPkgDEDXE11;fmxase;$(DCC_UsePackage) 60 | Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) 61 | Debug 62 | CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments= 63 | 1033 64 | 65 | 66 | DBXSqliteDriver;DBXInterBaseDriver;vclactnband;vclFireDAC;AbkStdRAD10_2;tethering;FireDACADSDriver;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;inetdb;RaizeComponentsVcl;vcwdXE11;FmxTeeUI;emsedge;RaizeComponentsVclDb;fmx;fmxdae;tmsdXE11;RadiantShapesFmx;tmsexdXE11;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;IcsVclD102Run;VCLRESTComponents;IcsFmxD102Run;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;FireDACMySQLDriver;FireDACCommonODBC;DataSnapClient;IndyIPCommon;bindcompdbx;AbkDBStdRAD10_2;vcl;IndyIPServer;IndySystem;FireDACDb2Driver;advchartdxe11;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;TeeDB;emshosting;FireDACPgDriver;FireDACASADriver;FireDACTDataDriver;FMXTee;DbxCommonDriver;AsyncProDR;Tee;xmlrtl;fmxobj;vclwinx;FireDACDSDriver;rtl;DbxClientDriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;IndyIPClient;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;FireDACODBCDriver;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;FireDACMongoDBDriver;IcsCommonD102Run;fmxase;$(DCC_UsePackage) 67 | 68 | 69 | DEBUG;$(DCC_Define) 70 | true 71 | false 72 | true 73 | true 74 | true 75 | 76 | 77 | false 78 | 79 | 80 | false 81 | RELEASE;$(DCC_Define) 82 | 0 83 | 0 84 | 85 | 86 | 87 | MainSource 88 | 89 | 90 | 91 | 92 | Cfg_2 93 | Base 94 | 95 | 96 | Base 97 | 98 | 99 | Cfg_1 100 | Base 101 | 102 | 103 | 104 | Delphi.Personality.12 105 | Console 106 | 107 | 108 | 109 | Test.dpr 110 | 111 | 112 | 113 | 114 | 115 | true 116 | 117 | 118 | 119 | 120 | true 121 | 122 | 123 | 124 | 125 | true 126 | 127 | 128 | 129 | 130 | true 131 | 132 | 133 | 134 | 135 | Test.exe 136 | true 137 | 138 | 139 | 140 | 141 | 1 142 | 143 | 144 | Contents\MacOS 145 | 0 146 | 147 | 148 | 149 | 150 | classes 151 | 1 152 | 153 | 154 | 155 | 156 | library\lib\armeabi-v7a 157 | 1 158 | 159 | 160 | 161 | 162 | library\lib\armeabi 163 | 1 164 | 165 | 166 | 167 | 168 | library\lib\mips 169 | 1 170 | 171 | 172 | 173 | 174 | library\lib\armeabi-v7a 175 | 1 176 | 177 | 178 | 179 | 180 | res\drawable 181 | 1 182 | 183 | 184 | 185 | 186 | res\values 187 | 1 188 | 189 | 190 | 191 | 192 | res\drawable 193 | 1 194 | 195 | 196 | 197 | 198 | res\drawable-xxhdpi 199 | 1 200 | 201 | 202 | 203 | 204 | res\drawable-ldpi 205 | 1 206 | 207 | 208 | 209 | 210 | res\drawable-mdpi 211 | 1 212 | 213 | 214 | 215 | 216 | res\drawable-hdpi 217 | 1 218 | 219 | 220 | 221 | 222 | res\drawable-xhdpi 223 | 1 224 | 225 | 226 | 227 | 228 | res\drawable-small 229 | 1 230 | 231 | 232 | 233 | 234 | res\drawable-normal 235 | 1 236 | 237 | 238 | 239 | 240 | res\drawable-large 241 | 1 242 | 243 | 244 | 245 | 246 | res\drawable-xlarge 247 | 1 248 | 249 | 250 | 251 | 252 | 1 253 | 254 | 255 | 1 256 | 257 | 258 | 0 259 | 260 | 261 | 262 | 263 | 1 264 | .framework 265 | 266 | 267 | 0 268 | 269 | 270 | 271 | 272 | 1 273 | .dylib 274 | 275 | 276 | 0 277 | .dll;.bpl 278 | 279 | 280 | 281 | 282 | 1 283 | .dylib 284 | 285 | 286 | 1 287 | .dylib 288 | 289 | 290 | 1 291 | .dylib 292 | 293 | 294 | 1 295 | .dylib 296 | 297 | 298 | 0 299 | .bpl 300 | 301 | 302 | 303 | 304 | 0 305 | 306 | 307 | 0 308 | 309 | 310 | 0 311 | 312 | 313 | 0 314 | 315 | 316 | 0 317 | 318 | 319 | 0 320 | 321 | 322 | 323 | 324 | 1 325 | 326 | 327 | 1 328 | 329 | 330 | 1 331 | 332 | 333 | 334 | 335 | 1 336 | 337 | 338 | 1 339 | 340 | 341 | 1 342 | 343 | 344 | 345 | 346 | 1 347 | 348 | 349 | 1 350 | 351 | 352 | 1 353 | 354 | 355 | 356 | 357 | 1 358 | 359 | 360 | 1 361 | 362 | 363 | 1 364 | 365 | 366 | 367 | 368 | 1 369 | 370 | 371 | 1 372 | 373 | 374 | 1 375 | 376 | 377 | 378 | 379 | 1 380 | 381 | 382 | 1 383 | 384 | 385 | 1 386 | 387 | 388 | 389 | 390 | 1 391 | 392 | 393 | 1 394 | 395 | 396 | 1 397 | 398 | 399 | 400 | 401 | 1 402 | 403 | 404 | 405 | 406 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 407 | 1 408 | 409 | 410 | ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF 411 | 1 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 1 420 | 421 | 422 | 1 423 | 424 | 425 | 1 426 | 427 | 428 | 429 | 430 | 431 | 432 | Contents\Resources 433 | 1 434 | 435 | 436 | 437 | 438 | library\lib\armeabi-v7a 439 | 1 440 | 441 | 442 | 1 443 | 444 | 445 | 1 446 | 447 | 448 | 1 449 | 450 | 451 | 1 452 | 453 | 454 | 1 455 | 456 | 457 | 0 458 | 459 | 460 | 461 | 462 | 1 463 | 464 | 465 | 1 466 | 467 | 468 | 469 | 470 | Assets 471 | 1 472 | 473 | 474 | Assets 475 | 1 476 | 477 | 478 | 479 | 480 | Assets 481 | 1 482 | 483 | 484 | Assets 485 | 1 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | True 499 | False 500 | 501 | 502 | 12 503 | 504 | 505 | 506 | 507 | 508 | -------------------------------------------------------------------------------- /Test/Test.res: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmaxeiner/TSSHCommand/fc24b7ca6844f0f1dcbe2258c3879675f6175c57/Test/Test.res -------------------------------------------------------------------------------- /Test/uTest.pas: -------------------------------------------------------------------------------- 1 | unit uTest; 2 | 3 | interface 4 | uses 5 | DUnitX.TestFramework, 6 | SSHCommand; 7 | 8 | type 9 | 10 | [TestFixture] 11 | TMyTestObject = class(TObject) 12 | public 13 | [Setup] 14 | procedure Setup; 15 | [TearDown] 16 | procedure TearDown; 17 | [TEST] 18 | procedure TestParameterLineCommandStandardPort; 19 | [TEST] 20 | procedure TestParameterLineCommandOtherPort; 21 | [TEST] 22 | procedure TestParameterLineSCPToRemoteStandardPort; 23 | [TEST] 24 | procedure TestParameterLineSCPFromRemoteStandardPort; 25 | end; 26 | 27 | implementation 28 | 29 | procedure TMyTestObject.Setup; 30 | begin 31 | end; 32 | 33 | procedure TMyTestObject.TearDown; 34 | begin 35 | end; 36 | 37 | procedure TMyTestObject.TestParameterLineSCPFromRemoteStandardPort; 38 | var 39 | LSSHCommander : TSSHCommand; 40 | LGoodLine : string; 41 | begin 42 | LSSHCommander.HostName := 'example.com'; 43 | LSSHCommander.UserName := 'myuser'; 44 | LSSHCommander.KeyFile := '~/.ssh/mykey'; 45 | LSSHCommander.Source := '/home/myuser/list1.txt'; 46 | LSSHCommander.Destination := 'c:\Users\bill\'; 47 | // scp -P 22 -i keyfile user@remotehost:/home/myuser/file1.csv c:\tools\ 48 | LGoodLine := '-P 22 -i ~/.ssh/mykey myuser@example.com:/home/myuser/list1.txt c:\Users\bill\'; 49 | Assert.AreEqual(LGoodLine, LSSHCommander.GetSCPFromRemoteParameterLine, 'Parameterlist scp from remote standardport incorrect'); 50 | end; 51 | 52 | procedure TMyTestObject.TestParameterLineSCPToRemoteStandardPort; 53 | var 54 | LSSHCommander : TSSHCommand; 55 | LGoodLine : string; 56 | begin 57 | LSSHCommander.HostName := 'example.com'; 58 | LSSHCommander.UserName := 'myuser'; 59 | LSSHCommander.KeyFile := '~/.ssh/mykey'; 60 | LSSHCommander.Source := 'c:\Users\bill\list1.txt'; 61 | LSSHCommander.Destination := '/home/myuser/list2.txt'; 62 | // scp -P 22 -i keyfile c:\Users\bill\list1.txt user@remotehost:/home/myuser/file1.csv 63 | LGoodLine := '-P 22 -i ~/.ssh/mykey c:\Users\bill\list1.txt myuser@example.com:/home/myuser/list2.txt'; 64 | Assert.AreEqual(LGoodLine, LSSHCommander.GetSCPToRemoteParameterLine, 'Parameterlist scp to remote standardport incorrect'); 65 | end; 66 | 67 | procedure TMyTestObject.TestParameterLineCommandOtherPort; 68 | var 69 | LSSHCommander : TSSHCommand; 70 | LGoodLine : string; 71 | begin 72 | LSSHCommander.HostName := 'example.com'; 73 | LSSHCommander.UserName := 'myuser'; 74 | LSSHCommander.PortNum := 12322; 75 | LSSHCommander.KeyFile := '~/.ssh/mykey'; 76 | LSSHCommander.Command := 'MyCommand'; 77 | LSSHCommander.CommandParameter := 'DoNothing'; 78 | // ssh remotehost -p 12322 -i keyfile -l user -t "command commandparameter" 79 | LGoodline := 'example.com -p 12322 -i ~/.ssh/mykey -l myuser -t "MyCommand DoNothing"'; 80 | Assert.AreEqual(LGoodLine, LSSHCommander.GetCommandParameterLine, 'Parameterlist Command other port incorrect'); 81 | end; 82 | 83 | procedure TMyTestObject.TestParameterLineCommandStandardPort; 84 | var 85 | LSSHCommander : TSSHCommand; 86 | LGoodLine : string; 87 | begin 88 | LSSHCommander.HostName := 'example.com'; 89 | LSSHCommander.UserName := 'myuser'; 90 | LSSHCommander.KeyFile := '~/.ssh/mykey'; 91 | LSSHCommander.Command := 'MyCommand'; 92 | LSSHCommander.CommandParameter := 'DoNothing'; 93 | // ssh remotehost -p 22 -i keyfile -l user -t "command commandparameter" 94 | LGoodline := 'example.com -p 22 -i ~/.ssh/mykey -l myuser -t "MyCommand DoNothing"'; 95 | Assert.AreEqual(LGoodLine, LSSHCommander.GetCommandParameterLine, 'Parameterlist Command standardport incorrect'); 96 | end; 97 | 98 | initialization 99 | TDUnitX.RegisterTestFixture(TMyTestObject); 100 | end. 101 | -------------------------------------------------------------------------------- /Thorsten Maxeiner Vortrag ssh Forentage 2019.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tmaxeiner/TSSHCommand/fc24b7ca6844f0f1dcbe2258c3879675f6175c57/Thorsten Maxeiner Vortrag ssh Forentage 2019.pdf --------------------------------------------------------------------------------