Initial commit

This commit is contained in:
2026-04-24 17:41:53 +08:00
commit 7105e8b165
94 changed files with 8141 additions and 0 deletions

View File

@@ -0,0 +1,174 @@
#!/usr/bin/env python3
"""
Benchmark SSH vs WinRM performance
Compares execution times and capabilities
"""
import time
import subprocess
import os
from winrm import Session
def benchmark_ssh_method():
"""Benchmark SSH-based script execution"""
print("=== SSH Method Benchmark ===")
start_time = time.time()
try:
# Run a simple recon via SSH
result = subprocess.run(
['timeout', '30', './recon.sh'],
capture_output=True,
text=True,
timeout=35
)
end_time = time.time()
duration = end_time - start_time
if result.returncode == 0:
print(f"✅ SSH method successful")
print(f"⏱️ Execution time: {duration:.2f} seconds")
return duration, True
else:
print(f"❌ SSH method failed: {result.stderr}")
return duration, False
except subprocess.TimeoutExpired:
print(f"❌ SSH method timed out after 35 seconds")
return 35, False
except Exception as e:
end_time = time.time()
duration = end_time - start_time
print(f"❌ SSH method error: {e}")
return duration, False
def benchmark_winrm_method():
"""Benchmark WinRM-based script execution"""
print("\n=== WinRM Method Benchmark ===")
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
start_time = time.time()
try:
# Connect to WinRM
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ntlm'
)
# Run equivalent recon commands via WinRM
recon_script = """
Write-Host ""
Write-Host "======== Computer ========"
Get-ComputerInfo -Property CsName,WindowsProductName,OsVersion,OsInstallDate | Format-List
Write-Host "======== Boot Time ========"
(Get-CimInstance Win32_OperatingSystem).LastBootUpTime
Write-Host "======== Local Users ========"
Get-LocalUser | Select-Object Name,Enabled,LastLogon | Format-Table -AutoSize
Write-Host "======== Disks ========"
Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter,FileSystemLabel,
@{n='Size(GB)';e={[math]::Round($_.Size / 1GB, 1)}},
@{n='Free(GB)';e={[math]::Round($_.SizeRemaining / 1GB, 1)}} | Format-Table -AutoSize
Write-Host "======== IPv4 Addresses ========"
Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.InterfaceAlias -notmatch 'Loopback' } |
Select-Object InterfaceAlias,IPAddress | Format-Table -AutoSize
Write-Host "======== WinRM Recon Completed ========"
"""
result = session.run_ps(recon_script)
end_time = time.time()
duration = end_time - start_time
if result.status_code == 0:
print(f"✅ WinRM method successful")
print(f"⏱️ Execution time: {duration:.2f} seconds")
# Show some output
output = result.std_out.decode('utf-8', errors='replace')
lines = [line.strip() for line in output.split('\n') if line.strip()]
print(f"📊 Output lines: {len(lines)}")
return duration, True
else:
print(f"❌ WinRM method failed: {result.std_err.decode()}")
return duration, False
except Exception as e:
end_time = time.time()
duration = end_time - start_time
print(f"❌ WinRM method error: {e}")
return duration, False
def main():
print("🚀 SSH vs WinRM Performance Benchmark")
print("=====================================")
# Benchmark SSH
ssh_time, ssh_success = benchmark_ssh_method()
# Benchmark WinRM
winrm_time, winrm_success = benchmark_winrm_method()
# Results comparison
print("\n📊 RESULTS COMPARISON")
print("=====================")
print(f"SSH Method: {ssh_time:.2f}s {'' if ssh_success else ''}")
print(f"WinRM Method: {winrm_time:.2f}s {'' if winrm_success else ''}")
if ssh_success and winrm_success:
if ssh_time < winrm_time:
speedup = winrm_time / ssh_time
print(f"\n🏃 SSH is {speedup:.1f}x faster than WinRM")
else:
speedup = ssh_time / winrm_time
print(f"\n🏃 WinRM is {speedup:.1f}x faster than SSH")
print(f"\nTime difference: {abs(ssh_time - winrm_time):.2f} seconds")
print("\n🎯 RECOMMENDATION")
print("=================")
if ssh_success and winrm_success:
if ssh_time < winrm_time * 1.5: # If SSH is not significantly slower
print("✅ Continue using SSH method:")
print(" - Proven stability")
print(" - Good performance")
print(" - Handles large scripts well")
print(" - Simpler setup")
else:
print("✅ Consider WinRM method for:")
print(" - Better Windows integration")
print(" - Advanced PowerShell features")
print(" - Structured error handling")
elif ssh_success:
print("✅ SSH method is more reliable for this environment")
elif winrm_success:
print("✅ WinRM method works, SSH has issues")
else:
print("❌ Both methods have issues, investigate connectivity")
print("\n💡 HYBRID APPROACH")
print("==================")
print("Consider using both methods strategically:")
print("- SSH: Large scripts, file operations, stability")
print("- WinRM: Quick commands, Windows-specific tasks, real-time interaction")
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,154 @@
#!/usr/bin/env python3
"""
Generate WinRM wrapper scripts for existing PowerShell scripts
Creates Python WinRM alternatives to SSH-based scripts
"""
import os
import sys
from pathlib import Path
import json
def create_winrm_wrapper(ps_script_name, description=""):
"""Create a Python WinRM wrapper for a PowerShell script"""
script_name_base = ps_script_name.replace('.ps1', '')
wrapper_name = f"{script_name_base}-winrm.py"
template = f'''#!/usr/bin/env python3
"""
WinRM version of {ps_script_name}
{description}
"""
import os
import sys
from winrm_executor import WinRMExecutor
from pathlib import Path
def main():
# Get connection details
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"=== WinRM Execution: {{username}}@{{host}} - {ps_script_name} ===")
# Create WinRM executor
executor = WinRMExecutor(host, username, password)
try:
# Test connection
print("[*] Establishing WinRM connection...")
if not executor.connect():
print("❌ Failed to establish WinRM connection")
print("\\nTroubleshooting:")
print(" 1. Ensure target machine is powered on and reachable")
print(" 2. Verify WinRM service is running")
print(" 3. Check firewall and network connectivity")
sys.exit(1)
print("✅ WinRM connection established")
# Execute PowerShell script
script_path = Path(__file__).parent / "{ps_script_name}"
if not script_path.exists():
print(f"❌ PowerShell script not found: {{script_path}}")
sys.exit(1)
print(f"[*] Executing {ps_script_name} via WinRM...")
print("=" * 60)
success = executor.upload_and_execute_script(script_path)
print("=" * 60)
if success:
print(f"🎉 {{script_path.name}} completed successfully via WinRM!")
else:
print(f"{{script_path.name}} failed")
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()
'''
return wrapper_name, template
def main():
current_dir = Path(__file__).parent
# List of PowerShell scripts and their descriptions
scripts = {
'recon.ps1': 'System reconnaissance and inventory',
'activate-windows.ps1': 'Activate Windows using KMS method',
'remove-windows-ai.ps1': 'Remove Windows AI components',
'win11debloat.ps1': 'Remove Windows bloatware and disable telemetry',
'verify-ai-removed.ps1': 'Verify Windows AI removal',
'verify-debloat.ps1': 'Verify Windows debloating changes',
'install-thunderbird.ps1': 'Install Thunderbird email client',
'setup-thunderbird.ps1': 'Configure Thunderbird IMAP/SMTP',
'install-telegram.ps1': 'Install Telegram Desktop',
'install-nirsoft.ps1': 'Install NirSoft diagnostic tools',
'nirsoft-dump.ps1': 'Collect system diagnostic data',
'firewall-allow-ssh.ps1': 'Configure firewall for SSH access',
'apply-ui-to-user.ps1': 'Apply UI settings to user',
'configure-ime.ps1': 'Configure input method settings',
'rename-hide-accounts.ps1': 'Rename and hide user accounts',
'install-cports.ps1': 'Install CurrPorts network tool',
'remove-apps.ps1': 'Remove specified applications'
}
print("=== Generating WinRM Wrapper Scripts ===")
print()
created_count = 0
for ps_script, description in scripts.items():
ps_path = current_dir / ps_script
if ps_path.exists():
wrapper_name, wrapper_content = create_winrm_wrapper(ps_script, description)
wrapper_path = current_dir / wrapper_name
# Only create if it doesn't exist or user confirms overwrite
if wrapper_path.exists():
response = input(f"⚠️ {wrapper_name} exists. Overwrite? [y/N]: ")
if response.lower() != 'y':
print(f"⏭️ Skipping {wrapper_name}")
continue
with open(wrapper_path, 'w', encoding='utf-8') as f:
f.write(wrapper_content)
# Make executable
wrapper_path.chmod(0o755)
print(f"✅ Created: {wrapper_name}")
created_count += 1
else:
print(f"⚠️ PowerShell script not found: {ps_script}")
print()
print(f"🎉 Generated {created_count} WinRM wrapper scripts")
print()
print("Usage examples:")
print(" python3 recon-winrm.py")
print(" HOST=pc-74269 python3 install-thunderbird-winrm.py")
print(" USER_NAME=SomeUser python3 apply-ui-to-user-winrm.py")
print()
print("Benefits of WinRM approach:")
print(" ✅ Native Windows remote management")
print(" ✅ Better PowerShell integration")
print(" ✅ Structured error handling")
print(" ✅ Automatic UTF-8 BOM handling for Chinese Windows")
print(" ✅ Detailed logging and progress reporting")
if __name__ == "__main__":
main()

