or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

auth-security.mdexceptions.mdindex.mdprotocol.mdresponse.mdsession.md

exceptions.mddocs/

0

# Exception Handling

1

2

Comprehensive exception hierarchy for handling WinRM-specific errors, transport failures, and authentication issues. PyWinRM provides detailed error information to help diagnose connection problems, authentication failures, and WinRM service issues.

3

4

## Capabilities

5

6

### Exception Hierarchy

7

8

PyWinRM defines a structured exception hierarchy for different types of failures.

9

10

```python { .api }

11

# Base exception classes

12

class WinRMError(Exception):

13

"""Generic WinRM error with HTTP status code."""

14

code = 500

15

16

class WinRMTransportError(Exception):

17

"""Transport-level HTTP errors (unexpected status codes)."""

18

19

@property

20

def protocol(self) -> str: ...

21

22

@property

23

def code(self) -> int: ...

24

25

@property

26

def message(self) -> str: ...

27

28

@property

29

def response_text(self) -> str: ...

30

31

class WinRMOperationTimeoutError(Exception):

32

"""WinRM operation timeout (retryable)."""

33

code = 500

34

35

# Authentication exceptions

36

class AuthenticationError(WinRMError):

37

"""Base authentication error."""

38

code = 401

39

40

class BasicAuthDisabledError(AuthenticationError):

41

"""HTTP Basic authentication is disabled on remote host."""

42

message = "WinRM/HTTP Basic authentication is not enabled on remote host"

43

44

class InvalidCredentialsError(AuthenticationError):

45

"""Invalid username/password credentials."""

46

```

47

48

### WSMan Fault Errors

49

50

Detailed WSMan protocol fault information for diagnosing WinRM service errors.

51

52

```python { .api }

53

class WSManFaultError(WinRMError):

54

"""

55

WSMan fault with detailed error information.

56

57

Contains raw response and parsed fault details from WSMan service.

58

Provides both Microsoft-specific codes and standard WSMan fault data.

59

"""

60

61

def __init__(

62

self,

63

code: int,

64

message: str,

65

response: str,

66

reason: str,

67

fault_code: str | None = None,

68

fault_subcode: str | None = None,

69

wsman_fault_code: int | None = None,

70

wmierror_code: int | None = None

71

):

72

"""

73

Initialize WSMan fault error with detailed fault information.

74

75

Parameters:

76

- code: HTTP status code of the response

77

- message: error message from transport layer

78

- response: raw WSMan response text

79

- reason: WSMan fault reason text

80

- fault_code: WSMan fault code string

81

- fault_subcode: WSMan fault subcode string

82

- wsman_fault_code: Microsoft WSManFault specific code

83

- wmierror_code: Microsoft WMI error code (for quota violations, etc.)

84

"""

85

86

# Fault information attributes

87

code: int # HTTP status code

88

response: str # Raw WSMan response

89

fault_code: str | None # WSMan fault code

90

fault_subcode: str | None # WSMan fault subcode

91

reason: str # Fault reason text

92

wsman_fault_code: int | None # MS-specific fault code

93

wmierror_code: int | None # WMI error code

94

```

95

96

## Exception Handling Examples

97

98

### Basic Exception Handling

99

100

```python

101

import winrm

102

from winrm.exceptions import (

103

WinRMError, WSManFaultError, WinRMTransportError,

104

AuthenticationError, WinRMOperationTimeoutError

105

)

106

107

def safe_winrm_operation(hostname, username, password, command):

108

"""Execute WinRM command with comprehensive error handling."""

109

110

try:

111

s = winrm.Session(hostname, auth=(username, password))

112

r = s.run_cmd(command)

113

114

if r.status_code == 0:

115

return r.std_out.decode('utf-8')

116

else:

117

print(f"Command failed with exit code: {r.status_code}")

118

print(f"Error output: {r.std_err.decode('utf-8')}")

119

return None

120

121

except AuthenticationError as e:

122

print(f"Authentication failed: {e}")

123

print("Check username, password, and authentication method")

124

return None

125

126

except WSManFaultError as e:

127

print(f"WSMan fault: {e.reason}")

128

print(f"HTTP Status: {e.code}")

129

if e.wsman_fault_code:

130

print(f"WSMan Fault Code: {e.wsman_fault_code}")

131

if e.wmierror_code:

132

print(f"WMI Error Code: {e.wmierror_code}")

133

return None

134

135

except WinRMTransportError as e:

136

print(f"Transport error: {e.message}")

137

print(f"HTTP Status: {e.code}")

138

print(f"Response: {e.response_text[:200]}...")

139

return None

140

141

except WinRMOperationTimeoutError as e:

142

print("Operation timed out - this is often retryable")

143

return None

144

145

except WinRMError as e:

146

print(f"General WinRM error: {e}")

147

return None

148

149

except Exception as e:

150

print(f"Unexpected error: {e}")

151

return None

152

153

# Usage

154

result = safe_winrm_operation('windows-host', 'user', 'password', 'hostname')

155

if result:

156

print(f"Hostname: {result.strip()}")

157

```

