DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel  •  DevOps · K8s · Volleyball · Travel
Explore NY Stream

How to step up SSL log transfer - Windows

— ny_wk

How to step up SSL log transfer - Windows

Setting up automated SSL log transfer on Windows means collecting your web, application, and event logs on a schedule, packaging them, and pushing them to a remote collector over an encrypted SFTP connection. This guide walks through the full pipeline end to end — a log-capture script, secure key-based authentication, a service account, and a Scheduled Task — and replaces the brittle legacy pieces (Cygwin SSHD, WinZip command line, PsLogList) with the modern, built-in Windows equivalents so the setup keeps working for years.

The problem this solves

Compliance, security monitoring, and troubleshooting all depend on getting logs off the server that produced them and onto a central, tamper-resistant store. Many Windows application servers — think IBM WebSphere, HTTP Server, MQ link processes, and the Windows Event Log itself — write logs to local disk where they rotate away or get lost if the box fails.

The goal of SSL log transfer on Windows is to automate three things: collect the day's logs from every relevant directory, compress them into a single dated archive, and transfer them securely to a remote server over SFTP, with zero manual steps and no plaintext passwords on disk.

What you need before you start

  • A Windows Server box that hosts the applications whose logs you are collecting.
  • OpenSSH client — ships with Windows Server 2019/2022 and Windows 10/11 (the sftp.exe and ssh-keygen.exe binaries live in C:\Windows\System32\OpenSSH\). This replaces the old Cygwin sftp/ssh-keygen build entirely.
  • An SFTP destination — the remote collector's hostname/IP, port (22 by default), the target upload path, and the username you'll authenticate as.
  • A dedicated service account with local administrator rights (only if a step genuinely needs them — prefer least privilege) to own the Scheduled Task.
  • Network reachability to the collector on the SFTP port, plus any static route your data-out NIC requires.

Legacy note: the original procedure relied on Cygwin SSHD, the WinZip wzzip command-line tool, and Sysinternals psloglist. All three still function but are unnecessary today — Windows now bundles OpenSSH, PowerShell can read the Event Log and create ZIP archives natively, and Cygwin's mkpasswd/mkgroup account-sync dance is no longer needed because you are not running a Cygwin SSH server; you are only acting as an SFTP client.

Step-by-step: build the SSL log transfer pipeline

  1. Confirm the OpenSSH client is installed. Open an elevated PowerShell and run Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH.Client*'. If the state is not Installed, run Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0.
  2. Create or designate a service account. Use a domain or local account such as svc_logxfer, give it only the permissions it needs (read on the log folders, write on the staging folder), and use a long random password or a Group Managed Service Account (gMSA). Add it to the local Administrators group only if a collection step truly requires elevation.
  3. Log in as the service account once interactively (or use runas) so you can generate its SSH key under its own profile — keys are per-user.
  4. Add the static route to the data-out NIC if your network design requires the traffic to leave a specific interface. The persistent route command is route add -p 10.225.3.73 mask 255.255.255.255 <gateway-ip> metric 1. The -p flag makes it survive reboots; replace the gateway with your real next hop.
  5. Generate an SSH key pair for key-based authentication (no passwords in scripts): ssh-keygen -t ed25519 -C "svc_logxfer@loghost". Ed25519 is the modern default; use -t rsa -b 4096 only if the remote server is old and lacks Ed25519 support. Press Enter for the default path (%USERPROFILE%\.ssh\id_ed25519).
  6. Send the public key to the SFTP server administrator. Hand over only the .pub file (e.g. id_ed25519.pub) — never the private key. The remote admin appends it to the target user's ~/.ssh/authorized_keys.
  7. Place the log-capture script in a permanent, non-temporary location — for example D:\AutoLogTrans\. Never run it from C:\temp, which can be cleaned out from under you.
  8. Write the SFTP batch (command) file that tells the client what to upload (see the script section below).
  9. Create a Scheduled Task that runs the capture script daily as the service account (covered below).
  10. Test the task manually, then verify by logging into the collector and confirming the dated archive arrived intact.

The log-capture script (modern PowerShell)

The legacy version was a Windows batch file that built a date-stamped folder, robocopied each log directory into it, dumped Event Logs to CSV with psloglist, zipped the lot with wzzip, and called sftp -b. The PowerShell rewrite below does the same job with no third-party tools, correct date handling, and proper error checking. Save it as D:\AutoLogTrans\Collect-Logs.ps1.

