Agent Unable to Access Drive When Server Running as NT Service

Mindwatering Incorporated

Author: Tripp W Black

Created: 03/06/2003 at 09:05 AM

 

Category:
Notes Developer Tips
Agents, LotusScript

Issue:
If Domino runs as a NT service (using the System / desktop account) then there are no network drives mounted as you have to log in to have network drives.

Workarounds:
Note: If running >2000, I would suggest trying #4, first.
1. Don't run Domino as a service. Log in and have a batch file start Domino.
2. Run Domino as a user (rather than System - interact with Desktop). Side-effect: The domino server console window won't be there for general log ins. You'll have to use the Administrator remote console instead.
3. Share a local drive instead on the Domino box for the user. That way the agent is accessing a local drive.
4. If running XP or 2003, you should still be able to use the UNC path, e.g. \\server\sharedfolder


Semi-Complicated Fix:
Communicate via API and actually have the agent log in using a user account and map the drive... Here is sample code to get you started:

'LibNT:

Option Public

Public Const SYS_USERName = "SH-S\notesadmin"
Public Const SYS_PASSWORD = "1NAi1MSF"
'----- DLL containing the needed Win32 functions
Public Const WIN32_DLL = "mpr.dll"
'----- Flags
Public Const RESOURCETYPE_ANY = &H00000000
Public Const RESOURCETYPE_DISK = &H00000001
Public Const RESOURCETYPE_PRINT = &H00000002
Public Const CONNECT_UPDATE_PROFILE = &H00000001

'----- Network resource structure
Public Type WIN32_NETRESOURCE
dwScope As Long
dwType As Long '<< Any/disk/print
dwDisplayType As Long
dwUsage As Long
lpLocalName As String '<< Local drive name to use
lpRemoteName As String '<< Remote path
lpComment As String
lpProvider As String
End Type

'----- Win 32 API function(s)
Declare Function WNetAddConnection2& Lib WIN32_DLL Alias "WNetAddConnection2A" ( lpNetResource As WIN32_NETRESOURCE, _ 'Network resource structure
Byval lpPassword As String, _ 'User password
Byval lpUserName As String, _ 'User name
Byval dwFlags As Long) 'Flags

Declare Function WNetCancelConnection& Lib WIN32_DLL Alias "WNetCancelConnectionA" ( _
Byval lpName As String, _ 'Name of local device to disconnect
Byval fForce As Long) 'Force the disconnect

'----- Error codes from error.h
Public Const NO_ERROR = 0
Public Const ERROR_ACCESS_DENIED = 5
Public Const ERROR_ALREADY_ASSIGNED = 85
Public Const ERROR_INVALID_PASSWORD = 86

'----- Error codes from winerror.h
Public Const ERROR_BAD_DEV_TYPE = 66
Public Const ERROR_BAD_NET_NAME = 67
Public Const ERROR_BUSY = 170
Public Const ERROR_BAD_DEVICE = 1200
Public Const ERROR_DEVICE_ALREADY_REMEMBERED = 1202
Public Const ERROR_NO_NET_OR_BAD_PATH = 1203
Public Const ERROR_BAD_PROVIDER = 1204
Public Const ERROR_CANNOT_OPEN_PROFILE = 1205
Public Const ERROR_BAD_PROFILE = 1206
Public Const ERROR_EXTENDED_ERROR = 1208
Public Const ERROR_NO_NETWORK = 1222
Public Const ERROR_CANCELLED = 1223
Public Const ERROR_NOT_CONNECTED = 2250
Public Const ERROR_DEVICE_IN_USE = 2404
Dim retCode&, ascLett&, drivNam$, tmp$


Public Function Win32ConnectDrive$(Byval pathNam$)

Win32ConnectDrive = ""
On Error Goto Errors
Const FUNC_NAME = "Win32ConnectDrive"
Dim netRes As WIN32_NETRESOURCE
Dim retCode&, ascLett&, drivNam$
Dim fst&, sec&, mach$, shar$, pth$, tmp$
drivNam = ""
If Instr(pathNam, "\\") = 0 Then Goto TheEnd

'----- Try to find a drive that isn't being used
For ascLett = 90 To 68 Step -1
tmp = Chr$(ascLett) & ":"
If Not(IsDriveAvailable(tmp)) Then
drivNam = tmp
Exit For
End If
Next ascLett
If drivNam = "" Then Goto TheEnd

