c# - 使用 PSCommands 获取进程 ID psexec
问题描述
启动 psexec 后获取进程 ID的后续内容
我想知道如何使用PSCommand 和 PowerShell 获得问题的答案。
我已经尽我所能,希望得到一些帮助。这是我最初想翻译的答案,也是我失败的尝试。
private int GetRemoteProcessId()
{
string remoteFilename = "ExampleBatfile.bat";
string remoteDirectory = "C:\\ExampleDirectory";
string remoteUsername = "ExampleUsername";
string remotePassword = "ExamplePassword";
string remoteIp = "ExampleIP";
PowerShell ps = PowerShell.Create()
.AddScript($"psexec.exe \\{remoteIp} -accepteula -u {remoteUsername} -p {remotePassword} -s -i -d - w {remoteDirectory} {remoteFilename}" )
.AddCommand( "Select-String" ).AddParameter( "process ID (\\d+)" )
.AddCommand( "ForEach-Object" ).AddParameter( "{$_.Matches.Groups[1].Value}" );
Collection<PSObject> results = ps.Invoke();
int remoteProcessId = ( int )results.First().BaseObject;
return remoteProcessId;
}
我想要的只是在启动远程进程后使用 psexec 从远程进程获取进程 ID(与已回答的问题相同) - 但通过 C# PSCommands。
解决方案
最后,我实现了 psexec 进程将进程 id 输出到控制台。我最终将 psexec 进程的输出转储到临时文件并解析提到的进程 ID。
我确信有比这更好/更安全的方法,但它有效!
/// <summary>
/// Creates a path to a unqiue-guid-named .txt file under the <see cref="Path.GetTempPath"/> directory. This does not create the file.
/// </summary>
/// <returns>Path.</returns>
public static string CreateTempGuidTxtFilename()
{
return string.Format(
"{0}.txt",
Path.Combine(
Path.GetTempPath(),
Guid.NewGuid().ToString().Replace( '-', '_' ) ) );
}
/// <summary>
/// Attempt to gather the process id for from a remote process start.
/// </summary>
/// <param name="info">Process info.</param>
/// <param name="ip">Remote machine ip.</param>
/// <returns>Process ID if it was successfully found.</returns>
private int? GetRemoteProcessStartId( ProcessStartInfo info, string ip )
{
// Declare no process id.
int? processId = null;
// We are going to start the process and feed the output into a generated .txt file with the given args.
string processInfoTempGuidPath = CreateTempGuidTxtFilename();
info.Arguments = string.Format( "{0} > {1} 2>&1 &", info.Arguments, processInfoTempGuidPath );
// Right, here we go!
Process psexecProcess = null;
try
{
// Start the process and wait for it to exit!
psexecProcess = Process.Start( info );
psexecProcess?.WaitForExit();
// Now we have exited, we can safely read the generated txt file and search the output.
// We are attempting to parse the output to find the process ID which was remotely launched
// since psexec displays this as standard output.
processId = TryParsePsexecLinesForProcessId( ip, File.ReadAllLines( processInfoTempGuidPath ) );
}
catch
{
// Any exception and we will try to kill our process.
processId = null;
psexecProcess?.Kill();
}
finally
{
// We finally want to delete the generated .txt file.
// It may have been created even on a failed process, so be safe!
if ( File.Exists( processInfoTempGuidPath ) )
{
File.Delete( processInfoTempGuidPath );
}
psexecProcess?.Close();
}
// Return the process id which may or may not be found.
return processId;
}
/// <summary>
/// Attempt to retrieve the process id from an output of text.
/// </summary>
/// <param name="ip">Machine address.</param>
/// <param name="output">Output.</param>
/// <returns>Process ID if it was parsed successfully.</returns>
public static int? TryParsePsexecLinesForProcessId(string ip, params string[] output)
{
// Get the queryable string for the line of psexec stream output which contains the remotely started process id.
string queryId = string.Format( "started on {0} with process ID", ip );
// Once we have found the line containing the process id query string,
// we will reverse and clean it to read the beginning characters which should be the
// string representation of the remote process id but backwards.
string reversedQuery = string.Concat(
output.FirstOrDefault(
x => x.Contains(
queryId,
StringComparison.OrdinalIgnoreCase ) )
.TrimEnd( '.' ).Reverse() );
// Take while are parsing the integer, remeber to reverse again since we are backwards!
// On successfully reading characters, we are going to try and parse for and integer!
string idToParse = string.Concat( reversedQuery.TakeWhile( x => !char.IsWhiteSpace( x ) ).Reverse() );
if ( !string.IsNullOrEmpty( idToParse ) && int.TryParse( idToParse, out int remoteProcessId ) )
{
return remoteProcessId;
}
else
{
// Else we can't parse any informative message regarding process id.
return null;
}
}
推荐阅读
- mysql - 使用不同的脚本创建 If 分支
- sql-server - 多个数据源的 Spring Boot 问题
- jquery - 在将图像获取为 encode64 时删除 encode64 标头数据。?
- r - 如何找到不同年龄组的信用卡持有人百分比
- firebase - 如何在应用程序的二进制文件中捆绑默认的 ML 人脸模型?
- android - 使用 webview 在 Chrome 73 android 中取消对所有字体的请求
- dart - 如何使用for循环将具有相同名称的元素添加到列表中
- r - 我想要在包含使用 R 的文本的列中的第一个句号之后的单词
- mysql - 如何添加具有不同时区的额外列
- design-patterns - 哪种设计模式解决了多规则检查?