The original batch built its date string with for /F "tokens=2-4 delims=/" %%i in ('date /t'), which silently breaks on any machine whose locale isn't MM/DD/YYYY. PowerShell's Get-Date -Format is locale-proof.

  1. Define a stable date stamp and a staging root:
    $stamp = Get-Date -Format 'yyyyMMdd'
    $root = "D:\AutoLogTrans\staging\$stamp"
    New-Item -ItemType Directory -Force -Path $root | Out-Null
  2. Copy each source log folder using robocopy (still the right tool for resilient copies). Only grab files changed in the last day with /MAXAGE:1 and retry sparingly with /R:1 /W:5:
    robocopy "D:\Program Files\IBM\WebSphere\AppServer\profiles\AppSrv01\logs\Clone1" "$root\WebSphere" *.* /MAXAGE:1 /R:1 /W:5
    robocopy "D:\WireLinkMQ\Link_B\logs" "$root\Link_B" *.* /MAXAGE:1 /R:1 /W:5
    Repeat one line per source directory. Important fix: robocopy's /MAXAGE takes a number of days (1) or a date, not the yyyyMMdd stamp the legacy script passed — feeding it the full date stamp meant it copied almost nothing.
  3. Export the Windows Event Logs to CSV natively, instead of psloglist:
    Get-WinEvent -FilterHashtable @{LogName='Application'; StartTime=(Get-Date).AddHours(-24)} | Export-Csv "$root\AppEvtLog_$stamp.csv" -NoTypeInformation
    Get-WinEvent -FilterHashtable @{LogName='System'; StartTime=(Get-Date).AddHours(-24)} | Export-Csv "$root\SystemLog_$stamp.csv" -NoTypeInformation
    Add the Security log the same way only if the account has the audit-read right.
  4. Compress everything into one archive with the built-in cmdlet — no WinZip needed:
    $zip = "D:\AutoLogTrans\outbox\DLU_App1_${stamp}_logfiles.zip"
    Compress-Archive -Path "$root\*" -DestinationPath $zip -Force
  5. Upload over SFTP using the batch command file and key auth:
    sftp -i "$env:USERPROFILE\.ssh\id_ed25519" -b "D:\AutoLogTrans\sftp_commands.txt" sftpuser@10.225.3.73
  6. Clean up the staging folder after a confirmed upload:
    Remove-Item -Recurse -Force $root

Wrap the upload in a check on $LASTEXITCODE so you only delete the staging copy if SFTP returned 0 — otherwise you lose the only copy of a log set that never made it across.

The SFTP command file

The SFTP client's -b (batch) flag reads commands from a text file and runs non-interactively — exactly what a Scheduled Task needs. Create D:\AutoLogTrans\sftp_commands.txt:

  1. lcd D:\AutoLogTrans\outbox — set the local directory to where the ZIP lives.
  2. cd /opt/IBM/HTTPServer/logdir/logfiles/DLU — change to the remote upload path.
  3. put *.zip — upload every archive in the local outbox.
  4. bye — close the session cleanly.

Because authentication is key-based, no password ever appears in this file. On the very first connection, run sftp once interactively as the service account so the collector's host key is recorded in known_hosts; otherwise the batch run will hang or fail on the unknown-host prompt. To pre-seed it non-interactively, use ssh-keyscan 10.225.3.73 >> "$env:USERPROFILE\.ssh\known_hosts" — but verify the fingerprint with the remote admin first.

Create the Scheduled Task

Run the capture script on a schedule as the service account. Do this from an elevated PowerShell so the task is registered correctly:

  1. Define the action — PowerShell running your script with no profile and a bypassed execution policy for this one process only:
    $action = New-ScheduledTaskAction -Execute 'powershell.exe' -Argument '-NoProfile -ExecutionPolicy Bypass -File "D:\AutoLogTrans\Collect-Logs.ps1"'
  2. Define the trigger — e.g. every day at 01:15:
    $trigger = New-ScheduledTaskTrigger -Daily -At 1:15AM
  3. Register the task under the service account, running whether or not the user is logged on:
    Register-ScheduledTask -TaskName 'SSL Log SFTP Transfer' -Action $action -Trigger $trigger -User 'DOMAIN\svc_logxfer' -Password '<password>' -RunLevel Highest

For a gMSA, drop the password and pass -LogonType Password via a New-ScheduledTaskPrincipal with the gMSA's name instead — that keeps secrets out of your provisioning history entirely.

