How to Execute Remote Commands on Windows Server from Linux for SQL Server DB Restoration


5 views

When managing hybrid environments, administrators often need to execute commands on Windows machines from Linux systems. A common scenario is restoring SQL Server databases from backup files stored on remote Windows servers. While Windows-native tools like PowerShell Remoting are available, Linux requires alternative approaches.

The most reliable method involves PowerShell Core (pwsh), Microsoft's cross-platform shell:

# Install PowerShell Core on Linux
wget -q https://aka.ms/install-powershell.sh -O /tmp/install-powershell.sh
sudo bash /tmp/install-powershell.sh
pwsh

Once installed, you can establish a remote session:

$session = New-PSSession -ComputerName win-server -Credential (Get-Credential)
Invoke-Command -Session $session -ScriptBlock {
    sqlcmd -S localhost -Q "RESTORE DATABASE [YourDB] FROM DISK = 'C:\backups\db.bak' WITH REPLACE"
}
Remove-PSSession $session

For environments without PowerShell Core, pywinrm provides Python-based Windows Remote Management:

pip install pywinrm

import winrm
session = winrm.Session('win-server', auth=('username', 'password'))
result = session.run_ps('''
    sqlcmd -S localhost -Q "RESTORE DATABASE [YourDB] FROM DISK = 'C:\\backups\\db.bak' WITH REPLACE"
''')
print(result.status_code, result.std_out)

When implementing remote execution:

  • Always use encrypted connections (HTTPS/WinRM over SSL)
  • Implement certificate-based authentication when possible
  • Restrict remote management to specific IP ranges
  • Use service accounts with minimal required privileges

If you encounter access denied errors:

# On Windows server, check WinRM configuration
winrm quickconfig
Enable-PSRemoting -Force
Set-NetFirewallRule -Name "WINRM-HTTP-In-TCP" -RemoteAddress Any

As a developer working in mixed environments, I recently faced a scenario where I needed to trigger a SQL Server database restoration on a Windows Server from my Linux development machine. The standard Windows remote protocols don't always play nicely with Linux, creating an interesting technical challenge.

After extensive testing, these are the most reliable approaches:


# Method 1: Using PowerShell Remoting (requires WinRM configuration)
$ ssh user@linux_host "echo 'Invoke-Command -ComputerName WIN_SERVER -ScriptBlock { Restore-SqlDatabase -ServerInstance \"SQL_INSTANCE\" -Database \"DB_NAME\" -BackupFile \"\\\\path\\to\\backup.bak\" -ReplaceDatabase }' | pwsh -"

Before using PowerShell remoting, ensure WinRM is properly configured:


# On Windows Server (run as Administrator):
Enable-PSRemoting -Force
Set-Item WSMan:\localhost\Client\TrustedHosts "linux_host" -Force
Restart-Service WinRM

Windows now includes an OpenSSH server that can be enabled:


# On Windows Server (Administrator PowerShell):
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
Start-Service sshd
Set-Service -Name sshd -StartupType 'Automatic'

# Then from Linux:
ssh administrator@windows_server "sqlcmd -Q \"RESTORE DATABASE [DB_NAME] FROM DISK = N'C:\\backups\\db.bak' WITH FILE = 1, NOUNLOAD, STATS = 5\""

For older environments where WinRM isn't available:


# Install winexe on Linux (Debian/Ubuntu):
sudo apt-get install winexe

# Execute remote command:
winexe -U 'domain\user%password' //windows_server "cmd.exe /c \"sqlcmd -Q \\\"RESTORE DATABASE [DB_NAME] FROM DISK = N'C:\\backups\\db.bak'\\\"\""

Always consider security implications when implementing remote execution:

  • Use certificate-based authentication where possible
  • Restrict access with firewalls
  • Implement just-in-time access for production systems
  • Consider using Ansible or other configuration management tools for better audit trails

Here's a robust implementation with proper error handling:


#!/bin/bash

REMOTE_USER="admin"
REMOTE_SERVER="windows-server.domain.com"
SQL_INSTANCE="SQLSERVER01"
DB_NAME="ProductionDB"
BACKUP_PATH="\\\\network\\share\\backup.bak"

# Execute via SSH with PowerShell
ssh $REMOTE_USER@$REMOTE_SERVER << 'EOF'
try {
    $RestoreResult = Restore-SqlDatabase -ServerInstance "$env:SQL_INSTANCE" 
        -Database "$env:DB_NAME" 
        -BackupFile "$env:BACKUP_PATH" 
        -ReplaceDatabase 
        -ErrorAction Stop
    
    Write-Output "Restore completed successfully"
    Write-Output $RestoreResult
    exit 0
}
catch {
    Write-Error "Restore failed: $_"
    exit 1
}
EOF

if [ $? -eq 0 ]; then
    echo "Database restoration completed"
else
    echo "Restoration failed" >&2
    exit 1
fi