--Original Post--
I am trying to manage (start/stop) a windows service on a remote machine using alternate credentials. I know that I can use the ServiceController class to manage a service using my current credentials:
Dim sc As New ServiceController(ServiceName, ComputerName)
but I want to use different credentials. The other classes I am using (DirectoryEntry and System.Management) both support using alternate credentials... Help would be greatly appreciated.
--Working Code (built based off accepted answer)--
I have to admit that I was sceptical it would work... but below is the code. I had to make a minor change to the code you suggested. Whenever I tried IPC$ it would return a 53 result code, even though I'm sure the share exists. So at the suggestion of another website I removed the share and just the computer name and this worked.
Imports System.Runtime.InteropServices
Imports System.Net
Imports System.IO
Imports System.ServiceProcess
Module Module1
Sub Main()
Dim Computername As String = "SomeComputer"
'Create connection to remote computer'
Using nc As New NetworkConnection("\\" + Computername, New NetworkCredential("Domain\User", "Password"))
Dim sc As New ServiceController("Windows Firewall/Internet Connection Sharing (ICS)", Computername)
'now we can start/stop/whatever we want here'
End Using
Console.ReadLine()
End Sub
Public Class NetworkConnection
Implements IDisposable
Private _networkName As String
Public Sub New(ByVal networkName As String, ByVal credentials As NetworkCredential)
_networkName = networkName
Dim netResource = New NetResource() With { _
.Scope = ResourceScope.GlobalNetwork, _
.ResourceType = ResourceType.Disk, _
.DisplayType = ResourceDisplaytype.Share, _
.RemoteName = networkName _
}
Dim result = WNetAddConnection2(netResource, credentials.Password, credentials.UserName, 0)
If result <> 0 Then
Throw New IOException("Error connecting to remote share", result)
End If
End Sub
Protected Overrides Sub Finalize()
Try
Dispose(False)
Finally
MyBase.Finalize()
End Try
End Sub
Public Sub Dispose() Implements System.IDisposable.Dispose
Dispose(True)
GC.SuppressFinalize(Me)
End Sub
Protected Sub Dispose(ByVal disposing As Boolean)
WNetCancelConnection2(_networkName, 0, True)
End Sub
<DllImport("mpr.dll")> _
Private Shared Function WNetAddConnection2(ByVal netResource As NetResource, ByVal password As String, ByVal username As String, ByVal flags As Integer) As Integer
End Function
<DllImport("mpr.dll")> _
Private Shared Function WNetCancelConnection2(ByVal name As String, ByVal flags As Integer, ByVal force As Boolean) As Integer
End Function
End Class
<StructLayout(LayoutKind.Sequential)> _
Public Class NetResource
Public Scope As ResourceScope
Public ResourceType As ResourceType
Public DisplayType As ResourceDisplaytype
Public Usage As Integer
Public LocalName As String
Public RemoteName As String
Public Comment As String
Public Provider As String
End Class
Public Enum ResourceScope As Integer
Connected = 1
GlobalNetwork
Remembered
Recent
Context
End Enum
Public Enum ResourceType As Integer
Any = 0
Disk = 1
Print = 2
Reserved = 8
End Enum
Public Enum ResourceDisplaytype As Integer
Generic = &H0
Domain = &H1
Server = &H2
Share = &H3
File = &H4
Group = &H5
Network = &H6
Root = &H7
Shareadmin = &H8
Directory = &H9
Tree = &HA
Ndscontainer = &HB
End Enum
End Module
To make remote login you should use
WNetAddConnection2
(see http://msdn.microsoft.com/en-us/library/aa385413.aspx) orNetUseAdd
(see http://msdn.microsoft.com/en-us/library/aa370645.aspx) API. You can use\\RemoteComputer\IPC$
as the destination resource.UPDATED based on the question from the comment: The explanation about IPC$ sessions can be long. Just the main information.
If you want to do something on a remote computer the first thing which will be done is the establishing a authenticated "connection" to the remote computer. The network login (remote login) on the remote computer will be done, which works quite other as a local login. The network logon session stay holding and if you have a connection to for example
\\RemoteComputer\share1
and one other program on your computer try access for example\\RemoteComputer\share2
, the same session will be used.You can simulate the situation with
net.exe
. Just startcmd.exe
and typeor
then you will have a connection to the destination computer. Then you can type
\\RemoteComputer\AnyShare
in Explorer and access file system under the user'sDomain\User
orRemoteComputer\LocalRemoteUser
credential. To disconnect useIf you try to start/stop a service on the remote computer the same IPC session will be tried to established. If you have already such session with one of user's credentials it will be used. Functions
WNetAddConnection2
,NetUseAdd
can be used as replacement of "net use". If you permanently want to access a remote computer with other user's credentials you can useCredWrite
,CredWriteDomainCredentials
orCredUIPromptForCredentials
/CredUIPromptForWindowsCredentials
. The Cred-function seems me not the best way for your case.