'----- Explode the pieces of the UNC name
pathNam = Mid$(pathNam, 3) 'remove first 2 slashes
fst = Instr(pathNam, "\") 'first slash "\"
mach = Left$(pathNam, fst-1) 'machine name
sec = Instr(fst+1, pathNam, "\") 'second slash "\"
If (sec <> 0) Then
shar = Mid$(pathNam, fst+1, Instr(fst+1, pathNam, "\")-(fst+1)) 'share name
Else
shar = Mid$(pathNam, fst+1)
End If

tmp = "\\" & mach & "\" & shar
pth = Mid$(pathNam, Len(tmp))
pathNam = tmp

'----- Fill out the relevant info in the resource structure
netRes.dwType = RESOURCETYPE_DISK
netRes.lpLocalName = drivNam
netRes.lpRemoteName = pathNam

'----- Make the necessary call to map the drive
retCode = WNetAddConnection2(netRes, SYS_PASSWORD, SYS_USERNAME, 0)
If (retCode <> NO_ERROR) Then
tmp = Win32GetErrorString(retCode)
Print FUNC_NAME & ": " & tmp & "(" & Trim$(Str(retCode)) & ")"
Exit Function
End If

'----- Return the new full path
Win32ConnectDrive = drivNam & "\" & pth

TheEnd:
Exit Function

Errors:
Win32ConnectDrive = ""
Print FUNC_NAME & ": " & Error$
Resume TheEnd

End Function
Function Win32GetErrorString$(retCode&)

Dim tmp$
Select Case(retCode)

Case NO_ERROR:
tmp = "No error"
Case ERROR_ACCESS_DENIED:
tmp = "Access to resource was denied"
Case ERROR_ALREADY_ASSIGNED:
tmp = "Resource already assigned"
Case ERROR_INVALID_PASSWORD:
tmp = "Specified password is invalid"
Case ERROR_BAD_DEV_TYPE:
tmp = "Type of local device and the type of network resource do not match"
Case ERROR_BAD_NET_NAME:
tmp = "The resource name is invalid, or the named resource cannot be located"
Case ERROR_BUSY:
tmp = "The router or provider is busy, possibly initializing"
Case ERROR_BAD_DEVICE:
tmp = "The local name is invalid"
Case ERROR_DEVICE_ALREADY_REMEMBERED:
tmp = "An entry for the specified device is already in the user profile"
Case ERROR_NO_NET_OR_BAD_PATH:
tmp = "A network component has not started, or the specified name could not be handled"
Case ERROR_BAD_PROVIDER:
tmp = "The provider value is invalid"
Case ERROR_CANNOT_OPEN_PROFILE:
tmp = "Unable to open the user profile to process persistent connections"
Case ERROR_BAD_PROFILE:
tmp = "The user profile is in an incorrect format"
Case ERROR_EXTENDED_ERROR:
tmp = "A network specific error occurred"
Case ERROR_NO_NETWORK:
tmp = "No network is present"
Case ERROR_CANCELLED:
tmp = "The action was cancelled"
Case Else:
tmp = "Error"
End Select
Win32GetErrorString = tmp
End Function
Public Function Win32DisconnectDrive(Byval drivNam$) As Variant
Const FUNC_NAME = "Win32DisconnectDrive"
On Error Goto Errors
Dim retCode&, tmp$
Win32DisconnectDrive = True

drivNam = Left$(drivNam, Instr(drivNam, ":"))
If Not(IsDriveAvailable(drivNam)) Then Exit Function
retCode = WNetCancelConnection(drivNam, 1)
If (retCode <> NO_ERROR) Then
tmp = Win32GetErrorString(retCode)
Print FUNC_NAME & ": " & tmp & " (" & Trim$(Str$(retCode)) & ")"
End If

TheEnd:
Exit Function

Errors:
Print FUNC_NAME & ": " & Error$
Win32DisconnectDrive = False
Resume TheEnd

End Function
Function IsDriveAvailable(drivNam$) As Variant
On Error Goto Errors
IsDriveAvailable = False
If Dir$(drivNam, 8) <> "" Then
IsDriveAvailable = True
End If
TheEnd:
Exit Function
Errors:
Resume TheEnd
End Function
Public Function SetupPathRoot(Byval filePathRoot$) As String

On Error Goto Errors
Dim bak$
bak = filePathRoot

'----- If we are dealing with UNC names, map a drive
If Instr(filePathRoot, ":") = 0 And Left$(filePathRoot, 2) = "\\" Then
filePathRoot = Win32ConnectDrive(filePathRoot)
If filePathRoot = "" Then filePathRoot = bak
End If

'----- Make sure the last character is a backslash
If Right(filePathRoot, 1) <> "\" Then filePathRoot = filePathRoot & "\"
SetupPathRoot = filePathRoot

TheEnd:
Exit Function

Errors:
SetupPathRoot = bak
Resume TheEnd

End Function
Public Function TermPathRoot(Byval filePath$)

On Error Goto Errors
Call Win32DisconnectDrive(filePath)
TermPathRoot = True

TheEnd:
Exit Function

Errors:
TermPathRoot = False
Resume TheEnd

End Function

previous page