61
scripts/winrm/recon-winrm.py Executable file
View File

@@ -0,0 +1,61 @@
#!/usr/bin/env python3
"""
WinRM version of recon script
Demonstrates how to replace SSH-based scripts with Python WinRM
"""
import os
import sys
from winrm_executor import WinRMExecutor
from pathlib import Path
def main():
# Get connection details
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"=== WinRM Reconnaissance: {username}@{host} ===")
# Create WinRM executor
executor = WinRMExecutor(host, username, password)
try:
# Test connection
print("[*] Establishing WinRM connection...")
if not executor.connect():
print("❌ Failed to establish WinRM connection")
print("\nTroubleshooting:")
print(" 1. Ensure target machine is powered on and reachable")
print(" 2. Verify WinRM service is running: Get-Service WinRM")
print(" 3. Check AllowUnencrypted setting: winrm get winrm/config/service")
print(" 4. Verify firewall rules: Get-NetFirewallRule -DisplayGroup '*Remote Management*'")
sys.exit(1)
print("✅ WinRM connection established")
# Execute recon script
script_path = Path(__file__).parent / "../powershell/recon.ps1"
if not script_path.exists():
print(f"❌ PowerShell script not found: {script_path}")
sys.exit(1)
print(f"[*] Executing reconnaissance script via WinRM...")
print("=" * 60)
success = executor.upload_and_execute_script(script_path)
print("=" * 60)
if success:
print("🎉 Reconnaissance completed successfully via WinRM!")
else:
print("❌ Reconnaissance failed")
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()

