首页 > 解决方案 > Not able to run power shell script in.Net console app using System.automation.management(Power shell package)

问题描述

Hi I am creating an software where it should loggOff all except currently logged in user in Windows 10 system. I am able loggoff using a powershell command in powershell. find command below:

quser | Select-String "Disc" | ForEach{logoff ($_.toString() -split ' +')[2]}

The above command perfectly works with powershell console.

When add it into my code c# and invoke the command its not working. Please find the code below.

string logOff = "quser | Select-String \"Disc\" | ForEach{logoff ($_.toString() -split ' +')[2]}";
PowerShell psExec = PowerShell.Create();
psExec.AddScript(logoff);
Collection<PSObject> results;
results = psExec.Invoke();

I have also tried by spawning child process of power shell. Please check code below:

 processInfo = new ProcessStartInfo
 {
  UseShellExecute = false,
  FileName = "powershell.exe",
  Arguments = "quser | Select-String \"Disc\" | ForEach{logoff ($_.toString() -split ' +')[2]}"
 }
 Console.WriteLine("Starting child process...");
 using (var process = Process.Start(processInfo))
  {
   process.WaitForExit();
  }

I have also tried as below:

            using (PowerShell ps = PowerShell.Create())
            {
                ps.AddScript("‪C:\\Users\\vijay.rm\\Desktop\\test.ps1");

                Collection<PSObject> PSOutput = ps.Invoke();

                foreach (PSObject item in PSOutput)
                {
                    if (item == null)
                    {
                        Console.WriteLine(item.BaseObject.ToString());
                        Console.WriteLine("Done");
                    }
                }
            }

where test.ps1 script contains:

quser | Select-String \"Disc\" | ForEach{logoff ($_.toString() -split ' +')[2]}

I have also checked with build by changing it to x86 and x64 but the result is same.

I didn't get any exceptions.

But also i didn't get users logged off.

I have also tried console app with adminstrative privilages.

I am expecting that when run c# code, all users except user who is logged in the computer should loggoff. In order to check weather an user is logged Off or not, run below command in powershell:

Get-WMIObject -class Win32_UserProfile

You will get results something like this below:


__GENUS                          : 2
__CLASS                          : Win32_UserProfile
__SUPERCLASS                     :
__DYNASTY                        : Win32_UserProfile
__RELPATH                        : Win32_UserProfile.SID="S-1-5-21-329068152-1454471165-1417001333-8355646"
__PROPERTY_COUNT                 : 29
__DERIVATION                     : {}
__SERVER                         : BDC3-LX-G5N6QQ2
__NAMESPACE                      : root\cimv2
__PATH                           : \\BDC3-LX-G5N6QQ2\root\cimv2:Win32_UserProfile.SID="S-1-5-21-329068152-1454471165-14
                                   17001333-8355646"
AppDataRoaming                   : System.Management.ManagementBaseObject
Contacts                         : System.Management.ManagementBaseObject
Desktop                          : System.Management.ManagementBaseObject
Documents                        : System.Management.ManagementBaseObject
Downloads                        : System.Management.ManagementBaseObject
Favorites                        : System.Management.ManagementBaseObject
HealthStatus                     : 3
LastAttemptedProfileDownloadTime :
LastAttemptedProfileUploadTime   :
LastBackgroundRegistryUploadTime :
LastDownloadTime                 :
LastUploadTime                   :
LastUseTime                      : 20190917044128.412000+000
Links                            : System.Management.ManagementBaseObject
Loaded                           : True
LocalPath                        : C:\Users\vijay.rm
Music                            : System.Management.ManagementBaseObject
Pictures                         : System.Management.ManagementBaseObject
RefCount                         :
RoamingConfigured                : False
RoamingPath                      :
RoamingPreference                :
SavedGames                       : System.Management.ManagementBaseObject
Searches                         : System.Management.ManagementBaseObject
SID                              : S-1-5-21-329068152-1454471165-1417001333-8355646
Special                          : False
StartMenu                        : System.Management.ManagementBaseObject
Status                           : 0
Videos                           : System.Management.ManagementBaseObject
PSComputerName                   : BDC3-LX-G5N6QQ2

In that loaded property should be false when we run the script or code.

Thanks in advance.

标签: c#powershell

解决方案


最有可能失败的是对外部程序的调用,quser.exe并且logoff.exe(可能是后者-我强烈怀疑您需要运行管理权限才能注销其他用户的会话)。

外部程序输出的stderr 消息显示在 PowerShell 的错误流中,但它们不会导致异常,因此您的代码会安静地运行和失败(类似地,报告非零退出代码
的外部程序不会导致 PowerShell 采取任何操作。

要查看出了什么问题,您必须检查psExec.Streams.Error,即调用期间收集的错误消息。


在评论中,您声明在检查错误流时,您发现那里的错误消息抱怨quser没有作为命令 ( The term 'quser' is not recognized as the name of a cmdlet, function, script file, or operable program. ...) 被发现。

这表明了两个可能的原因之一(结果是(a)):

  • 任一 (a):您的 System32 文件夹(通常为C:\Windows\System32)莫名其妙地未列在您的Path环境变量 ( $env:Path) 中,但这将是非常不寻常的,值得进一步调查。

    • 同时作为一种解决方法:虽然您可以尝试通过它们的完整路径进行引用quser.exelogoff.exe但它为您提供了更大的灵活性,可以将 System32 文件夹$env:PATH作为第一个命令添加到。
string logOff = "$env:PATH += \";$env:windir\\System32\"; quser.exe | Select-String \"Disc\" | ForEach{logoff.exe ($_.toString() -split ' +')[2]}";
  • 或者 (b):您的 C# 代码使用32 位版本的 PowerShell SDK,并且在 32 位应用程序所看到的不同目录中C:\Windows\System32(实际上是C:\Windows\SysWow64),既不quser.exe也不logoff.exe存在。

    • 您可以尝试调用64 位版本,通过虚拟目录C:\Windows\SysNative[1](仅对 32 位应用程序可见)显式引用它们:
string logOff = "C:\\Windows\\SysNative\\quser.exe | Select-String \"Disc\" | ForEach{C:\\Windows\\SysNative\\logoff.exe ($_.toString() -split ' +')[2]}";

[1] 注意:我假设您的 Windows 安装的根目录是C:\Windows; 即使它位于不同命名的目录中,一种可靠地引用它的方法是使用$env:windir而不是 literal C:\Windows


推荐阅读