Files
certctl/internal/connector/target/iis/winrm.go
T
shankar0123 7cb453a336 chore(fmt): repo-wide gofmt -w sweep — close drift surfaced by ci-pipeline-cleanup Phase 4
Mechanical reformat. The new 'gofmt drift' CI step (added in
ci-pipeline-cleanup Phase 4, commit 0f205a8) surfaced 111 files
with accumulated gofmt drift across cmd/, internal/, and deploy/test/.

Each file's diff is gofmt-standard: whitespace adjustments, intra-
group import sorting (alphabetical by import path within blank-line-
separated groups), and struct-tag column alignment. No semantic
changes — verified via 'git diff --ignore-all-space' which shows only
the line-position deltas from import reordering.

The gate stays in place after this commit. Going forward it catches
gofmt drift at PR time.
2026-04-30 22:33:57 +00:00

90 lines
2.8 KiB
Go

package iis
import (
"context"
"fmt"
"time"
"github.com/masterzen/winrm"
)
// WinRMConfig holds WinRM connection settings for remote IIS management.
// Used when Mode is "winrm" — the proxy agent connects to a remote Windows
// server over WinRM and executes PowerShell commands remotely.
type WinRMConfig struct {
Host string `json:"winrm_host"` // WinRM target hostname or IP (required)
Port int `json:"winrm_port"` // WinRM port (default 5985 for HTTP, 5986 for HTTPS)
Username string `json:"winrm_username"` // Windows user (e.g., "Administrator")
Password string `json:"winrm_password"` // Windows password
UseHTTPS bool `json:"winrm_https"` // Use HTTPS (port 5986) instead of HTTP (port 5985)
Insecure bool `json:"winrm_insecure"` // Skip TLS certificate verification (for self-signed certs)
Timeout int `json:"winrm_timeout"` // Operation timeout in seconds (default 60)
}
// winrmExecutor implements PowerShellExecutor by running PowerShell commands
// on a remote Windows server via WinRM. This enables the proxy agent pattern:
// a Linux agent in the same network zone manages Windows IIS servers remotely.
type winrmExecutor struct {
client *winrm.Client
}
// newWinRMExecutor creates a WinRM client and returns a PowerShellExecutor.
func newWinRMExecutor(cfg *WinRMConfig) (*winrmExecutor, error) {
if cfg.Host == "" {
return nil, fmt.Errorf("winrm_host is required for WinRM mode")
}
if cfg.Username == "" {
return nil, fmt.Errorf("winrm_username is required for WinRM mode")
}
if cfg.Password == "" {
return nil, fmt.Errorf("winrm_password is required for WinRM mode")
}
port := cfg.Port
if port == 0 {
if cfg.UseHTTPS {
port = 5986
} else {
port = 5985
}
}
timeout := time.Duration(cfg.Timeout) * time.Second
if cfg.Timeout == 0 {
timeout = 60 * time.Second
}
endpoint := winrm.NewEndpoint(
cfg.Host,
port,
cfg.UseHTTPS,
cfg.Insecure,
nil, // CA cert
nil, // Client cert
nil, // Client key
timeout,
)
client, err := winrm.NewClient(endpoint, cfg.Username, cfg.Password)
if err != nil {
return nil, fmt.Errorf("failed to create WinRM client: %w", err)
}
return &winrmExecutor{client: client}, nil
}
// Execute runs a PowerShell script on the remote Windows server via WinRM.
// The script is wrapped in powershell.exe invocation on the remote side.
func (e *winrmExecutor) Execute(ctx context.Context, script string) (string, error) {
// RunPSWithContext returns (stdout, stderr, exitCode, error)
stdout, stderr, exitCode, err := e.client.RunPSWithContext(ctx, script)
if err != nil {
return stdout + stderr, fmt.Errorf("WinRM command failed: %w", err)
}
if exitCode != 0 {
return stdout + stderr, fmt.Errorf("PowerShell exited with code %d: %s", exitCode, stdout+stderr)
}
return stdout, nil
}