Common pitfalls to avoid

  • Running from a temp folder. Scripts and staging directories under C:\temp can be wiped by cleanup tools mid-run. Keep everything under a dedicated, permanent path.
  • Locale-dependent date parsing. The legacy date /t token trick produces a wrong or empty folder name on non-US locales. Use Get-Date -Format 'yyyyMMdd'.
  • Wrong /MAXAGE value. Passing a yyyyMMdd stamp where robocopy expects a day count copies nothing. Use /MAXAGE:1 for "last 24 hours."
  • Unknown host key hangs the batch. A first-time SFTP connection prompts to trust the host key; in a Scheduled Task there's no one to answer. Pre-populate known_hosts.
  • Storing passwords in scripts. Always use SSH key authentication. A private key with correct NTFS permissions beats an embedded password every time.
  • Deleting before confirming upload. Only remove the staging/outbox copy after $LASTEXITCODE -eq 0, or a failed transfer destroys your only copy.
  • The task runs but "does nothing." Almost always a permissions issue — the service account can't read a source log folder or can't write the outbox. Check the task's Last Run Result and the script's own log.

Verification: confirm SSL log transfer is working

Don't trust a green "task completed" — verify the data actually landed. Work through these checks:

  1. Run the task on demand: Start-ScheduledTask -TaskName 'SSL Log SFTP Transfer', then check the result with Get-ScheduledTaskInfo -TaskName 'SSL Log SFTP Transfer'. A LastTaskResult of 0 means success.
  2. Confirm the archive built locally by listing the outbox: a fresh DLU_App1_<date>_logfiles.zip with a non-trivial size should be present.
  3. Log into the collector and list the remote upload directory. Compare the file size and timestamp against the local copy.
  4. Validate the archive integrity on the remote side (e.g. unzip -t on Linux) so you know it transferred without corruption.
  5. Test key auth in isolation: ssh -i ~/.ssh/id_ed25519 sftpuser@10.225.3.73 should connect without asking for a password. If it prompts, the public key isn't installed correctly on the server.

Below is a quick reference mapping every legacy tool to its modern, built-in Windows replacement.

Legacy approachModern equivalent
Cygwin sftp / ssh-keygenBuilt-in Windows OpenSSH client
Cygwin SSHD + mkpasswd/mkgroupNot needed (acting as SFTP client only)
psloglist (Sysinternals)Get-WinEvent + Export-Csv
wzzip (WinZip CLI)Compress-Archive
Batch date /t parsingGet-Date -Format 'yyyyMMdd'
Password in scriptSSH key-based authentication

Key Takeaways

  • SSL log transfer on Windows = collect, compress, and push logs to a remote collector over SFTP on a schedule, with no manual steps.
  • Use the built-in OpenSSH client and PowerShell (Get-WinEvent, Compress-Archive) instead of legacy Cygwin, PsLogList, and WinZip tooling.
  • Always authenticate with an SSH key pair, hand over only the public key, and pre-seed known_hosts so batch transfers never hang.
  • Run the capture script as a least-privilege service account via a Scheduled Task, from a permanent (never temp) folder.
  • Only delete staged logs after confirming $LASTEXITCODE -eq 0, and always verify the archive landed and is intact on the collector.

Frequently Asked Questions

Do I still need Cygwin to run SFTP on Windows?

No. Modern Windows Server (2019/2022) and Windows 10/11 include the OpenSSH client with sftp.exe and ssh-keygen.exe in C:\Windows\System32\OpenSSH\. Install it via Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0 if it isn't already present. You only needed Cygwin in the past because Windows shipped no native SSH tooling.

How do I run an SFTP transfer with no password in a scheduled job?

Generate an SSH key pair with ssh-keygen -t ed25519, give the public key to the remote administrator to add to authorized_keys, and point the client at your private key with sftp -i <keyfile> -b <commandfile> user@host. Key-based auth runs unattended and keeps secrets out of scripts.

Why does my Scheduled Task succeed but transfer no files?

The two usual causes are permissions and date filtering. Confirm the service account can read every source log folder and write the outbox, and check that robocopy's /MAXAGE:1 isn't excluding everything because the logs are older than a day. The task's Last Run Result plus your own script log will pinpoint it.

What's the difference between SFTP and FTPS for log transfer?

SFTP runs over a single SSH connection (port 22) and is firewall-friendly and key-authenticated, which is why it's preferred here. FTPS is FTP wrapped in TLS/SSL and uses multiple ports, making it harder to firewall. Both encrypt data in transit; SFTP is simpler to automate on Windows with the OpenSSH client.

If this walkthrough helped, subscribe to @explorenystream on YouTube for more practical Windows sysadmin and automation guides.