158

159

### Authentication Error Recovery

160

161

```python

162

def try_authentication_methods(hostname, username, password):

163

"""Try different authentication methods until one succeeds."""

164

165

auth_methods = [

166

('ntlm', {'transport': 'ntlm', 'message_encryption': 'auto'}),

167

('ssl', {'transport': 'ssl'}),

168

('kerberos', {'transport': 'kerberos'}),

169

('basic', {'transport': 'basic'})

170

]

171

172

for method_name, kwargs in auth_methods:

173

try:

174

print(f"Trying {method_name} authentication...")

175

s = winrm.Session(hostname, auth=(username, password), **kwargs)

176

r = s.run_cmd('echo', ['test'])

177

178

if r.status_code == 0:

179

print(f"Success with {method_name} authentication")

180

return s

181

182

except BasicAuthDisabledError:

183

print("Basic authentication is disabled on the server")

184

continue

185

186

except InvalidCredentialsError:

187

print("Invalid credentials - check username and password")

188

break # Don't try other methods with bad credentials

189

190

except AuthenticationError as e:

191

print(f"Authentication failed with {method_name}: {e}")

192

continue

193

194

except Exception as e:

195

print(f"Error with {method_name}: {e}")

196

continue

197

198

print("All authentication methods failed")

199

return None

200

201

# Usage

202

session = try_authentication_methods('windows-host', 'user', 'password')

203

if session:

204

# Use successful session

205

r = session.run_cmd('systeminfo')

206

```

207

208

### WSMan Fault Analysis

209

210

```python

211

def analyze_wsman_fault(fault_error):

212

"""Analyze WSMan fault error and provide troubleshooting guidance."""

213

214

analysis = {

215

'http_status': fault_error.code,

216

'fault_reason': fault_error.reason,

217

'fault_code': fault_error.fault_code,

218

'wsman_code': fault_error.wsman_fault_code,

219

'wmi_code': fault_error.wmierror_code,

220

'guidance': []

221

}

222

223

# Common fault code analysis

224

if fault_error.fault_code == 'a:ActionNotSupported':

225

analysis['guidance'].append("The requested WS-Management action is not supported")

226

analysis['guidance'].append("Check WinRM service configuration and Windows version")

227

228

elif fault_error.fault_code == 'a:AccessDenied':

229

analysis['guidance'].append("Access denied - check user permissions")

230

analysis['guidance'].append("User may need 'Log on as a service' or WinRM permissions")

231

232

elif fault_error.fault_code == 'a:QuotaLimit':

233

analysis['guidance'].append("WinRM quota limit exceeded")

234

analysis['guidance'].append("Increase MaxShellsPerUser or MaxConcurrentOperationsPerUser")

235

236

# Microsoft-specific fault codes

237

if fault_error.wsman_fault_code:

238

wsman_code = fault_error.wsman_fault_code

239

if wsman_code == 2150858793: # 0x80338029

240

analysis['guidance'].append("WinRM service is not running or not properly configured")

241

elif wsman_code == 2150858770: # 0x80338012

242

analysis['guidance'].append("The specified resource URI is not supported")

243

244

# WMI error codes

245

if fault_error.wmierror_code:

246

wmi_code = fault_error.wmierror_code

247

if wmi_code == 2147749889: # 0x80041001

248

analysis['guidance'].append("WMI: General failure")

249

elif wmi_code == 2147749890: # 0x80041002

250

analysis['guidance'].append("WMI: Object not found")

251

252

return analysis

253

254

# Usage in exception handler

255

try:

256

s = winrm.Session('windows-host', auth=('user', 'password'))

257

r = s.run_cmd('invalidcommand')

258

except WSManFaultError as e:

259

analysis = analyze_wsman_fault(e)

260

261

print(f"WSMan Fault Analysis:")

262

print(f"HTTP Status: {analysis['http_status']}")

263

print(f"Reason: {analysis['fault_reason']}")

264

if analysis['fault_code']:

265

print(f"Fault Code: {analysis['fault_code']}")

266

267

if analysis['guidance']:

268

print("Troubleshooting suggestions:")

269

for suggestion in analysis['guidance']:

270

print(f" - {suggestion}")

271

```

272

273

### Retry Logic with Timeout Handling

274

275