172
scripts/winrm/smart_executor.py Executable file
View File

@@ -0,0 +1,172 @@
#!/usr/bin/env python3
"""
Smart Executor - Automatically choose between SSH and WinRM
Based on script size and complexity
"""
import os
import sys
import subprocess
from pathlib import Path
from winrm import Session
class SmartExecutor:
def __init__(self, host=None, username=None, password=None):
self.host = host or os.getenv('HOST', '192.168.88.108')
self.username = username or os.getenv('USER_NAME', 'Admin')
self.password = password or os.getenv('PASS', 'P@ssw0rd!')
def analyze_script(self, script_path):
"""Analyze script to determine best execution method"""
script_path = Path(script_path)
if not script_path.exists():
return None
# Get script size
size = script_path.stat().st_size
# Read content for analysis
with open(script_path, 'r', encoding='utf-8') as f:
content = f.read()
lines = len(content.split('\n'))
chars = len(content)
analysis = {
'size_bytes': size,
'lines': lines,
'characters': chars,
'has_file_operations': any(keyword in content.lower() for keyword in
['out-file', 'copy-item', 'move-item', 'new-item', 'remove-item']),
'has_long_commands': any(len(line) > 500 for line in content.split('\n')),
'complexity_score': lines + (chars / 100) + (size / 1000)
}
return analysis
def choose_method(self, script_path):
"""Choose optimal execution method"""
analysis = self.analyze_script(script_path)
if not analysis:
return "error"
# Decision logic
if analysis['size_bytes'] > 5000: # Large scripts
return "ssh"
elif analysis['lines'] > 100: # Many lines
return "ssh"
elif analysis['has_file_operations']: # File operations
return "ssh"
elif analysis['has_long_commands']: # Very long command lines
return "ssh"
elif analysis['complexity_score'] > 150: # Complex scripts
return "ssh"
else:
return "winrm" # Simple, fast execution
def execute_via_ssh(self, script_path):
"""Execute script using SSH method"""
script_name = Path(script_path).stem
ssh_script = f"{script_name}.sh"
if not Path(ssh_script).exists():
print(f"❌ SSH wrapper {ssh_script} not found")
return False
try:
result = subprocess.run([f'./{ssh_script}'], capture_output=False, timeout=300)
return result.returncode == 0
except Exception as e:
print(f"❌ SSH execution failed: {e}")
return False
def execute_via_winrm(self, script_path):
"""Execute script using WinRM method"""
try:
# Read and execute script content directly
with open(script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
# Connect via WinRM
session = Session(
f'http://{self.host}:5985/wsman',
auth=(self.username, self.password),
transport='ntlm'
)
# Execute PowerShell
result = session.run_ps(script_content)
# Output results
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
return result.status_code == 0
except Exception as e:
print(f"❌ WinRM execution failed: {e}")
return False
def execute(self, script_path):
"""Smart execute with automatic method selection"""
script_path = Path(script_path)
print(f"🧠 Analyzing script: {script_path.name}")
analysis = self.analyze_script(script_path)
method = self.choose_method(script_path)
print(f"📊 Script analysis:")
print(f" Size: {analysis['size_bytes']} bytes")
print(f" Lines: {analysis['lines']}")
print(f" Complexity: {analysis['complexity_score']:.1f}")
print(f" File operations: {analysis['has_file_operations']}")
print(f"⚡ Selected method: {method.upper()}")
if method == "ssh":
print("🔗 Executing via SSH (for large/complex scripts)")
return self.execute_via_ssh(script_path)
elif method == "winrm":
print("⚡ Executing via WinRM (for speed)")
return self.execute_via_winrm(script_path)
else:
print("❌ Unable to determine execution method")
return False
def main():
if len(sys.argv) != 2:
print("Usage: python3 smart_executor.py <script.ps1>")
sys.exit(1)
script_path = sys.argv[1]
executor = SmartExecutor()
print("🎯 Smart PowerShell Executor")
print("============================")
success = executor.execute(script_path)
if success:
print(f"\n✅ Script execution completed successfully")
else:
print(f"\n❌ Script execution failed")
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,97 @@
#!/usr/bin/env python3
"""
Test simple WinRM script execution
Uses very small commands to avoid length limits
"""
import os
from winrm import Session
def test_simple_script_execution():
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"Testing simple WinRM script execution on {host}")
try:
# Connect
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ntlm'
)
# Test 1: Simple inline PowerShell
print("\n[Test 1] Running simple inline PowerShell:")
simple_ps = """
Write-Host "=== Simple WinRM Test ==="
Write-Host "Computer: $env:COMPUTERNAME"
Write-Host "User: $env:USERNAME"
Write-Host "PowerShell: $($PSVersionTable.PSVersion)"
Write-Host "Time: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Host "=== End Test ==="
"""
result = session.run_ps(simple_ps)
if result.status_code == 0:
print("✅ Simple PowerShell execution successful:")
output = result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(f" {line.strip()}")
else:
print(f"❌ Simple PowerShell failed: {result.std_err.decode()}")
return False
# Test 2: Create small script file
print("\n[Test 2] Creating and executing small script file:")
# Create a very small script
create_script = """
$scriptContent = @'
Write-Host "Small script test"
Get-ComputerInfo -Property CsName, WindowsProductName | Format-List
Write-Host "Small script completed"
'@
$scriptContent | Out-File -FilePath 'C:\\Users\\Admin\\small_test.ps1' -Encoding UTF8
Write-Host "Small script file created"
"""
result = session.run_ps(create_script)
if result.status_code == 0:
print("✅ Script file created successfully")
# Execute the small script
exec_result = session.run_cmd('powershell -NoProfile -ExecutionPolicy Bypass -File C:\\Users\\Admin\\small_test.ps1')
if exec_result.status_code == 0:
print("✅ Script execution successful:")
output = exec_result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(f" {line.strip()}")
return True
else:
print(f"❌ Script execution failed: {exec_result.std_err.decode()}")
return False
else:
print(f"❌ Script creation failed: {result.std_err.decode()}")
return False
except Exception as e:
print(f"❌ Test failed: {e}")
return False
if __name__ == "__main__":
if test_simple_script_execution():
print("\n🎉 Simple WinRM script execution works!")
print("This proves WinRM can execute PowerShell scripts.")
print("The issue is with large script handling, not basic functionality.")
else:
print("\n❌ Basic WinRM functionality failed")

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python3
"""
Test WinRM with Negotiate authentication (instead of Basic)
"""
import os
from winrm import Session
def test_negotiate_auth():
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print(f"Testing WinRM with Negotiate authentication to {host}")
try:
# Try with negotiate/ntlm transport
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ntlm' # Use NTLM instead of plaintext
)
print("✅ Session created with NTLM transport")
# Test simple command
result = session.run_cmd('echo "NTLM test successful"')
if result.status_code == 0:
print(f"✅ Command successful: {result.std_out.decode().strip()}")
return True
else:
print(f"❌ Command failed: {result.std_err.decode()}")
return False
except Exception as e:
print(f"❌ NTLM authentication failed: {e}")
# Try with ssl transport (even though we're using HTTP)
try:
print("Trying with SSL transport (ignore cert validation)...")
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='ssl',
server_cert_validation='ignore'
)
print("✅ Session created with SSL transport")
result = session.run_cmd('echo "SSL transport test"')
if result.status_code == 0:
print(f"✅ Command successful: {result.std_out.decode().strip()}")
return True
else:
print(f"❌ Command failed: {result.std_err.decode()}")
return False
except Exception as e2:
print(f"❌ SSL transport also failed: {e2}")
# Try with kerberos if available
try:
print("Trying with Kerberos transport...")
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='kerberos'
)
print("✅ Session created with Kerberos transport")
result = session.run_cmd('echo "Kerberos test"')
if result.status_code == 0:
print(f"✅ Command successful: {result.std_out.decode().strip()}")
return True
else:
print(f"❌ Command failed: {result.std_err.decode()}")
return False
except Exception as e3:
print(f"❌ Kerberos transport failed: {e3}")
return False
if __name__ == "__main__":
success = test_negotiate_auth()
if success:
print("\n🎉 Alternative authentication method works!")
else:
print("\n❌ All authentication methods failed")
print("\nThis suggests the issue is with AllowUnencrypted=false")
print("We may need to force this setting or use HTTPS instead")

