I am attempting to remotely call an executable on a target machine, with the executable located on a UNC network path. I am using the Win32_Process.Create method to do this. I am able to use this method to launch files that are stored locally on the C: drive, but I get Return Value 2, Access Denied, when I try to launch the file from a UNC path. I am confident the path is correct, because if I alter it to a bogus path, I get Return Value 9, Path Not Found.
In Powershell I am using invoke-wmimethod to call the Create method of Win32_Process and passing a credential object that has administrative rights on the target system and read rights on the UNC path. In C# I am impersonating using ConnectionOptions with the same credentials. The results are the same in both cases.
I have also tried using various methods (CIM_DataFile, remotely invoking XCopy) to copy the EXE file locally first. None of these methods have worked. I want to copy directly from a file server, to a target system, without pulling the file to the application server first, because the application server is not in the same datacenter as most target systems and as such would be pulling a large file down over the WAN twice, which is slow and less reliable. One option I have found is to use FTP, but I consider that a last resort.
I can also remotely invoke the EXE from the UNC path using PSExec and the same credentials, but I want to avoid shelling out from my web application to call PSExec. I know it will work if that's what I have to do, and I have used PSExec many times to solve problems like this, but I really want to do this all within the application and not hacking around it using an external program.
Is there any way I can use Win32_Process to launch an EXE on a remote machine, when that EXE is located on a UNC path? Could this be a Group Policy issue wherein the process launched by WMI does not have permission to invoke an EXE from a network location? I am out of ideas and out of search terms.
Powershell code examples. This works:
$launchproc = Invoke-WmiMethod -ComputerName $compName -Class Win32_process -Name Create -ArgumentList "c:\temp\installer.exe /s /f1c:\temp\installer.iss" #-Credential $adminCreds
This does not:
$launchproc = Invoke-WmiMethod -ComputerName $compName -Class Win32_process -Name Create -ArgumentList "\\fileserver\share\installer.exe /s /f1\\fileserver\share\installer.iss" -Credential $adminCreds
Note that if I issue the command locally from a command window, interactively, the UNC based command DOES work just fine. The funny syntax is an artifact of InstallShield's silent install switches. Also note that if I double-backslash or backtick escape the backslashes, I get Path Not Found, so I don't think it's an escaping issue.
Edit: while not exactly the same problem, I did check the GP rights described here: WMI Win32_Process.Create fails with Insufficient Privs and I do have those rights set correctly.
Edit #2: I found someone else having a similar problem:
Win32_Process Create method. Trying to copy a file from a remote machine to a remote machine Again it's a batch file-ish hack launching Net Use on the remote system. Is this my only real option?
In the end, I just called PsExec using System.Diagnostics.Process() in C#. It's not the solution I wanted, but I wasn't able to make anything else work, and while I don't like shelling out to an external EXE, it does end up being relatively straightforward.
I asked some of the PowerShell MVPs who are more knowledgeable in WMI and got the response that unless the remote machine was the domain controller you won't be able to do it. However, if you could use PowerShell remoting to remote to the computer with -Authentication CredSSP, then you could use Invoke-WmiMethod with the network path. Richard Siddaway did a write up on this that might be useful to peruse.
Related
I have been trying to launch text pad installation from network path to a remote machine using WMI managementclass.InvokeMethod.
However several attempts have failed with
error code 1602
So I created a batch file containing script to launch installation executable from network path in a remote machine, and tried to invoke it with managementclass.InvokeMethod.
However, even this didn't work.
I tried the same by changing the executable from network path to remote machine C:\path.
And it worked!!!
But I want to launch the installation executable from a network path.
I would be grateful if somebody would help me.
I have already switch on the telnet option on control panel - program/features.
Though telnet worked fine manually, but when I run below from my C# library, I am getting this error :
"'telnet' is not recognized as an internal or external command,
operable program or batch file."
This is the code I use to start Telnet:
Process.Start("cmd", "/k telnet")
What makes the difference between this and running it from the command prompt manually and how do I overcome this difference?
Telnet is a program, always installed in the system folder. Which also means, it's always in the path. You don't need to start cmd.exe in order to start telnet.exe. Just use
Process.Start("telnet.exe");
Use the arguments parameter to pass arguments to telnet itself, eg the host, log file etc:
Process.Start("telnet.exe","localhost 80 -f mylog.txt");
There other, probably better options.
Use a Telnet Library
You can use a Telnet library and connect to a server directly, eg using the Telnet NuGet package :
using (Client client = new Client("localhost",80, new System.Threading.CancellationToken()))
{
await client.WriteLine("abcd");
string response = await client.ReadAsync();
Console.WriteLine(response);
}
Use PowerShell
Telnet is often used to test connectivity to a web server, not to actually send commands. In this case, you could use PowerShell's Test-NetConnection to receive diagnostics about the connection:
using System.Management.Automation;
var ps = PowerShell.Create()
.AddCommand("test-netconnection")
.AddArgument("localhost")
.AddParameter("CommonTCPPort", "HTTP");
var results = cmd.Invoke();
foreach (dynamic result in results)
{
Console.WriteLine($"{result.TcpTestSucceeded} {result.SourceAddress}");
}
Make sure you add the correct Powershell NuGet package, Microsoft.PowerShell.5.ReferenceAssemblies, not the unsupported and abandoned System.Management.Automation package
The advantage of PowerShell is that you can chain commands and scripts together just by adding more AddComand, AddScript calls. Each command will receive the output of the previous one. You could use Import-CSV to read a list of servers and ports from a file and pipe the output to Test-NetConnection
On installing Telnet Client via Control Panel - Programs and Features - Turn Windows features on or off there is installed telnet.exe into directory %SystemRoot%\System32.
The directory %SystemRoot%\System32 is for 64-bit applications on 64-bit Windows. Therefore the installed executable telnet.exe is also the 64-bit version. This directory contains also the 64-bit version of cmd.exe.
System environment variable PATH contains %SystemRoot%\System32 which is responsible for finding %SystemRoot%\System32\cmd.exe and %SystemRoot%\System32\telnet.exe when being executed without file extension and without path.
But there is additionally the directory %SystemRoot%\SysWOW64 for 32-bit applications containing the 32-bit versions of the executables.
Microsoft explains with the documentation pages WOW64 Implementation Details and File System Redirector how a file system access to %SystemRoot%\System32 by a 32-bit application is redirected automatically to %SystemRoot%\SysWOW64.
There is no 32-bit version of telnet.exe installed into %SystemRoot%\SysWOW64 on installing Telnet Client.
So what happens on:
Process.Start("cmd", "/k telnet")
When the C# library is compiled as 64-bit library used by a 64-bit application, 64-bit Windows finds and starts %SystemRoot%\System32\cmd.exe which finds and then starts %SystemRoot%\System32\telnet.exe.
But when the C# library is compiled as 32-bit library used by a 32-bit application, 64-bit Windows finds and starts via file system redirector %SystemRoot%\SysWOW64\cmd.exe which cannot find telnet.* with a file extension listed in environment variable PATHEXT in current directory or any directory of environment variable PATH because there is no file telnet.exe in directory %SystemRoot%\SysWOW64.
The best solution is definitely to use a static (or dynamic) telnet library in the C# library to be independent on telnet.exe as suggested by Panagiotis Kanavos. In my point of view it is a shame for every C# programmer using external executables via a process call for which C# code can be quite easily also written by the programmer. Using any world wide web search engine with the search term C# telnet returns lots of pages with solutions, for example C# Telnet Library on Stack Overflow.
Of course it is also possible to get first value of environment variable SystemRoot using GetEnvironmentVariable method to get path to Windows directory, or even better using GetWindowsDirectory or GetSystemWindowsDirectory method.
Then concatenate this string value with "\\System32\\telnet.exe" to a new string and check if the file with that full path exists using File.Exists method. If that file exists on 32-bit Windows with 32-bit version of telnet.exe installed if C# application is also a 32-bit application or on 64-bit Windows with 64-bit telnet.exe installed if C# application is a 64-bit application, then this file name with full path and file extension can be used in a process call.
Otherwise concatenate the Windows directory path with "\\Sysnative\\telnet.exe" and check if file with that full path exists. If this is true on 64-bit Windows with 64-bit version of telnet.exe installed if C# application is a 32-bit application, it would be possible to run from within 32-bit application the 64-bit telnet client executable using this path.
But if that fails also, telnet.exe is not installed at all which is the reason why usage of telnet.exe from within a C# code application is in general not advisable.
Honestly, I don't understand why to have code in a C# library which just starts a command process executing telnet.exe without options and therefore requiring user input and which keeps the command process running after telnet client session terminated. The C# library function can be replaced by a shortcut to telnet.exe on Windows desktop or in Windows start menu of the user.
I have programmed a Windows Service that is calling another service over the network.
The other service's IP is defined in the hosts file.
The Windows Service is running as local system.
On Windows Server 2008 this works fine. The IP from the hosts file is used.
On Windows 7, the IP from the hosts file is not used. Instead it uses normal DNS.
If I use a normal user instead of local system, the behaviour is correct. The same as on Windows Server 2008. The host file is used.
I can reliably switch between local system and a normal user for the same service binary without touching the hosts file, the error is reproducable. So it's not about caching anything anywhere or having a wrong hosts file.
Is there anything in Windows 7 I missed? Why would a service running as local system not use the hosts file?
The reason why it works as normal user could be this: you could have a duplicate hosts file in %LOCALAPPDATA%\VirtualStore, which is a redirection folder for programs running as non-admin and trying to write to system locations. If this is the case, then you actually see wrong hosts file when you think you edit the system's one!
The other reason could be wrong permissions set to file. Please try point 5 from https://serverfault.com/a/452269
First close other runnings applications and have a look at your system logs
You can run anything as system to debug like explorer.exe or cmd.exe
with the folowing command using PSTools you could then browser your hosts and check it
psexec -i -s cmd.exe
psexec -i -s ping your.host
Avoid multiple entry for the same host on hosts file
Even if you talked about it i post some debug commands
ipconfig /flushdns
nbtstat -R (reset netbios)
You can check DNS Cache
ipconfig /displaydns | more
Windows set the hosts file location with this registry key
\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\DataBasePath
Check proxy config it could bypass hosts
Check "etc" directory permission and "hosts" file permission
I am trying to create a setup package that not only installs our app but also copies files to a remote app server and installs a service there. I thought that I would just override the install method in a custom action to have it kick off a powershell script to copy the files. Unfortunately when the code calls the powershell script I get this CmdletProviderInvocationException:
The system detected a possible attempt to compromise security. Please ensure that you can contact the server that authenticated you.
I was able to copy the code I am using to call the powershell script into a test project and it ran just fine, as I would expect since I have logged in to the server through windows explorer and so my user should be authenticated. I think the reason the script won't work when called by the installer must be that the installer switches users in order to get admin permissions to install the app, and the admin user is not authenticated (although I could be wrong).
Does anyone know how I could get this to work?
Here's the custom action code:
Runspace runspace = RunspaceFactory.CreateRunspace();
runspace.Open();
Pipeline pipeline = runspace.CreatePipeline();
string scriptLoc = "c:\\sampleLocation";
pipeline.Commands.AddScript("&\"" + scriptLoc + "\\script.ps1\"");
Collection<PSObject> results = pipeline.Invoke();
runspace.Close();
and here's the script:
$RemotePath = "\\SERVER\C$\Shared\Service"
$Source = "C:\sampleLocation\Service"
Get-ChildItem $Source -Recurse | Copy-Item -Destination $RemotePath
There are two major requirements for copying files to a network location:
your custom action should run without impersonation
the network location should have full permissions for Everyone
A MSI installation runs under the local system account. So it doesn't matter if you have permissions or not.
Since it's not easy to give permissions to SYSTEM account from a network machine, the easiest approach is to give full permissions to Everyone. This needs to be done on the machine which contains the shared folder.
According to #Cosmin Pirvu and Microsoft documentation :
The LocalSystem account is a predefined local account used by the service control manager. It has extensive privileges on the local computer, and acts as the computer on the network.
If your shared folder is on a computer that is on a domain, you can give full permissions to the client computer in spite giving it to Everyone.
I have the following in a vbs file that i am trying to run from the command line:
strServerName = "ServerName"
strAppPoolName = "DefaultAppPool"
set objAppPools = GetObject("IIS://" & strServerName
& "/w3svc/AppPools/" & strAppPoolName & "")
objAppPools.Recycle()
And yet when I run the vbs from cmd line i get the following error:
Microsoft VBScript runtime error: ActiveX component can't create object: 'Get Object'_
I am running XP on my local machine, and the remote machine has IIS 7.
How can I get this to work?
I am not sure regarding the particular vb script but I would recommend using "appcmd" (http://learn.iis.net/page.aspx/114/getting-started-with-appcmdexe)
Add %windir%\system32\inetsrv to your path if it is not already
in a command prompt type: appcmd recycle apppool "apppool_name"
While not a vbs file command you could get vbs to execute this command line;
appcmd recycle apppool /apppool.name:string
The variable string is the name of the application pool that you want to recycle. For example, to recycle an application pool named Marketing, type the following at the command prompt, and then press ENTER:
appcmd recycle apppool /apppool.name:Marketing
Taken from technet
If it's too far away from what you want then my apologies.
Use powershell command to run it. Example:
Invoke-WMIMethod Recycle -Path "IIsApplicationPool.Name='W3SVC/APPPOOLS/apppoolname'" -Computer "WIN-Computername" -Namespace root\MicrosoftIISv2 -Authentication PacketPrivacy
Where apppoolname is your application pool name.
Where WIN-Computername is your remote/local server name
Use powershell to execute command remotely on the server:
Invoke-Command -ComputerName <YOUR_IIS_SERVER_NAME> -ScriptBlock { Restart-WebAppPool -Name <YOUR_APP_POOL_NAME> }
I just tried it from a Windows XP machine to Windows 2008R2 machine. It worked. So you are definitely on the right track.
If you are looking for an alternative way, try this from a command prompt. At least the error message will be a little more specific, when it doesn't work.
wmic /namespace:"\\root\MicrosoftIISv2" /node:"**serverName**" path IISApplicationPool where (name like '%**DefaultAppPool**%') call recycle
Have you got the IIS7 WMI Provider installed and enabled on the remote machine?
I think this doc covers most of what you need.
this covers pre req and how to browse the available management options...sure you'll be able to reset the app pool with a few tweaks...
I just stumbled upon this problem, and here's the fix:
There is a small windows tool called PsExec, which basically gives you command line remote access, and from there you can use apppool. You can just run this command from C#
psexec \\192.168.xx.xx %windir%\system32\inetsrv\appcmd recycle apppool /apppool.name:yourapppool
here's the tool: http://technet.microsoft.com/en-us/sysinternals/bb897553.aspx
Following commands worked for me after trying everything !
cd %windir%\system32\inetsrv
appcmd.exe stop site /site.name:"test1.com"
appcmd.exe start site /site.name:"test1.com"
Obviously before these, you will run some ssh remote command as well