参考路径:http://www.cnblogs.com/LanTianYou/p/4727496.html
做过一个多进程监控的自动关机工具,详见那篇blog。
这次领导又加了需求,说要等进程监控结束后,不止需要关闭主控端server,还需要关闭其他servers。于是就用到了我上篇文章所介绍的知识——通过PowerShell来远程管理计算机。
由于PowerShell和C#都是基于.NET的,所以也不需要胶水把这两种语言粘合到一起。可以充分的利用两者各自的优点,结合到一起!(PowerShell在远程管理server这方面是很擅长的。)
于是我修改了之前的工具UI界面,多出了两个textbox,分别用来选择server配置文件(需要关闭的除主控端的server的相关信息都记录在该配置文件中)和PowerShell脚本文件(主要负责远程方面的操作):

server配置文件格式如下,一行对应一台server,每一行中的server ip、用户名、密码用空格隔开:

选用的PowerShell脚本文件代码如下:
function ShutDownRemoteComputers
{
param($ip,$user,$pwd)
#winrm s winrm/config/client '@{TrustedHosts=10.1.23.60"}'
$sen = "'@{TrustedHosts=`""+$ip+"`"}'"
winrm s winrm/config/client $sen
$pw = convertto-securestring -AsPlainText -Force -String $pwd
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $user,$pw
$session = New-PSSession $ip -Credential $cred
icm $session {shutdown -s -t 0}
}
Winform程序在主控端结束进程检查后,会先关闭server配置文件中的servers,然后关闭主控端server(本机)。
代码如下(粉色部分为新加的和远程相关的主要内容):
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Diagnostics;
using System.Text.RegularExpressions;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
namespace AutoShutDown2
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private void chooseFileButton_Click(object sender, EventArgs e)
{
OpenFileDialog fileName = new OpenFileDialog();
fileName.Filter = "文本文件|*.*|C#文件|*.cs|所有文件|*.*";
if (fileName.ShowDialog() == DialogResult.OK)
{
filePath.Text = fileName.FileName;
}
}
private void filePath_Click(object sender, EventArgs e)
{
filePath.Text = "";
}
private void startButton_Click(object sender, EventArgs e)
{
if (filePath.Text.ToString().Substring(filePath.Text.Length - 3, 3) == "txt")
{
if (Regex.IsMatch(duration.Text, "^([0-9]{1,})$"))
{
if (int.Parse(duration.Text) >= 30)
{
if (serverFilePath.Text == "")
{
MessageBox.Show("You should choose a server configuration file first.");
}
else
{
MessageBox.Show("PCAS will check with a duration of " + duration.Text + "s.");
this.Hide();
//Check the processes with the duration.
DurationStart();
}
}
else
{
MessageBox.Show("The integer number should be greater than 30 seconds.");
}
}
else
{
MessageBox.Show("You can only type in an integer for duration.");
duration.Text = "";
}
}
else
{
MessageBox.Show("You can only choose a txt to be a configuration file.");
filePath.Text = "";
}
}
private void DurationStart()
{
//Check the process's status with the duration.
System.Timers.Timer tmr = new System.Timers.Timer(int.Parse(duration.Text)*1000);
tmr.Elapsed += new System.Timers.ElapsedEventHandler(CheckProcess);
tmr.AutoReset = true;
tmr.Enabled = true;
}
private void CheckProcess(object source, System.Timers.ElapsedEventArgs e)
{
//Check the processes's status in the config file.
using (FileStream fs = new FileStream(filePath.Text, FileMode.Open))
{
using (StreamReader sr = new StreamReader(fs))
{
string line;
int numOfTheProcesses = 0;
while ((line = sr.ReadLine()) != null)
{
var processes = System.Diagnostics.Process.GetProcesses();
foreach (var process in processes)
{
if (process.ProcessName == line)
{
//Find the objective process.
//MessageBox.Show(line);
numOfTheProcesses++;
}
}
}
if (numOfTheProcesses == 0)
{
//No such process, shut down the computer.
//MessageBox.Show("The computer is ready to be shut down.");
//Shut down the computer
ShutDown();
}
sr.Close();
}
fs.Close();
}
}
private void ShutDown()
{
//Shut down the other computers.
ShutDownOthers(serverFilePath.Text, scriptPathText.Text);
//Shut down this computer.
System.Diagnostics.Process myProcess = new System.Diagnostics.Process();
myProcess.StartInfo.FileName = "cmd.exe";
myProcess.StartInfo.UseShellExecute = false;
myProcess.StartInfo.RedirectStandardInput = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.StartInfo.CreateNoWindow = true;
myProcess.Start();
Thread.Sleep(3000);
myProcess.StandardInput.WriteLine("shutdown -s -t 0");
//MessageBox.Show("Shut down self.");
}
private void ShutDownOthers(string serverFilePath,string scriptPath)
{
//Read servers from the server file and shut down the servers.
//Read the servers.
string filePath = serverFilePath;
using (FileStream fs1 = new FileStream(filePath, FileMode.Open))
{
try
{
using (StreamReader sr1 = new StreamReader(fs1))
{
string line;
try
{
while ((line = sr1.ReadLine()) != null)
{
var elements = line.Split();
string ip = elements[0].ToString();
string user = elements[1].ToString();
string pwd = elements[2].ToString();
//Shut down the server checked from the line.
//Open the PowerShell.
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
//MessageBox.Show("Run PowerShell.");
string script = File.ReadAllText(scriptPath);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script);
ps.Invoke();
ps.AddCommand("ShutDownRemoteComputers").AddParameter("ip", ip).AddParameter("user", user).AddParameter("pwd", pwd);
ps.Invoke();
//MessageBox.Show("Shut down others");
}
}
}
finally
{
sr1.Close();
}
}
}
finally
{
fs1.Close();
}
}
}
private void chooseServerFileButton_Click(object sender, EventArgs e)
{
OpenFileDialog fileName = new OpenFileDialog();
fileName.Filter = "文本文件|*.*|C#文件|*.cs|所有文件|*.*";
if (fileName.ShowDialog() == DialogResult.OK)
{
serverFilePath.Text = fileName.FileName;
}
}
private void serverFilePath_Click(object sender, EventArgs e)
{
serverFilePath.Text = "";
}
private void scriptPathText_Click(object sender, EventArgs e)
{
scriptPathText.Text = "";
}
private void chooseScriptButton_Click(object sender, EventArgs e)
{
OpenFileDialog fileName = new OpenFileDialog();
fileName.Filter = "文本文件|*.*|C#文件|*.cs|所有文件|*.*";
if (fileName.ShowDialog() == DialogResult.OK)
{
scriptPathText.Text = fileName.FileName;
}
}
}
}
至于远程所需要在主控端和被控端所做的准备工作,一语概括就是在主控端和被控端都Enable-PSRemoting(全选A),然后互相配置Winrm信任就ok了(这两步都是在PowerShell中进行的,详见通过PowerShell来远程管理计算机这篇blog)。
//Open the PowerShell.
using (Runspace runspace = RunspaceFactory.CreateRunspace())
{
//MessageBox.Show("Run PowerShell.");
string script = File.ReadAllText(scriptPath);
runspace.Open();
PowerShell ps = PowerShell.Create();
ps.Runspace = runspace;
ps.AddScript(script);
ps.Invoke();
ps.AddCommand("ShutDownRemoteComputers")
.AddParameter("ip", ip)
.AddParameter("user", user)
.AddParameter("pwd", pwd);
ps.Invoke();
}
上面这段代码就是在C#中调用PowerShell脚本的关键。想要在C#中引用PowerShell需要事先add reference:

找到这个reference最快捷的方式就是在PowerShell中输入[psobject].Assembly.Location:

然后在代码里using相应的命名空间就可以了:

亲测通过后获得了相关部门领导赠送的可爱多一个。


浙公网安备 33010602011771号