View File

@@ -0,0 +1,192 @@
#!/usr/bin/env python3
"""
Python WinRM Connection Test
Tests WinRM connectivity using pywinrm library
"""
import os
import sys
from winrm.protocol import Protocol
from winrm import Session
import xml.etree.ElementTree as ET
def test_basic_connection(host, username, password):
"""Test basic WinRM connectivity"""
print(f"[1/4] Testing basic WinRM protocol connection to {host}...")
try:
# Create a basic protocol connection
endpoint = f"http://{host}:5985/wsman"
p = Protocol(
endpoint=endpoint,
transport='plaintext',
username=username,
password=password
)
# Try a simple identify operation
result = p.send_message(
'<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:wsmid="http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd">'
'<s:Header></s:Header>'
'<s:Body>'
'<wsmid:Identify/>'
'</s:Body>'
'</s:Envelope>'
)
print("✅ Basic WinRM protocol connection successful")
# Parse response to get some info
try:
root = ET.fromstring(result)
for elem in root.iter():
if 'ProductVersion' in elem.tag:
print(f" Protocol Version: {elem.text}")
elif 'ProductVendor' in elem.tag:
print(f" Product Vendor: {elem.text}")
except:
pass
return True
except Exception as e:
print(f"❌ Basic connection failed: {e}")
return False
def test_session_connection(host, username, password):
"""Test WinRM session connectivity"""
print(f"\n[2/4] Testing WinRM session connection...")
try:
session = Session(
f'http://{host}:5985/wsman',
auth=(username, password),
transport='plaintext'
)
print("✅ WinRM session created successfully")
return session
except Exception as e:
print(f"❌ Session creation failed: {e}")
return None
def test_command_execution(session):
"""Test basic command execution"""
print(f"\n[3/4] Testing command execution...")
try:
# Test simple command
result = session.run_cmd('echo "Hello from WinRM"')
if result.status_code == 0:
print("✅ Command execution successful")
print(f" Output: {result.std_out.decode().strip()}")
else:
print(f"⚠️ Command execution completed with exit code: {result.status_code}")
print(f" Error: {result.std_err.decode().strip()}")
return True
except Exception as e:
print(f"❌ Command execution failed: {e}")
return False
def test_powershell_execution(session):
"""Test PowerShell script execution"""
print(f"\n[4/4] Testing PowerShell execution...")
try:
# Test PowerShell command
ps_script = """
$info = @{
ComputerName = $env:COMPUTERNAME
UserName = $env:USERNAME
PowerShellVersion = $PSVersionTable.PSVersion.ToString()
WindowsVersion = (Get-ComputerInfo -Property WindowsProductName).WindowsProductName
CurrentTime = Get-Date -Format 'yyyy-MM-dd HH:mm:ss'
}
Write-Host "=== Remote System Information ==="
Write-Host "Computer: $($info.ComputerName)"
Write-Host "User: $($info.UserName)"
Write-Host "PowerShell: $($info.PowerShellVersion)"
Write-Host "Windows: $($info.WindowsVersion)"
Write-Host "Time: $($info.CurrentTime)"
Write-Host "=== End Information ==="
"""
result = session.run_ps(ps_script)
if result.status_code == 0:
print("✅ PowerShell execution successful")
print("Remote system info:")
output = result.std_out.decode().strip()
for line in output.split('\n'):
if line.strip():
print(f" {line.strip()}")
else:
print(f"⚠️ PowerShell execution completed with exit code: {result.status_code}")
if result.std_err:
print(f" Error: {result.std_err.decode().strip()}")
return True
except Exception as e:
print(f"❌ PowerShell execution failed: {e}")
return False
def main():
# Get connection details from environment or use defaults
host = os.getenv('HOST', '192.168.88.108')
username = os.getenv('USER_NAME', 'Admin')
password = os.getenv('PASS', 'P@ssw0rd!')
print("=== Python WinRM Connection Test ===")
print(f"Target: {username}@{host}")
print("")
# Test sequence
success = True
# Test 1: Basic connection
if not test_basic_connection(host, username, password):
success = False
print("\n If basic connection fails, ensure:")
print(" - WinRM service is running on target")
print(" - Port 5985 is accessible")
print(" - AllowUnencrypted=true for HTTP connections")
sys.exit(1)
# Test 2: Session creation
session = test_session_connection(host, username, password)
if not session:
success = False
sys.exit(1)
# Test 3: Command execution
if not test_command_execution(session):
success = False
# Test 4: PowerShell execution
if not test_powershell_execution(session):
success = False
if success:
print(f"\n🎉 All tests passed! Python WinRM is working correctly.")
print(f"\nNext steps:")
print(f" 1. Create Python WinRM wrapper for existing scripts")
print(f" 2. Compare performance with SSH method")
print(f" 3. Implement error handling and logging")
else:
print(f"\n⚠️ Some tests failed. Check configuration and try again.")
sys.exit(1)
if __name__ == "__main__":
main()

