c# - 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.
解决方案
最有可能失败的是对外部程序的调用,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.exe
,logoff.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 位应用程序可见)显式引用它们:
- 您可以尝试调用64 位版本,通过虚拟目录
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
。