C# 中未获取 Powershell 结果集
Posted
技术标签:
【中文标题】C# 中未获取 Powershell 结果集【英文标题】:Powershell resultset not being picked up in C# 【发布时间】:2017-05-14 07:41:05 【问题描述】:单击 button1 时,将执行以下代码,该代码将运行 PowerShell 脚本以获取当前的 SQL Server 实例。但是,当它运行时,结果集(结果变量)从 PowerShell 输出中计数为 0 行。当我在本机 PowerShell 中运行相同的代码时,它会显示 3 行的实例名称。
如果我遗漏了什么,谁能告诉我?
private void button1_Click(object sender, EventArgs e)
//If the logPath exists, delete the file
string logPath = "Output.Log";
if (File.Exists(logPath))
File.Delete(logPath);
string[] Servers = richTextBox1.Text.Split('\n');
//Pass each server name from the listview to the 'Server' variable
foreach (string Server in Servers)
//PowerShell Script
string PSScript = @"
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string] $server)
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force;
Import-Module SQLServer;
Try
Set-Location SQLServer:\\SQL\\$server -ErrorAction Stop;
Get-ChildItem | Select-Object -ExpandProperty Name;
Catch
echo 'No SQL Server Instances';
";
//Create PowerShell Instance
PowerShell psInstance = PowerShell.Create();
//Add PowerShell Script
psInstance.AddScript(PSScript);
//Pass the Server variable in to the $server parameter within the PS script
psInstance.AddParameter("server", Server);
//Execute Script
Collection<PSObject> results = new Collection<PSObject>();
try
results = psInstance.Invoke();
catch (Exception ex)
results.Add(new PSObject((Object)ex.Message));
//Loop through each of the results in the PowerShell window
foreach (PSObject result in results)
File.AppendAllText(logPath, result + Environment.NewLine);
// listBox1.Items.Add(result);
psInstance.Dispose();
【问题讨论】:
这是 Windows 窗体应用程序还是其他什么?如果有别的,是什么? 是的。我已经添加了 WinForms 标签,谢谢。 检查 PowerShell 对象的HadErrors
属性。如果是真的,您需要阅读Streams
.Error
属性并检查错误。 CmdLet 可能已写入非终止错误。
HadErrors 属性在调用 powershell 脚本时返回 false @TravisEz13
代码看起来基本正确。我更新它以根据我使用$server
输入的路径执行Get-ChildItem
,代码将输出写入output.log
。你从哪里得到SQLServer
模块?如果 SQL 附带 SQL 是什么版本的 SQL?是否需要安装选项才能获得它?你得到的是No SQL Server Instances
还是零行?
【参考方案1】:
为了得到一个可能的 PowerShell 错误,我会尝试 sth。像这样:
private void button1_Click(object sender, EventArgs e)
//If the logPath exists, delete the file
string logPath = "Output.Log";
if (File.Exists(logPath))
File.Delete(logPath);
string[] Servers = richTextBox1.Text.Split('\n');
//Pass each server name from the listview to the 'Server' variable
foreach (string Server in Servers)
//PowerShell Script
string PSScript = @"
param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string] $server)
Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force;
Import-Module SQLServer;
Try
Set-Location SQLServer:\\SQL\\$server -ErrorAction Stop;
Get-ChildItem | Select-Object -ExpandProperty Name;
Catch
echo 'No SQL Server Instances';
";
using (PowerShell psInstance = PowerShell.Create())
psInstance.AddScript(PSScript);
psInstance.AddParameter("server", Server);
Collection<PSObject> results = psInstance.Invoke();
if (psInstance.Streams.Error.Count > 0)
foreach (var errorRecord in psInstance.Streams.Error)
MessageBox.Show(errorRecord.ToString());
foreach (PSObject result in results)
File.AppendAllText(logPath, result + Environment.NewLine);
// listBox1.Items.Add(result);
【讨论】:
更仔细地查看代码,该代码捕获所有错误,然后使用echo
(write-output
的别名)在出现错误时输出字符串。所以大多数错误实际上会导致结果,而不是错误。另外,在写这条评论之前,有一条评论说HadErrors
属性是假的。【参考方案2】:
它不起作用的原因是psInstance.AddParameter
仅向命令添加参数,它不适用于脚本。 You'll need to find another way of getting the $server parameter into the script. 试试这两个 powershell 示例,看看我的意思。第一个将输出所有进程(忽略 AddParameter),而第二个仅显示 svchost 进程。
1)
$ps = [system.management.automation.powershell]::create()
$ps.AddScript("get-process")
$ps.AddParameter("name","svchost")
$ps.invoke()
2)
$ps = [system.management.automation.powershell]::create()
$ps.AddCommand("get-process")
$ps.AddParameter("name","svchost")
$ps.invoke()
【讨论】:
当我将 Powershell 代码更改为Try echo $server;
时,它会返回预期的变量,所以这不是问题。它确实没有问题地传递参数【参考方案3】:
我设法通过使用 Win32_service 而不是 SQLPS 解决了这个问题。
Param([Parameter(Mandatory = $true, ValueFromPipeline = $true)][string] $server)
$localInstances = @()
[array]$captions = GWMI Win32_Service -ComputerName $server | ?$_.Name -match 'mssql *' -and $_.PathName -match 'sqlservr.exe' | %$_.Caption
ForEach($caption in $captions)
if ($caption -eq 'MSSQLSERVER')
$localInstances += 'MSSQLSERVER'
else
$temp = $caption | %$_.split(' ')[-1] | %$_.trimStart('(') | %$_.trimEnd(')')
$localInstances += ""$server\$temp""
$localInstances;
【讨论】:
以上是关于C# 中未获取 Powershell 结果集的主要内容,如果未能解决你的问题,请参考以下文章