PowerShell remoting from a Windows service - c#

I have a Windows service that regulary runs a PowerShell script on a remote computer via WsManConnectionInfo/RunspaceFactory (following the steps from this article: Remotely Executing Commands in PowerShell using C#):
var connectionInfo = new WSManConnectionInfo(false, server, 5985, "/wsman",
"http://schemas.microsoft.com/powershell/Microsoft.PowerShell",
cred)
{
OperationTimeout = 4*60*1000,
OpenTimeout = 1*60*1000
};
using (var runSpace = RunspaceFactory.CreateRunspace(connectionInfo))
{
runSpace.Open();
using (var p = runSpace.CreatePipeline())
{
p.Commands.AddScript(script);
var output = p.Invoke();
...
}
}
Now, if I run the Windows service itself with an Administrator account, all is well. But if i run the service with the LocalSystem account, I get the following exception;
System.Management.Automation.Remoting.PSRemotingTransportException:
Connecting to remote server NOSRVDEV02 failed with the following error message :
WinRM cannot process the request. The following error with
errorcode 0x8009030d occurred while using Negotiate authentication:
A specified logon session does not exist. It may already have been terminated.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does not exist.
-The client and remote computers are in different domains and there is no trust between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
-For more information about WinRM configuration, run the following command: winrm help config. For more information, see the about_Remote_Troubleshooting Help topic.
at System.Management.Automation.Runspaces.AsyncResult.EndInvoke()
at System.Management.Automation.Runspaces.Internal.RunspacePoolInternal.EndOpen(IAsyncResult asyncResult)
at System.Management.Automation.RemoteRunspace.Open()
...
Note: This has nothing to do with the credentials in WSManConnectionInfo - just the account settings in the service properties "Log On" tab.
I don't want to give the service admin privileges. Any ideas why the LocalSystem user fails to log in?
Additional info:
The remote computer is not a member of a domain.
I have tried to connect both by IP address and hostname (both are listed in the local computer's TrustedHosts).
EDIT: Even more info (summary of the comments):
Local computer: Windows 7 Ultimate 64bit (virtual machine on a Windows 8 box).
Remote computer: Windows Server 2008R2 Datacenter 64bit.
The main reason we don't want to change service user accounts is that this is an update to an old service which is already deployed on many clients (customers).
The service also accesses the Windows registry and the file system on the local computer, so setting the user account to something more restricted, like NetworkService, would just open a different can of worms.

A rather surprising solution to this one: The username in the PSCredential object (cred) needed to be prefixed with the domain-less remote computer's name, e.g. "MYREMOTESERVERNAME\remoteusername" and not just "remoteusername".
I have no idea why the prefix is needed only when connecting with the LocalSystem account though...

Related

IBM.XMS MQ Listener Error 2063 or how to create connection without credentials

I'm trying to implement an MQ Listener in a windows service and I have used the xms mq consumer sample provided in the dotnet folder from the MQ Explorer installation. I am using MQ WebSphere 7.1
If I run their sample solution in console, everything works.
However, in my windows service it fails with MQ Reason Code: 2063.
I'm using these settings for my factory
cf.SetStringProperty(XMSC.WMQ_HOST_NAME, _queueHost);
cf.SetIntProperty(XMSC.WMQ_PORT, Convert.ToInt32(_queuePort));
cf.SetStringProperty(XMSC.WMQ_CHANNEL, "SYSTEM.DEF.SVRCONN");
cf.SetIntProperty(XMSC.WMQ_CONNECTION_MODE, XMSC.WMQ_CM_CLIENT_UNMANAGED);
cf.SetStringProperty(XMSC.WMQ_QUEUE_MANAGER, _queueChannel);
cf.SetIntProperty(XMSC.WMQ_BROKER_VERSION, 0);
and then this line seems to be failing
IConnection connection = cf.CreateConnection(null,null);
I don't want to provide any user credentials, is that possible?
I've tried changing the CONNECTION_MODE to bindings and getting different errors as well.
Is the sample code only working because I am running it and therefore it is using my local credentials by default? Otherwise I am using the same config in both.
The MQ XMS client is propagating the logged on user to the queue manager, then the QM checks its authority records to determine whether that user can connect and what objects it may access.
You could set the authority records to allow the user currently used to run the service, or you could set the logged on user on the windows service to match an allowed user of the queue manager, or set the MCAUSER property on the server connection channel used to connect to the queue manager, if you use client connection.
Setting the MCAUSER on the server connection channel will allow anyone who can connect to that channel to impersonate the set user, so this should be used with caution, possibly with setting appropriate channel authentication records.
References:
http://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.msc.doc/xms_rtrouble_tips.html
https://www-01.ibm.com/support/knowledgecenter/SSFKSJ_7.5.0/com.ibm.mq.sec.doc/q010530_.htm

PSRemotingTransportException in creating a Remote PowerShell Runspace in C#

I have the following code to connect to a remote computer:
var credential = new PSCredential(username, securePassword);
var rri = new WSManConnectionInfo(new Uri(uri), schema, credential)
{
AuthenticationMechanism = AuthenticationMechanism.Kerberos,
ProxyAuthentication = AuthenticationMechanism.Negotiate
};
var remoteRunspace = RunspaceFactory.CreateRunspace(rri);
remoteRunspace.Open();
But it's throwing the following exception:
System.Management.Automation.Remoting.PSRemotingTransportException was unhandled by user code
HResult=-2146233087
Message=Connecting to remote server sw-spdev02 failed with the following error message : WinRM cannot process the request. The following error with errorcode 0x80090311 occurred while using Kerberos authentication: There are currently no logon servers available to service the logon request.
Possible causes are:
-The user name or password specified are invalid.
-Kerberos is used when no authentication method and no user name are specified.
-Kerberos accepts domain user names, but not local user names.
-The Service Principal Name (SPN) for the remote computer name and port does not exist.
-The client and remote computers are in different domains and there is no trust between the two domains.
After checking for the above issues, try the following:
-Check the Event Viewer for events related to authentication.
-Change the authentication method; add the destination computer to the WinRM TrustedHosts configuration setting or use HTTPS transport.
Note that computers in the TrustedHosts list might not be authenticated.
The equivalent code in PowerShell ISE is working properly:
$cred = new-object -typename System.Management.Automation.PSCredential `-argumentlist 'domain\user', ('password' | ConvertTo-SecureString -AsPlainText -Force)
$session = New-PSSession http://servername -Credential $cred
As a hint, I was getting this exception in ISE too before I ran this script:
Set-Item -Path WSMan:\localhost\Client\TrustedHosts -Value http://servername
Another point is that, the computer which the script is running on, and the remote computer are in different domains.
Why am I getting this exception in C# and not in PowerShell ISE?
I don't know why! But I changed the code to this and it worked. I've just set the port number to 5985:
var rri = new WSManConnectionInfo(false, "sw-spdev02.mahanair.aero", 5985, "wsman",
"http://schemas.microsoft.com/powershell/Microsoft.PowerShell", credential)
{
ProxyAuthentication = AuthenticationMechanism.Negotiate,
AuthenticationMechanism = AuthenticationMechanism.Default,
};
Also I've used Username#Domain style instead of Domain\Username as #Donal said in the comments.
I you get that kind of an error when trying to initiate a remote connection and execute commands , most probably you are using the wrong credentials . You might want to cross check your credentials , use the credentials that you use to login to the machine.
Notice that am using the same credentials from the environment variables here:
Sometimes using the environment variables might mislead if your using your Microsoft account to login to your machine. Use your Microsoft credentials instead.
Now it works if you use the same credentials as your Microsoft Account.

Running self-hosted OWIN Web API under non-admin account

Is it possible for a self-hosted OWIN Web API to run under a non-administrator account? I have already tried dozens of url reservations and nothing works. The service fails to start with "Access is denied". It works when the account is added to the administrator role but I don't want that. Code below is running on Win 7 framework 4.5.2.
//install-package microsoft.owin.hosting
//install-package Microsoft.Owin.Host.HttpListener
StartOptions options = new StartOptions();
options.Urls.Add("http://localhost:5000/");
//options.Urls.Add(string.Format("http://{0}:5000", Environment.MachineName));
//options.Urls.Add("http://+:5000/");
//options.Urls.Add("http://*:5000/");
using (WebApp.Start<WebAPISelfHostMinimal.Startup>(options))
{
while (!Terminate)
{
await Task.Delay(10); //keep cpu from getting pegged
}
LogUtil.LogInfo("Terminating owin host.");
}
EDIT - this is running under a Windows account.
C:\>netsh http add urlacl http://+:5000/ user=mini2012\svcAPI
URL reservation successfully added
C:\>sc start apiservice
[SC] StartService FAILED 5:
Access is denied.
C:\>netsh http add urlacl http://*:5000/ user=mini2012\svcAPI
URL reservation successfully added
C:\>sc start apiservice
[SC] StartService FAILED 5:
Access is denied.
C:\>netsh http add urlacl http://localhost:5000/ user=mini2012\svcAPI
URL reservation successfully added
C:\>sc start apiservice
[SC] StartService FAILED 5:
Access is denied.
It looks like the problem was with the URL reservation. I didn't need one. If there is a URL reservation, it will just prevent the owin host from starting with the access denied error. Also, the default port for owin host is 5000. If there is a "dead" process that is still running on that port, it will block your service from starting. To check you can run netstat -a -b at the command prompt.
Your service is running (most likely) under the LocalSystem (SYSTEM) account. This account is not in the Everyone security principal.
In short, to solve this, either make the namespace reservation for Anonymous Logon or change your service to run under the Network Service account which happens to be in the Everyone principal.
Third option is, of course, to create a new local/domain user, create the reservation for it and have the service run under this account. But then you'd have to worry about setting proper security permissions for it, so I'd go with one of the first two options.
Run this command line under admin
netsh http add urlacl url=http://*:8080/ user=MyUser

HttpWebResponse: Windows service vs. console application

I have a problem that I haven't been able to resolve for two days.
In a console app, this code works fine:
url="http://www.reuters.com/finance/currencies/quote?srcAmt=1.00&srcCurr=USD&destAmt=&destCurr=ASD&historicalDate=MMddyyyy"
HttpWebRequest req = WebRequest.Create(url) as HttpWebRequest;
req.Timeout = 3000000;
using (HttpWebResponse resp = req.GetResponse() as HttpWebResponse)
{
// ...
}
But in my Windows service, GetResponse() is throwing the exception, "The remote name could not be resolved: 'www.reuters.com'".
I have no idea what I am doing wrong, maybe I am setting something wrong in ServiceInstaller.
Thanks for showing me the right track, but there is an additional issue.
I am working on virtual machine (I have got admin rights, but I have no experience with administration at all).
If I set account in service installer for the user (and give details of my login) then I have problems with the connection to the database (Odbc). Connection open throws me:
ERROR [08001] [MERANT][ODBC Sybase driver]
Allocation of a Sybase Open Client Context failed.
Sybase normally generates a SYBINIT.ERR file containing more specific reasons for failing.\r\n
ERROR [01S00] [MERANT][ODBC Sybase driver]
Invalid attribute in connection string: Port.
So if set Account User in ServiceInstaller I can't connect to the DB, else if I set Account to LocalSystem I can open connection to DB but I can't use GetResponse().
So the question is, what should I do when everything is placed on Windows Terminal Server?
I suppose that there could be something messed up with admin rights. What could I do to fix this? Thanks again.
Windows Service application run under the LocalSystem account by default, whereas your console app runs under your user account, you may therefore be meeting permission problems (windows firewall?)
You should run the service under the administrator account to see if this resolves your issue.

Can't resolve DNS

I'm trying to consume a webmethod but it seems that my application can't resolve DNS. The problem surfaces when I configure my application with an url (e.g.: http://mywebservice.com/webservice/methods.asmx), but it does not when I access the same webmethod through the server's IP address.
The thing is that I need to access the webservice using the url and not the IP address due to an existing DHCP server policy.
Can anyone help me ?
Thanks in advance.
UPDATE: Checking out what moocha asked me to do, I found out that:
D:>nslookup server.com
Server: dnsserver.mycompany.com
Address: XXX.YYY.XXX.YYY
*** dnsserver.mycompany.com can't find server.com: Non-existent domain
Have you tried confirming the same DNS query works via nslookup from the same system on which your application runs?
I.e.,
C:\>nslookup
Default Server: whatever.dns.example.org
Address: 111.222.333.111
> set q=a
> mywebservice.com
Server: whatever.dns.example.org
Address: 111.222.333.111
Non-authoritative answer:
Name: mywebservice.com
Address: 208.254.26.139
Digging a little bit more I found that there is a proxy in between my PC and the server. Therefore, I'm oblied to log with a valid user in order to access the internet. The problem was that my application's server (where the IIS is running) was configured to run using anonymous access. All I had to do was to configure in the IIS an user that has permission to access the internet (through the proxy). Finally the problem is solved.
There was another option, I could use the logged user's credentials to grant access through the proxy; but that required that all users use the same log in information for the application and the intranet.

Categories

Resources