在日常使用中,经常忘记Powershell指令,总是需要去查询。在万物皆可AI得时代,我们可以利用大模型来搭建自己的小助手。
先看执行效果:
下面进入正式环节。
首先,使用国内大模型需要使用one-api或者chatnio等进行转发,这里就不多介绍了
本篇使用的agent技术是微软的SemanticKernel,可以参考相关文章: AI框架SemanticKernel
创建Plugin
先创建实现效果的Plugin,这里主要实现一个获取指令的作用
public class WinCmdPlugin
{
public async Task<string> GetCmd(Kernel kernel, string goal)
{
string prompt = """
用户正在使用Windows操作系统,他需要用powershell执行一些指令。请根据他输入的目的输出指令。
###
输出是一个字符串格式,只需要包含所需要执行的命令,不需要输出其他任何内容
###
例:
输入:打开cmd
输出:cmd
###
注意
必须严格输出windows操作系统上powershell能执行的指令。如果无可用指令,直接返回空字符串,不需要返回其他任何内容!!!
返回的指令结果严禁带上任何标点符号等。只需要指令本身
###
用户输入: {{$input}}
###
输出:
""";
var function = kernel.CreateFunctionFromPrompt(prompt);
var args = new KernelArguments
{
["input"] = goal,
};
var res = await function.InvokeAsync(kernel, args);
return res.ToString().TrimEnd('。');
}
}
创建代理
由于使用了转发,建立一个HttpClientHandler来实现请求转发到国内模型处理
public class OpenAIHttpclientHandler : HttpClientHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request.RequestUri.LocalPath == "/v1/chat/completions")
{
UriBuilder uriBuilder = new(request.RequestUri)
{
Scheme = "http",
Host = "Your OneApi Host",//你的Oneapi地址
Port = 3000 //你的Oneapi端口
};
request.RequestUri = uriBuilder.Uri;
}
return await base.SendAsync(request, cancellationToken);
}
}
主程序部分
由于是一个控制台程序,所以直接在program上进行完整功能。这里需要把model和key改成自己的model和key
这里因为就一个功能,没有必要注入到kernel中。当然,你也可以选择直接把相应plugin的function注册到kernel中执行,实际效果都是差不多的。
// See https://aka.ms/new-console-template for more information
using Caedmon.Semantic.Semantic.Handlers;
using Microsoft.SemanticKernel;
using System.Diagnostics;
using WinHelper;
Console.WriteLine("您好,我是Powershell执行小帮手。我能将你的需求转化成powershell指令,并提示你是否执行。在指令生成后,你可以选择直接执行指令");
var cls = new WinCmdPlugin();
var builder = Kernel.CreateBuilder();
builder.AddOpenAIChatCompletion(modelId: "your api model", apiKey: "your api key", httpClient: new HttpClient(new OpenAIHttpclientHandler()));
var cmd = string.Empty;
if (args.Length > 0)
{
cmd = args[0].ToString();
}
while (true)
{
if (string.IsNullOrWhiteSpace(cmd))
{
Console.Write("请输入你需要的指令> ");
cmd = Console.ReadLine();
continue;
}
if (string.Equals(cmd, "clear", StringComparison.OrdinalIgnoreCase))
{
Console.Clear();
Console.WriteLine("您好,我是Powershell执行小帮手。我能将你的需求转化成powershell指令,并提示你是否执行。在指令生成后,你可以选择直接执行指令");
cmd = string.Empty;
continue;
}
var kernel = builder.Build();
var data = await cls.GetCmd(kernel, cmd);
if (string.IsNullOrWhiteSpace(data))
{
Console.WriteLine("很遗憾,未能发现适合的指令。请尝试重新描述需求,提供更完整的命令");
cmd = string.Empty;
continue;
}
Console.WriteLine($"获取到指令:{data}");
Console.Write("是否执行?(Y/N)");
var key = Console.ReadKey();
Console.WriteLine();
if (key.KeyChar == 'Y' || key.KeyChar == 'y')
{
var process = new Process()
{
StartInfo = new ProcessStartInfo
{
FileName = "powershell.exe",
Arguments = $"/c {data}",
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true
}
};
process.Start();
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit(5000);
Console.WriteLine(output);
}
cmd = string.Empty;
Console.WriteLine();
}
程序安装
使用Costura.Fody减少依赖项,由于我们要实现powershell嵌入效果,这里我们把编译的exe和powershell脚本放一起
其中powershell脚本如下:
主要是将文件拷贝到指定目录,将该exe注册到powershell的helper命令。
# 获取当前脚本的目录
$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
# 定义目标目录
$targetDir = "C:\Windows\System32\winhelper"
# 检查目标目录是否存在,如果不存在则创建它
if (!(Test-Path -Path $targetDir)) {
New-Item -ItemType Directory -Path $targetDir | Out-Null
}
# 拷贝当前脚本目录下的所有文件到目标目录
Get-ChildItem -Path $scriptDir -File | Copy-Item -Destination $targetDir -Force -ErrorAction SilentlyContinue
Write-Host "拷贝文件成功"
# 获取PowerShell配置文件的路径
$profilePath = $PROFILE
# 如果配置文件不存在,则创建一个新的配置文件
if (-not (Test-Path -Path $profilePath)) {
# 这里我们假设配置文件是一个PS1文件,这是最常见的类型
# 如果你的环境有所不同,你可能需要更改文件扩展名
New-Item -ItemType File -Path $profilePath -Force | Out-Null
}
# 写入别名指令到配置文件
$aliasInstruction = "`nNew-Alias helper 'C:\Windows\System32\winhelper\WinHelper.exe' -Option AllScope"
$aliasInstruction | Add-Content -Path $profilePath
# 完成后通知用户
Write-Host "Alias 'helper' has been added to your PowerShell profile at $profilePath"
最后,使用powershell管理员模式执行脚本。执行完后,重启powershell,使用helper命令即可打开