```python

276

import time

277

import random

278

279

def execute_with_retry(session, command, args=None, max_retries=3, backoff_factor=2):

280

"""Execute command with exponential backoff retry for timeout errors."""

281

282

args = args or []

283

284

for attempt in range(max_retries):

285

try:

286

r = session.run_cmd(command, args)

287

return r # Success

288

289

except WinRMOperationTimeoutError:

290

if attempt < max_retries - 1:

291

wait_time = backoff_factor ** attempt + random.uniform(0, 1)

292

print(f"Operation timeout, retrying in {wait_time:.1f}s (attempt {attempt + 1})")

293

time.sleep(wait_time)

294

continue

295

else:

296

print("Operation timed out after all retry attempts")

297

raise

298

299

except (WSManFaultError, WinRMTransportError) as e:

300

# These errors are typically not retryable

301

print(f"Non-retryable error: {e}")

302

raise

303

304

except Exception as e:

305

# Unexpected error

306

print(f"Unexpected error on attempt {attempt + 1}: {e}")

307

if attempt < max_retries - 1:

308

time.sleep(1)

309

continue

310

else:

311

raise

312

313

# Usage

314

try:

315

r = execute_with_retry(session, 'ping', ['google.com', '-n', '10'])

316

print("Ping completed successfully")

317

except Exception as e:

318

print(f"Command failed after retries: {e}")

319

```

320

321

### Connection Validation

322

323

```python

324

def validate_winrm_connection(hostname, username, password, **kwargs):

325

"""Validate WinRM connection and return detailed diagnostics."""

326

327

diagnostics = {

328

'connection_successful': False,

329

'authentication_successful': False,

330

'command_execution_successful': False,

331

'errors': [],

332

'warnings': []

333

}

334

335

try:

336

# Test connection and authentication

337

s = winrm.Session(hostname, auth=(username, password), **kwargs)

338

diagnostics['connection_successful'] = True

339

diagnostics['authentication_successful'] = True

340

341

# Test command execution

342

r = s.run_cmd('echo', ['connection_test'])

343

if r.status_code == 0:

344

diagnostics['command_execution_successful'] = True

345

output = r.std_out.decode('utf-8').strip()

346

if output == 'connection_test':

347

diagnostics['echo_successful'] = True

348

else:

349

diagnostics['warnings'].append(f"Unexpected echo output: {output}")

350

else:

351

diagnostics['errors'].append(f"Echo command failed with code: {r.status_code}")

352

353

except BasicAuthDisabledError:

354

diagnostics['errors'].append("Basic authentication is disabled on the server")

355

356

except InvalidCredentialsError:

357

diagnostics['errors'].append("Invalid username or password")

358

359

except AuthenticationError as e:

360

diagnostics['errors'].append(f"Authentication error: {e}")

361

362

except WSManFaultError as e:

363

diagnostics['connection_successful'] = True # Network connection worked

364

diagnostics['errors'].append(f"WSMan fault: {e.reason}")

365

if e.wsman_fault_code:

366

diagnostics['errors'].append(f"WSMan code: {e.wsman_fault_code}")

367

368

except WinRMTransportError as e:

369

diagnostics['errors'].append(f"Transport error: {e.message} (HTTP {e.code})")

370

371

except Exception as e:

372

diagnostics['errors'].append(f"Unexpected error: {e}")

373

374

return diagnostics

375

376

# Usage

377

diag = validate_winrm_connection('windows-host', 'user', 'password', transport='ntlm')

378

print(f"Connection: {'✓' if diag['connection_successful'] else '✗'}")

379

print(f"Authentication: {'✓' if diag['authentication_successful'] else '✗'}")

380

print(f"Command execution: {'✓' if diag['command_execution_successful'] else '✗'}")

381

382

if diag['errors']:

383

print("Errors:")

384

for error in diag['errors']:

385

print(f" - {error}")

386

387

if diag['warnings']:

388

print("Warnings:")

389

for warning in diag['warnings']:

390

print(f" - {warning}")

391

```

392

393

## Common Error Scenarios

394

395

### WinRM Service Configuration Issues

396

397

```python

398

# Common WSMan fault codes and their meanings:

399

WSMAN_FAULT_CODES = {

400

'a:ActionNotSupported': 'WS-Management action not supported',

401

'a:AccessDenied': 'Access denied - check permissions',

402

'a:QuotaLimit': 'WinRM quota limit exceeded',

403

'a:InternalError': 'Internal server error',

404

'a:InvalidResourceURI': 'Invalid resource URI',

405

'a:TimedOut': 'Operation timed out on server side'

406

}

407

408

# Microsoft WSMan fault codes (decimal):

409

MS_WSMAN_FAULT_CODES = {

410

2150858793: 'WinRM service not running or not configured', # 0x80338029

411

2150858770: 'Resource URI not supported', # 0x80338012

412

2150858778: 'Invalid operation timeout specified', # 0x8033801A

413

2150858843: 'User quota exceeded' # 0x8033805B

414

}

415

```

416

417

These error codes help identify specific WinRM configuration issues and guide troubleshooting efforts for successful remote management deployment.