unctools 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- unctools/__init__.py +100 -0
- unctools/converter.py +378 -0
- unctools/detector.py +531 -0
- unctools/operations.py +562 -0
- unctools/utils/__init__.py +40 -0
- unctools/utils/compat.py +331 -0
- unctools/utils/logger.py +228 -0
- unctools/utils/validation.py +321 -0
- unctools/windows/__init__.py +45 -0
- unctools/windows/network.py +490 -0
- unctools/windows/registry.py +410 -0
- unctools/windows/security.py +586 -0
- unctools-0.1.0.dist-info/METADATA +189 -0
- unctools-0.1.0.dist-info/RECORD +17 -0
- unctools-0.1.0.dist-info/WHEEL +5 -0
- unctools-0.1.0.dist-info/licenses/LICENSE +21 -0
- unctools-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,490 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Windows network utilities for managing network drives and connections.
|
|
3
|
+
|
|
4
|
+
This module provides functions for working with Windows network drives,
|
|
5
|
+
including creating and removing network mappings, checking network connectivity,
|
|
6
|
+
and managing network shares.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import re
|
|
11
|
+
import logging
|
|
12
|
+
import subprocess
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
from typing import Dict, List, Optional, Tuple, Union, Any
|
|
15
|
+
|
|
16
|
+
# Set up module-level logger
|
|
17
|
+
logger = logging.getLogger(__name__)
|
|
18
|
+
|
|
19
|
+
# Check if we're running on Windows
|
|
20
|
+
IS_WINDOWS = os.name == 'nt'
|
|
21
|
+
|
|
22
|
+
# Try to import Windows-specific modules
|
|
23
|
+
if IS_WINDOWS:
|
|
24
|
+
try:
|
|
25
|
+
import win32net
|
|
26
|
+
import win32wnet
|
|
27
|
+
import win32api
|
|
28
|
+
import win32con
|
|
29
|
+
import win32netcon
|
|
30
|
+
from win32file import WNetAddConnection2, WNetCancelConnection2
|
|
31
|
+
HAVE_WIN32NET = True
|
|
32
|
+
except ImportError:
|
|
33
|
+
HAVE_WIN32NET = False
|
|
34
|
+
logger.debug("win32net module not available. Using command-line fallbacks for network operations.")
|
|
35
|
+
else:
|
|
36
|
+
HAVE_WIN32NET = False
|
|
37
|
+
|
|
38
|
+
def create_network_mapping(unc_path: str, drive_letter: Optional[str] = None,
|
|
39
|
+
username: Optional[str] = None, password: Optional[str] = None,
|
|
40
|
+
persistent: bool = False) -> Tuple[bool, Optional[str]]:
|
|
41
|
+
"""
|
|
42
|
+
Create a network drive mapping for a UNC path.
|
|
43
|
+
|
|
44
|
+
Args:
|
|
45
|
+
unc_path: The UNC path to map (e.g., \\\\server\\share).
|
|
46
|
+
drive_letter: The drive letter to map to (e.g., "Z:").
|
|
47
|
+
If None, Windows will assign the next available drive.
|
|
48
|
+
username: The username for authentication (optional).
|
|
49
|
+
password: The password for authentication (optional).
|
|
50
|
+
persistent: Whether the mapping should persist across reboots.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
A tuple of (success, drive_letter), where success is a boolean indicating
|
|
54
|
+
whether the operation was successful, and drive_letter is the assigned
|
|
55
|
+
drive letter (which may be different from the requested one if automatic
|
|
56
|
+
assignment was used).
|
|
57
|
+
"""
|
|
58
|
+
if not IS_WINDOWS:
|
|
59
|
+
logger.warning("Network mappings are only available on Windows.")
|
|
60
|
+
return (False, None)
|
|
61
|
+
|
|
62
|
+
# Normalize UNC path
|
|
63
|
+
unc_path = unc_path.replace('/', '\\')
|
|
64
|
+
if not unc_path.startswith('\\\\'):
|
|
65
|
+
unc_path = '\\\\' + unc_path.lstrip('\\')
|
|
66
|
+
|
|
67
|
+
# Normalize drive letter if provided
|
|
68
|
+
if drive_letter:
|
|
69
|
+
drive_letter = drive_letter.upper()
|
|
70
|
+
if not drive_letter.endswith(':'):
|
|
71
|
+
drive_letter += ':'
|
|
72
|
+
|
|
73
|
+
# Try to use the Windows API if available
|
|
74
|
+
if HAVE_WIN32NET:
|
|
75
|
+
try:
|
|
76
|
+
# Create a network resource object
|
|
77
|
+
netresource = {
|
|
78
|
+
'Provider': None,
|
|
79
|
+
'Flags': 0,
|
|
80
|
+
'LocalName': drive_letter if drive_letter else None,
|
|
81
|
+
'RemoteName': unc_path
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
# Attempt to add the connection
|
|
85
|
+
try:
|
|
86
|
+
WNetAddConnection2(netresource, password, username, win32con.CONNECT_UPDATE_PROFILE if persistent else 0)
|
|
87
|
+
|
|
88
|
+
# If we didn't specify a drive letter, we need to find out what was assigned
|
|
89
|
+
if not drive_letter:
|
|
90
|
+
# Enumerate network drives to find our newly created one
|
|
91
|
+
connections, _, _ = win32net.NetUseEnum(None, 2)
|
|
92
|
+
for conn in connections:
|
|
93
|
+
if conn.get('remote', '').lower() == unc_path.lower():
|
|
94
|
+
drive_letter = conn.get('local', '').upper()
|
|
95
|
+
break
|
|
96
|
+
|
|
97
|
+
logger.info(f"Successfully mapped {unc_path} to {drive_letter}")
|
|
98
|
+
return (True, drive_letter)
|
|
99
|
+
except win32api.error as e:
|
|
100
|
+
logger.error(f"Failed to map network drive using WNetAddConnection2: {e}")
|
|
101
|
+
# Fall back to net use command
|
|
102
|
+
pass
|
|
103
|
+
except Exception as e:
|
|
104
|
+
logger.error(f"Error using Windows API for network mapping: {e}")
|
|
105
|
+
# Fall back to net use command
|
|
106
|
+
|
|
107
|
+
# Fall back to using the net use command
|
|
108
|
+
cmd = ['net', 'use']
|
|
109
|
+
|
|
110
|
+
# Add drive letter if specified
|
|
111
|
+
if drive_letter:
|
|
112
|
+
cmd.append(drive_letter)
|
|
113
|
+
|
|
114
|
+
# Add UNC path
|
|
115
|
+
cmd.append(unc_path)
|
|
116
|
+
|
|
117
|
+
# Add password if specified
|
|
118
|
+
if password:
|
|
119
|
+
cmd.append(password)
|
|
120
|
+
|
|
121
|
+
# Add persistence flag
|
|
122
|
+
if persistent:
|
|
123
|
+
cmd.append('/PERSISTENT:YES')
|
|
124
|
+
else:
|
|
125
|
+
cmd.append('/PERSISTENT:NO')
|
|
126
|
+
|
|
127
|
+
# Add username if specified
|
|
128
|
+
if username:
|
|
129
|
+
cmd.append(f'/USER:{username}')
|
|
130
|
+
|
|
131
|
+
try:
|
|
132
|
+
# Execute the command
|
|
133
|
+
result = subprocess.run(cmd, text=True, capture_output=True, check=False)
|
|
134
|
+
|
|
135
|
+
if result.returncode == 0:
|
|
136
|
+
# Command succeeded, parse output to find drive letter if not specified
|
|
137
|
+
if not drive_letter:
|
|
138
|
+
# Try to extract from output - "Drive Z: is now connected to \\server\share"
|
|
139
|
+
match = re.search(r'Drive ([A-Z]:)', result.stdout)
|
|
140
|
+
if match:
|
|
141
|
+
drive_letter = match.group(1)
|
|
142
|
+
|
|
143
|
+
logger.info(f"Successfully mapped {unc_path} to {drive_letter}")
|
|
144
|
+
return (True, drive_letter)
|
|
145
|
+
else:
|
|
146
|
+
logger.error(f"Failed to map network drive: {result.stderr}")
|
|
147
|
+
return (False, None)
|
|
148
|
+
except Exception as e:
|
|
149
|
+
logger.error(f"Error executing net use command: {e}")
|
|
150
|
+
return (False, None)
|
|
151
|
+
|
|
152
|
+
def remove_network_mapping(drive_letter: str, force: bool = False) -> bool:
|
|
153
|
+
"""
|
|
154
|
+
Remove a network drive mapping.
|
|
155
|
+
|
|
156
|
+
Args:
|
|
157
|
+
drive_letter: The drive letter to remove (e.g., "Z:").
|
|
158
|
+
force: Whether to force disconnection even if the drive is in use.
|
|
159
|
+
|
|
160
|
+
Returns:
|
|
161
|
+
True if the operation was successful, False otherwise.
|
|
162
|
+
"""
|
|
163
|
+
if not IS_WINDOWS:
|
|
164
|
+
logger.warning("Network mappings are only available on Windows.")
|
|
165
|
+
return False
|
|
166
|
+
|
|
167
|
+
# Normalize drive letter
|
|
168
|
+
drive_letter = drive_letter.upper()
|
|
169
|
+
if not drive_letter.endswith(':'):
|
|
170
|
+
drive_letter += ':'
|
|
171
|
+
|
|
172
|
+
# Try to use the Windows API if available
|
|
173
|
+
if HAVE_WIN32NET:
|
|
174
|
+
try:
|
|
175
|
+
# Attempt to cancel the connection
|
|
176
|
+
WNetCancelConnection2(drive_letter, win32con.CONNECT_UPDATE_PROFILE, force)
|
|
177
|
+
logger.info(f"Successfully removed network mapping for {drive_letter}")
|
|
178
|
+
return True
|
|
179
|
+
except win32api.error as e:
|
|
180
|
+
logger.warning(f"Failed to remove network mapping using WNetCancelConnection2: {e}")
|
|
181
|
+
# Fall back to net use command
|
|
182
|
+
|
|
183
|
+
# Fall back to using the net use command
|
|
184
|
+
cmd = ['net', 'use', drive_letter, '/DELETE']
|
|
185
|
+
|
|
186
|
+
if force:
|
|
187
|
+
cmd.append('/Y')
|
|
188
|
+
|
|
189
|
+
try:
|
|
190
|
+
# Execute the command
|
|
191
|
+
result = subprocess.run(cmd, text=True, capture_output=True, check=False)
|
|
192
|
+
|
|
193
|
+
if result.returncode == 0:
|
|
194
|
+
logger.info(f"Successfully removed network mapping for {drive_letter}")
|
|
195
|
+
return True
|
|
196
|
+
else:
|
|
197
|
+
logger.error(f"Failed to remove network mapping: {result.stderr}")
|
|
198
|
+
return False
|
|
199
|
+
except Exception as e:
|
|
200
|
+
logger.error(f"Error executing net use command: {e}")
|
|
201
|
+
return False
|
|
202
|
+
|
|
203
|
+
def get_all_network_mappings() -> Dict[str, str]:
|
|
204
|
+
"""
|
|
205
|
+
Get all network drive mappings.
|
|
206
|
+
|
|
207
|
+
Returns:
|
|
208
|
+
A dictionary mapping drive letters to UNC paths.
|
|
209
|
+
"""
|
|
210
|
+
if not IS_WINDOWS:
|
|
211
|
+
logger.warning("Network mappings are only available on Windows.")
|
|
212
|
+
return {}
|
|
213
|
+
|
|
214
|
+
mappings = {}
|
|
215
|
+
|
|
216
|
+
# Try to use the Windows API if available
|
|
217
|
+
if HAVE_WIN32NET:
|
|
218
|
+
try:
|
|
219
|
+
# Enumerate network connections
|
|
220
|
+
connections, _, _ = win32net.NetUseEnum(None, 2)
|
|
221
|
+
|
|
222
|
+
for conn in connections:
|
|
223
|
+
local = conn.get('local', '')
|
|
224
|
+
remote = conn.get('remote', '')
|
|
225
|
+
|
|
226
|
+
if local and remote:
|
|
227
|
+
mappings[local.upper()] = remote
|
|
228
|
+
|
|
229
|
+
return mappings
|
|
230
|
+
except Exception as e:
|
|
231
|
+
logger.warning(f"Failed to enumerate network mappings using NetUseEnum: {e}")
|
|
232
|
+
# Fall back to net use command
|
|
233
|
+
|
|
234
|
+
# Fall back to using the net use command
|
|
235
|
+
try:
|
|
236
|
+
result = subprocess.run(['net', 'use'], text=True, capture_output=True, check=False)
|
|
237
|
+
|
|
238
|
+
if result.returncode == 0:
|
|
239
|
+
# Parse the output to extract mappings
|
|
240
|
+
for line in result.stdout.splitlines():
|
|
241
|
+
# Look for lines like "OK Z: \\server\share"
|
|
242
|
+
match = re.search(r'(OK|Disconnected)\s+([A-Za-z]:)\s+(\\\\\S+)', line, re.IGNORECASE)
|
|
243
|
+
if match:
|
|
244
|
+
drive_letter = match.group(2).upper()
|
|
245
|
+
unc_path = match.group(3)
|
|
246
|
+
mappings[drive_letter] = unc_path
|
|
247
|
+
|
|
248
|
+
return mappings
|
|
249
|
+
else:
|
|
250
|
+
logger.error(f"Failed to enumerate network mappings: {result.stderr}")
|
|
251
|
+
return {}
|
|
252
|
+
except Exception as e:
|
|
253
|
+
logger.error(f"Error executing net use command: {e}")
|
|
254
|
+
return {}
|
|
255
|
+
|
|
256
|
+
def check_network_connection(server: str, timeout: int = 5) -> bool:
|
|
257
|
+
"""
|
|
258
|
+
Check if a network server is reachable.
|
|
259
|
+
|
|
260
|
+
Args:
|
|
261
|
+
server: The server name or IP address to check.
|
|
262
|
+
timeout: The timeout in seconds.
|
|
263
|
+
|
|
264
|
+
Returns:
|
|
265
|
+
True if the server is reachable, False otherwise.
|
|
266
|
+
"""
|
|
267
|
+
if not IS_WINDOWS:
|
|
268
|
+
# On non-Windows platforms, try ping
|
|
269
|
+
try:
|
|
270
|
+
result = subprocess.run(['ping', '-c', '1', '-W', str(timeout), server],
|
|
271
|
+
text=True, capture_output=True, check=False)
|
|
272
|
+
return result.returncode == 0
|
|
273
|
+
except Exception as e:
|
|
274
|
+
logger.error(f"Error executing ping command: {e}")
|
|
275
|
+
return False
|
|
276
|
+
|
|
277
|
+
# On Windows, try ping with Windows-specific arguments
|
|
278
|
+
try:
|
|
279
|
+
result = subprocess.run(['ping', '-n', '1', '-w', str(timeout * 1000), server],
|
|
280
|
+
text=True, capture_output=True, check=False)
|
|
281
|
+
return result.returncode == 0
|
|
282
|
+
except Exception as e:
|
|
283
|
+
logger.error(f"Error executing ping command: {e}")
|
|
284
|
+
return False
|
|
285
|
+
|
|
286
|
+
def get_server_shares(server: str, username: Optional[str] = None,
|
|
287
|
+
password: Optional[str] = None) -> List[str]:
|
|
288
|
+
"""
|
|
289
|
+
Get a list of shares available on a server.
|
|
290
|
+
|
|
291
|
+
Args:
|
|
292
|
+
server: The server name.
|
|
293
|
+
username: The username for authentication (optional).
|
|
294
|
+
password: The password for authentication (optional).
|
|
295
|
+
|
|
296
|
+
Returns:
|
|
297
|
+
A list of share names.
|
|
298
|
+
"""
|
|
299
|
+
if not IS_WINDOWS:
|
|
300
|
+
logger.warning("Network share enumeration is only available on Windows.")
|
|
301
|
+
return []
|
|
302
|
+
|
|
303
|
+
shares = []
|
|
304
|
+
|
|
305
|
+
# Try to use the Windows API if available
|
|
306
|
+
if HAVE_WIN32NET:
|
|
307
|
+
try:
|
|
308
|
+
# Build server UNC path
|
|
309
|
+
server_unc = '\\\\' + server.strip('\\')
|
|
310
|
+
|
|
311
|
+
# Set up authentication if provided
|
|
312
|
+
if username and password:
|
|
313
|
+
try:
|
|
314
|
+
# Use NetUseAdd to create a temporary connection
|
|
315
|
+
use_info = {
|
|
316
|
+
'remote': server_unc,
|
|
317
|
+
'password': password,
|
|
318
|
+
'username': username
|
|
319
|
+
}
|
|
320
|
+
win32net.NetUseAdd(None, 2, use_info)
|
|
321
|
+
|
|
322
|
+
# Clean up when we're done
|
|
323
|
+
temp_connection_added = True
|
|
324
|
+
except Exception as e:
|
|
325
|
+
logger.warning(f"Failed to create temporary connection: {e}")
|
|
326
|
+
temp_connection_added = False
|
|
327
|
+
else:
|
|
328
|
+
temp_connection_added = False
|
|
329
|
+
|
|
330
|
+
try:
|
|
331
|
+
# Enumerate shares
|
|
332
|
+
share_info, _, _ = win32net.NetShareEnum(server, 1)
|
|
333
|
+
|
|
334
|
+
for share in share_info:
|
|
335
|
+
share_name = share.get('netname', '')
|
|
336
|
+
if share_name and not share_name.endswith('$'): # Exclude hidden shares
|
|
337
|
+
shares.append(share_name)
|
|
338
|
+
finally:
|
|
339
|
+
# Clean up temporary connection if we created one
|
|
340
|
+
if temp_connection_added:
|
|
341
|
+
try:
|
|
342
|
+
win32net.NetUseDel(None, server_unc)
|
|
343
|
+
except:
|
|
344
|
+
pass
|
|
345
|
+
|
|
346
|
+
return shares
|
|
347
|
+
except Exception as e:
|
|
348
|
+
logger.warning(f"Failed to enumerate shares using NetShareEnum: {e}")
|
|
349
|
+
# Fall back to net view command
|
|
350
|
+
|
|
351
|
+
# Fall back to using the net view command
|
|
352
|
+
cmd = ['net', 'view', '\\\\' + server.strip('\\')]
|
|
353
|
+
|
|
354
|
+
try:
|
|
355
|
+
result = subprocess.run(cmd, text=True, capture_output=True, check=False)
|
|
356
|
+
|
|
357
|
+
if result.returncode == 0:
|
|
358
|
+
# Parse the output to extract share names
|
|
359
|
+
for line in result.stdout.splitlines():
|
|
360
|
+
# Look for lines with share names
|
|
361
|
+
match = re.search(r'(\S+)\s+Disk\s+', line, re.IGNORECASE)
|
|
362
|
+
if match:
|
|
363
|
+
share_name = match.group(1)
|
|
364
|
+
if not share_name.endswith('$'): # Exclude hidden shares
|
|
365
|
+
shares.append(share_name)
|
|
366
|
+
|
|
367
|
+
return shares
|
|
368
|
+
else:
|
|
369
|
+
logger.error(f"Failed to enumerate shares: {result.stderr}")
|
|
370
|
+
return []
|
|
371
|
+
except Exception as e:
|
|
372
|
+
logger.error(f"Error executing net view command: {e}")
|
|
373
|
+
return []
|
|
374
|
+
|
|
375
|
+
def create_share(path: str, share_name: str, description: str = "",
|
|
376
|
+
max_users: int = -1, full_access_users: List[str] = None) -> bool:
|
|
377
|
+
"""
|
|
378
|
+
Create a network share on the local machine.
|
|
379
|
+
|
|
380
|
+
Args:
|
|
381
|
+
path: The local path to share.
|
|
382
|
+
share_name: The name of the share.
|
|
383
|
+
description: A description of the share.
|
|
384
|
+
max_users: Maximum number of concurrent users (-1 for unlimited).
|
|
385
|
+
full_access_users: List of users to grant full access to.
|
|
386
|
+
|
|
387
|
+
Returns:
|
|
388
|
+
True if the operation was successful, False otherwise.
|
|
389
|
+
"""
|
|
390
|
+
if not IS_WINDOWS:
|
|
391
|
+
logger.warning("Network share creation is only available on Windows.")
|
|
392
|
+
return False
|
|
393
|
+
|
|
394
|
+
# Check if path exists
|
|
395
|
+
if not os.path.exists(path):
|
|
396
|
+
logger.error(f"Path does not exist: {path}")
|
|
397
|
+
return False
|
|
398
|
+
|
|
399
|
+
# Try to use the Windows API if available
|
|
400
|
+
if HAVE_WIN32NET:
|
|
401
|
+
try:
|
|
402
|
+
# Create the share
|
|
403
|
+
share_info = {
|
|
404
|
+
'netname': share_name,
|
|
405
|
+
'path': os.path.abspath(path),
|
|
406
|
+
'remark': description,
|
|
407
|
+
'max_uses': max_users,
|
|
408
|
+
'type': win32netcon.STYPE_DISKTREE,
|
|
409
|
+
'permissions': 0
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
win32net.NetShareAdd(None, 2, share_info)
|
|
413
|
+
|
|
414
|
+
# Set permissions if requested
|
|
415
|
+
if full_access_users:
|
|
416
|
+
for user in full_access_users:
|
|
417
|
+
# Add permission setting code here
|
|
418
|
+
# This requires more complex Windows API calls
|
|
419
|
+
pass
|
|
420
|
+
|
|
421
|
+
logger.info(f"Successfully created share {share_name} for {path}")
|
|
422
|
+
return True
|
|
423
|
+
except Exception as e:
|
|
424
|
+
logger.error(f"Failed to create share using NetShareAdd: {e}")
|
|
425
|
+
# Fall back to net share command
|
|
426
|
+
|
|
427
|
+
# Fall back to using the net share command
|
|
428
|
+
cmd = ['net', 'share', share_name + '=' + os.path.abspath(path)]
|
|
429
|
+
|
|
430
|
+
if description:
|
|
431
|
+
cmd.extend(['/REMARK:', description])
|
|
432
|
+
|
|
433
|
+
if max_users >= 0:
|
|
434
|
+
cmd.extend(['/USERS:', str(max_users)])
|
|
435
|
+
|
|
436
|
+
try:
|
|
437
|
+
result = subprocess.run(cmd, text=True, capture_output=True, check=False)
|
|
438
|
+
|
|
439
|
+
if result.returncode == 0:
|
|
440
|
+
logger.info(f"Successfully created share {share_name} for {path}")
|
|
441
|
+
|
|
442
|
+
# Additional commands would be needed to set permissions
|
|
443
|
+
|
|
444
|
+
return True
|
|
445
|
+
else:
|
|
446
|
+
logger.error(f"Failed to create share: {result.stderr}")
|
|
447
|
+
return False
|
|
448
|
+
except Exception as e:
|
|
449
|
+
logger.error(f"Error executing net share command: {e}")
|
|
450
|
+
return False
|
|
451
|
+
|
|
452
|
+
def remove_share(share_name: str) -> bool:
|
|
453
|
+
"""
|
|
454
|
+
Remove a network share from the local machine.
|
|
455
|
+
|
|
456
|
+
Args:
|
|
457
|
+
share_name: The name of the share to remove.
|
|
458
|
+
|
|
459
|
+
Returns:
|
|
460
|
+
True if the operation was successful, False otherwise.
|
|
461
|
+
"""
|
|
462
|
+
if not IS_WINDOWS:
|
|
463
|
+
logger.warning("Network share removal is only available on Windows.")
|
|
464
|
+
return False
|
|
465
|
+
|
|
466
|
+
# Try to use the Windows API if available
|
|
467
|
+
if HAVE_WIN32NET:
|
|
468
|
+
try:
|
|
469
|
+
win32net.NetShareDel(None, share_name)
|
|
470
|
+
logger.info(f"Successfully removed share {share_name}")
|
|
471
|
+
return True
|
|
472
|
+
except Exception as e:
|
|
473
|
+
logger.error(f"Failed to remove share using NetShareDel: {e}")
|
|
474
|
+
# Fall back to net share command
|
|
475
|
+
|
|
476
|
+
# Fall back to using the net share command
|
|
477
|
+
cmd = ['net', 'share', share_name, '/DELETE']
|
|
478
|
+
|
|
479
|
+
try:
|
|
480
|
+
result = subprocess.run(cmd, text=True, capture_output=True, check=False)
|
|
481
|
+
|
|
482
|
+
if result.returncode == 0:
|
|
483
|
+
logger.info(f"Successfully removed share {share_name}")
|
|
484
|
+
return True
|
|
485
|
+
else:
|
|
486
|
+
logger.error(f"Failed to remove share: {result.stderr}")
|
|
487
|
+
return False
|
|
488
|
+
except Exception as e:
|
|
489
|
+
logger.error(f"Error executing net share command: {e}")
|
|
490
|
+
return False
|