C# 在调用Powershell cmdlet之间保持状态的最佳做法是什么?
我是Powershell开发的新手,我正在尝试用C编写一个Powershell Cmdlet,该Cmdlet将用作REST API的接口 我希望有某种setup Cmdlet,其中会提示用户向restapi输入Uri、用户名和密码,然后像Get Item一样调用Cmldlets,而无需输入这些参数。与用于Powershell的Azure provider非常相似,您可以通过调用Select AzureSubscription设置当前订阅,然后调用Save AzureVhd,而无需再次输入订阅名称 在对不同cmdlet的调用之间保持状态的最佳实践是什么 编辑: 我不确定这是否是解决这个问题的最佳方法,但我所做的是添加了一个保存状态的singleton类。C# 在调用Powershell cmdlet之间保持状态的最佳做法是什么?,c#,powershell,cmdlets,C#,Powershell,Cmdlets,我是Powershell开发的新手,我正在尝试用C编写一个Powershell Cmdlet,该Cmdlet将用作REST API的接口 我希望有某种setup Cmdlet,其中会提示用户向restapi输入Uri、用户名和密码,然后像Get Item一样调用Cmldlets,而无需输入这些参数。与用于Powershell的Azure provider非常相似,您可以通过调用Select AzureSubscription设置当前订阅,然后调用Save AzureVhd,而无需再次输入订阅名称
我有一个Cmdlet,选择Project-Name MyProject在我的singleton类中设置公共属性,然后我的其他Cmdlet可以访问该属性。如果它们运行的是V3或更高版本,您可以让安装程序在$PSDefaultParameterValues中设置这些值 见:
有关设置值的详细信息。可能类似于powershell的CimSession支持?使用new cimsession创建包含状态的会话,然后将cimsession对象传递给其他各种cmdlet。但这不适用于OP中提到的get项 然而,OP中的编辑描述了一个实现,如果我理解正确,它不太可能与get项一起工作 如果get-item支持真的是一个需求,那么我相信get-PSProvider中的PS提供商将是一个不错的选择。PS提供程序将使用诸如get-item之类的cmdlet,并可以通过PSDrives保存状态,就像在get-PSDrive中一样。您正在寻找PSCmdlet.SessionState 我通过创建一个小桥类MyCmdlet解决了同样的问题,MyCmdlet是我自己所有Cmdlet的派生源,它包含管理会话状态的帮助程序,以及保存要持久化的内容的对象的定义。在本例中,我将只编写一些简单的内容,例如用户名和数据库名称
// In MyCmdlet.cs
public class MyStateInfo {
public string Username { get; set;}
public string DbName { get; set;}
}
protected abstract class MyCmdlet : PSCmdlet {
private const string StateName = "_Blah";
protected MyStateInfo getState()
{
if ( ! SessionState.PSVariable.GetValue(StateName, null) is MyStateInfo s))
SessionState.PSVariable.Set(StateName, s = new MyStateInfo());
return s;
}
}
此时,所有cmdlet都应该从MyCmdlet继承,getState将始终返回一个现有的或新的变量:对类的更改将保留在同一会话中
可能有很多方法可以将其集成到整个cmdlet参数设计中,这对我来说还是一种新方法,因此我不确定这是否是最佳做法,但我通过创建一个helper cmdlet来设置初始值,从而解决了这一问题:
[Cmdlet(VerbsCommon.Set, "MyUsername")]
public class Set_MyUsername : MyCmdlet {
[Parameter(Mandatory = true, Position = 1)]
public string Username {get; set; }
protected override void ProcessRecord()
{
base.ProcessRecord();
WriteVerbose($"Saving {Username} in session state");
getState().Username = Username;
}
}
然后,稍后的某个cmdlet需要执行以下操作:
[Cmdlet(VerbsCommunication.Connect, "Database")]
public class Connect_Database : MyCmdlet {
[Parameter(Mandatory = false)]
public string Username { get; set; }
// other parameters here
protected override void BeginProcessing()
{
base.BeginProcessing();
if (Username == null)
Username = getState().Username;
if (Username == null)
{ // ERROR HERE: missing username }
}
// more stuff
}
然后,您的Connect数据库将获取一个显式的Username-steve参数,该参数不咨询或接触会话状态,但如果没有该参数,它将从会话状态对象中提取该参数。如果在此之后仍然缺少用户名,则可能会通过TerminationError失败
您选择的项目可以以相同的方式工作
我通常提供一个Get-MyState cmdlet,它只将状态对象写入管道输出,主要用于调试。如果您的应用程序保证将这些内容分开,那么您不必仅限于一个变量。也许这是一个解决方案,但当您需要从C代码更新它时,它看起来相当复杂。
[Cmdlet(VerbsCommunication.Connect, "Database")]
public class Connect_Database : MyCmdlet {
[Parameter(Mandatory = false)]
public string Username { get; set; }
// other parameters here
protected override void BeginProcessing()
{
base.BeginProcessing();
if (Username == null)
Username = getState().Username;
if (Username == null)
{ // ERROR HERE: missing username }
}
// more stuff
}