Powershell call through C # in a web application - problems with application pool id

I wrote a few things to run Powershell through C # using RunspaceFactory.

I load the default Powershell profile as follows:

Runspace runspace = RunspaceFactory.CreateRunspace(); runspace.Open(); string scriptText = @". .\" + scriptFileName + "; " + command; Pipeline pipeline = runspace.CreatePipeline(scriptText); 

Command = function from the profile that I know.

All this Powershell stuff is wrapped in an Impersonator.

For the avoidance of doubt, $ profile = C: \ Users \ Administrator \ Documents \ WindowsPowerShell \ Microsoft.PowerShell_profile.ps1

This is a web application running under IIS 7.5.

If the IIS application runs under the "administrator" account, it works. Under any other account, it gives an error:

"Term". \ Microsoft.PowerShell_profile.ps1 "is not recognized as the name of the cmdlet, function, script file or executable program. Check the spelling of the name or if the path was included, check the path and try again."

Since I impersonate the administrator account, I assumed that the location would be correct.

In some logs with called get-location reports, the directory is what it should be.

Due to the bloodshed, I tried to force him:

  System.Environment.CurrentDirectory = dir; 

... as well as an attempt to call "set-location". This works, but if I call "get-location" from the workspace, it reports the same directory as before (correct).

I thought that there might be an impersonation problem, so I wrote several tests that deal with the file system in ways that the application pool should not do. These work.

I also checked this:

 string contextUserName = System.Security.Principal.WindowsIdentity.GetCurrent().Name; 

What the correct user reports when the code is "wrapped" in the impersonator, and when it is executed through the application pool identifier. Then I despaired and tried to call:

  @"cmd /c dir" 

... (as well as get-Childitem). Both teams are returned:

 {} 

... when working under the application pool identifier (regardless of impersonation), but a complete and accurate list of directories in the correct directory when the application pool works as an "administrator".

I am sure that I am missing something stupid and fundamental here, if someone could give me some advice on where I made a mistake in my thinking (and code), that would be great.

+4
source share
1 answer

This is a kind of β€œwell-known” problem with using PowerShell in ASP.NET when in an impersonal context: it doesn't work the way people think it should work.

The reason for this is that PowerShell, behind the covers, spins another thread to actually do all its work. This new thread inside PowerShell does not inherit the impersonated context.

The fix is ​​not entirely beautiful. This MSDN blog post recommends setting up ASP.NET to always pass impersonation policies (so that the thread behind the scenes gets an identity):

 <configuration> <runtime> <legacyImpersonationPolicy enabled="false"/> <alwaysFlowImpersonationPolicy enabled="true"/> </runtime> </configuration> 

Another, even more ugly approach (albeit less hacks) is to use WinRM . You can use a PowerShell loopback session (connect to the local host) using PowerShell and let WinRM handle the impersonation. This requires version 3.0.0.0 of System.Management.Automation.

 var password = "HelloWorld"; var ss = new SecureString(); foreach (var passChar in password) { ss.AppendChar(passChar); } var psCredential = new PSCredential("username", ss); var connectionInfo = new WSManConnectionInfo(new Uri("http://localhost:5985/wsman"), "http://schemas.microsoft.com/powershell/Microsoft.PowerShell", psCredential); using (var runspace = RunspaceFactory.CreateRunspace(connectionInfo)) { connectionInfo.EnableNetworkAccess = true; using (var powershell = PowerShell.Create()) { 

It is also a sticky solution because it requires running WinRM Windows Service and configuring WinRM. WinRM is not exactly what β€œjust works”, but doing the first job is not suitable.

The URL used in WSManConnectionInfo is the endpoint of the local WinRM host, by default it listens on port 5985 in version 3, and credentials are specified for the connection.

+3
source

Source: https://habr.com/ru/post/1500593/


All Articles