250
scripts/winrm/winrm_executor.py Executable file
View File

@@ -0,0 +1,250 @@
#!/usr/bin/env python3
"""
WinRM Script Executor
A Python-based alternative to SSH for executing PowerShell scripts on Windows machines.
"""
import os
import sys
import argparse
import json
import time
from datetime import datetime
from pathlib import Path
from winrm import Session
import logging
class WinRMExecutor:
def __init__(self, host, username, password, port=5985, use_https=False):
self.host = host
self.username = username
self.password = password
self.port = port
self.use_https = use_https
self.session = None
# Setup logging
self.setup_logging()
def setup_logging(self):
"""Setup logging configuration"""
log_dir = Path(__file__).parent / "../../logs"
log_dir.mkdir(exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
log_file = log_dir / f"winrm-{self.host}-{timestamp}.log"
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
self.logger.info(f"Starting WinRM session to {self.host}")
def connect(self):
"""Establish WinRM connection"""
try:
protocol = 'https' if self.use_https else 'http'
endpoint = f'{protocol}://{self.host}:{self.port}/wsman'
self.logger.info(f"Connecting to {endpoint}")
self.session = Session(
endpoint,
auth=(self.username, self.password),
transport='ntlm' if not self.use_https else 'ssl',
server_cert_validation='ignore' if self.use_https else 'validate'
)
# Test connection with a simple command
result = self.session.run_cmd('echo Connection test')
if result.status_code == 0:
self.logger.info("✅ WinRM connection established successfully")
return True
else:
self.logger.error(f"❌ Connection test failed: {result.std_err.decode()}")
return False
except Exception as e:
self.logger.error(f"❌ Failed to connect: {e}")
return False
def upload_and_execute_script(self, local_script_path, remote_script_name=None):
"""Upload and execute a PowerShell script"""
if not self.session:
self.logger.error("No active WinRM session")
return False
try:
# Read the local script
with open(local_script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
# Generate remote script name if not provided
if not remote_script_name:
script_name = Path(local_script_path).name
remote_script_name = f"C:\\Users\\{self.username}\\{script_name}"
self.logger.info(f"Uploading script: {local_script_path} -> {remote_script_name}")
# Create the script on remote machine
create_script = f"""
$scriptContent = @'
{script_content}
'@
# Ensure UTF-8 encoding with BOM for Chinese Windows
$utf8BOM = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllText('{remote_script_name}', $scriptContent, $utf8BOM)
Write-Host "Script uploaded to {remote_script_name}"
"""
upload_result = self.session.run_ps(create_script)
if upload_result.status_code != 0:
self.logger.error(f"Failed to upload script: {upload_result.std_err.decode()}")
return False
self.logger.info("✅ Script uploaded successfully")
# Execute the script
self.logger.info(f"Executing PowerShell script: {remote_script_name}")
execute_command = f"PowerShell -NoProfile -ExecutionPolicy Bypass -File '{remote_script_name}'"
result = self.session.run_cmd(execute_command)
# Output results
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
self.logger.info("Script Output:")
for line in output.split('\n'):
if line.strip():
print(line)
self.logger.info(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
self.logger.warning("Script Errors:")
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
self.logger.warning(line)
success = result.status_code == 0
status = "✅ SUCCESS" if success else f"❌ FAILED (exit code: {result.status_code})"
self.logger.info(f"Script execution completed: {status}")
return success
except Exception as e:
self.logger.error(f"❌ Script execution failed: {e}")
return False
def execute_command(self, command, use_powershell=False):
"""Execute a single command"""
if not self.session:
self.logger.error("No active WinRM session")
return False
try:
self.logger.info(f"Executing command: {command}")
if use_powershell:
result = self.session.run_ps(command)
else:
result = self.session.run_cmd(command)
# Output results
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
for line in output.split('\n'):
if line.strip():
print(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
return result.status_code == 0
except Exception as e:
self.logger.error(f"Command execution failed: {e}")
return False
def close(self):
"""Close the WinRM session"""
if self.session:
self.logger.info("Closing WinRM session")
# Note: pywinrm doesn't have an explicit close method
self.session = None
def main():
parser = argparse.ArgumentParser(description='Execute PowerShell scripts via WinRM')
parser.add_argument('--host', default=os.getenv('HOST', '192.168.88.108'),
help='Target host (default: from HOST env var or 192.168.88.108)')
parser.add_argument('--username', default=os.getenv('USER_NAME', 'Admin'),
help='Username (default: from USER_NAME env var or Admin)')
parser.add_argument('--password', default=os.getenv('PASS', 'P@ssw0rd!'),
help='Password (default: from PASS env var)')
parser.add_argument('--port', type=int, default=5985,
help='WinRM port (default: 5985)')
parser.add_argument('--https', action='store_true',
help='Use HTTPS instead of HTTP')
parser.add_argument('--script', required=True,
help='PowerShell script file to execute')
parser.add_argument('--test-connection', action='store_true',
help='Test connection only, do not execute script')
args = parser.parse_args()
# Create executor
executor = WinRMExecutor(
host=args.host,
username=args.username,
password=args.password,
port=args.port,
use_https=args.https
)
try:
# Connect
if not executor.connect():
print("❌ Failed to establish WinRM connection")
sys.exit(1)
if args.test_connection:
print("✅ WinRM connection test successful")
return
# Execute script
script_path = Path(args.script)
if not script_path.exists():
print(f"❌ Script file not found: {script_path}")
sys.exit(1)
success = executor.upload_and_execute_script(script_path)
if success:
print(f"\n🎉 Script execution completed successfully")
else:
print(f"\n❌ Script execution failed")
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()

View File

@@ -0,0 +1,253 @@
#!/usr/bin/env python3
"""
Improved WinRM Script Executor
Handles large scripts by uploading them in chunks
"""
import os
import sys
import argparse
import json
import time
import base64
from datetime import datetime
from pathlib import Path
from winrm import Session
import logging
class WinRMExecutorV2:
def __init__(self, host, username, password, port=5985, use_https=False):
self.host = host
self.username = username
self.password = password
self.port = port
self.use_https = use_https
self.session = None
# Setup logging
self.setup_logging()
def setup_logging(self):
"""Setup logging configuration"""
log_dir = Path(__file__).parent / "../../logs"
log_dir.mkdir(exist_ok=True)
timestamp = datetime.now().strftime("%Y%m%d-%H%M%S")
log_file = log_dir / f"winrm-v2-{self.host}-{timestamp}.log"
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler()
]
)
self.logger = logging.getLogger(__name__)
self.logger.info(f"Starting WinRM session to {self.host}")
def connect(self):
"""Establish WinRM connection"""
try:
protocol = 'https' if self.use_https else 'http'
endpoint = f'{protocol}://{self.host}:{self.port}/wsman'
self.logger.info(f"Connecting to {endpoint}")
self.session = Session(
endpoint,
auth=(self.username, self.password),
transport='ntlm' if not self.use_https else 'ssl',
server_cert_validation='ignore' if self.use_https else 'validate'
)
# Test connection with a simple command
result = self.session.run_cmd('echo Connection test')
if result.status_code == 0:
self.logger.info("✅ WinRM connection established successfully")
return True
else:
self.logger.error(f"❌ Connection test failed: {result.std_err.decode()}")
return False
except Exception as e:
self.logger.error(f"❌ Failed to connect: {e}")
return False
def upload_script_chunked(self, local_script_path, remote_script_name):
"""Upload script in chunks to avoid command line length limits"""
try:
# Read the local script
with open(local_script_path, 'r', encoding='utf-8') as f:
script_content = f.read()
self.logger.info(f"Uploading script in chunks: {local_script_path} -> {remote_script_name}")
# Encode content as base64 to avoid special character issues
script_bytes = script_content.encode('utf-8')
script_b64 = base64.b64encode(script_bytes).decode('ascii')
# Split into chunks of 8000 chars (safe for command line)
chunk_size = 8000
chunks = [script_b64[i:i+chunk_size] for i in range(0, len(script_b64), chunk_size)]
self.logger.info(f"Uploading {len(chunks)} chunks...")
# Create the file and append chunks
for i, chunk in enumerate(chunks):
if i == 0:
# First chunk - create file
ps_command = f"""
$chunk = '{chunk}'
$chunk | Out-File -FilePath '{remote_script_name}.b64' -Encoding ASCII
"""
else:
# Subsequent chunks - append
ps_command = f"""
$chunk = '{chunk}'
$chunk | Out-File -FilePath '{remote_script_name}.b64' -Encoding ASCII -Append
"""
result = self.session.run_ps(ps_command)
if result.status_code != 0:
self.logger.error(f"Failed to upload chunk {i+1}: {result.std_err.decode()}")
return False
if (i + 1) % 10 == 0:
self.logger.info(f"Uploaded {i+1}/{len(chunks)} chunks...")
# Decode the base64 file to create the final script
decode_command = f"""
$b64Content = Get-Content '{remote_script_name}.b64' -Raw
$bytes = [System.Convert]::FromBase64String($b64Content)
# Write with UTF-8 BOM for Chinese Windows compatibility
$utf8BOM = New-Object System.Text.UTF8Encoding($true)
[System.IO.File]::WriteAllBytes('{remote_script_name}', $bytes)
# Clean up temporary file
Remove-Item '{remote_script_name}.b64' -ErrorAction SilentlyContinue
Write-Host "Script uploaded successfully to {remote_script_name}"
"""
result = self.session.run_ps(decode_command)
if result.status_code == 0:
self.logger.info("✅ Script uploaded and decoded successfully")
return True
else:
self.logger.error(f"Failed to decode script: {result.std_err.decode()}")
return False
except Exception as e:
self.logger.error(f"❌ Script upload failed: {e}")
return False
def execute_script(self, remote_script_name):
"""Execute the uploaded PowerShell script"""
try:
self.logger.info(f"Executing PowerShell script: {remote_script_name}")
# Execute the script
execute_command = f"PowerShell -NoProfile -ExecutionPolicy Bypass -File '{remote_script_name}'"
result = self.session.run_cmd(execute_command)
# Output results in real-time
if result.std_out:
output = result.std_out.decode('utf-8', errors='replace')
self.logger.info("Script Output:")
for line in output.split('\n'):
if line.strip():
print(line)
if result.std_err:
error = result.std_err.decode('utf-8', errors='replace')
if error.strip():
self.logger.warning("Script Errors:")
for line in error.split('\n'):
if line.strip():
print(f"ERROR: {line}")
success = result.status_code == 0
status = "✅ SUCCESS" if success else f"❌ FAILED (exit code: {result.status_code})"
self.logger.info(f"Script execution completed: {status}")
return success
except Exception as e:
self.logger.error(f"❌ Script execution failed: {e}")
return False
def upload_and_execute_script(self, local_script_path, remote_script_name=None):
"""Upload and execute a PowerShell script using chunked upload"""
if not self.session:
self.logger.error("No active WinRM session")
return False
# Generate remote script name if not provided
if not remote_script_name:
script_name = Path(local_script_path).name
remote_script_name = f"C:\\Users\\{self.username}\\{script_name}"
# Upload script
if not self.upload_script_chunked(local_script_path, remote_script_name):
return False
# Execute script
return self.execute_script(remote_script_name)
def close(self):
"""Close the WinRM session"""
if self.session:
self.logger.info("Closing WinRM session")
self.session = None
def main():
parser = argparse.ArgumentParser(description='Execute PowerShell scripts via WinRM (v2)')
parser.add_argument('--host', default=os.getenv('HOST', '192.168.88.108'),
help='Target host')
parser.add_argument('--username', default=os.getenv('USER_NAME', 'Admin'),
help='Username')
parser.add_argument('--password', default=os.getenv('PASS', 'P@ssw0rd!'),
help='Password')
parser.add_argument('--script', required=True,
help='PowerShell script file to execute')
args = parser.parse_args()
# Create executor
executor = WinRMExecutorV2(
host=args.host,
username=args.username,
password=args.password
)
try:
# Connect
if not executor.connect():
sys.exit(1)
# Execute script
script_path = Path(args.script)
if not script_path.exists():
print(f"❌ Script file not found: {script_path}")
sys.exit(1)
success = executor.upload_and_execute_script(script_path)
if success:
print(f"\n🎉 Script execution completed successfully")
else:
sys.exit(1)
finally:
executor.close()
if __name__ == "__main__":
main()