【问题标题】:Creating PowerShell Automatic Variables from C#从 C# 创建 PowerShell 自动变量
【发布时间】:2011-06-02 14:49:42
【问题描述】:

我试图使 Excel VBA(如 ActiveSheet 或 ActiveCell)可以使用的自动变量也可以作为“自动变量”用于 PowerShell。 PowerShell 引擎托管在 Excel VSTO 加载项中,并且 Excel.Application 作为 Globals.ThisAddin.Application 提供给它。我在 StackOverflow 上找到了 this 线程并开始创建 PSVariable 派生类,例如:

public class ActiveCell : PSVariable
{
    public ActiveCell(string name) : base(name) { }

    public override object Value
    {
        get 
        { 
            return Globals.ThisAddIn.Application.ActiveCell; 
        }
    }
}

public class ActiveSheet : PSVariable
{
    public ActiveSheet(string name) : base(name) { }

    public override object Value
    {
        get 
        { 
            return Globals.ThisAddIn.Application.ActiveSheet; 
        }
    }
}

并将它们的实例添加到当前的 POwerShell 会话中:

runspace.SessionStateProxy.PSVariable.Set(new ActiveCell("ActiveCell"));
runspace.SessionStateProxy.PSVariable.Set(new ActiveSheet("ActiveSheet"));

这可行,我可以将 PowerShell 中的这些变量用作 $ActiveCell 和 $ActiveSheet(它们的值随着 Excel 活动工作表或单元格的变化而变化)。然后我阅读了 PSVariable 文档here 并看到了这个:

“没有从此类派生的既定方案。要以编程方式创建 shell 变量,请创建此类的实例并使用 PSVariableIntrinsics 类进行设置。”

当我从 PSVariable 派生时,我尝试使用建议的内容:

PSVariable activeCell = new PSVariable("ActiveCell");
activeCell.Value = Globals.ThisAddIn.Application.ActiveCell;
runspace.SessionStateProxy.PSVariable.Set(activeCell);

使用它,$ActiveCell 会出现在我的 PowerShell 会话中,但它的值不会随着我在 Excel 中更改活动单元格而改变。

PSVariable 文档中的上述评论是我应该担心的,还是我可以继续创建 PSVariable 派生类?是否有另一种方法可以使 Excel 全局变量对 PowerShell 可用?

【问题讨论】:

    标签: c# powershell excel-addins


    【解决方案1】:

    我们的文档有误 - 这是受支持的场景。

    以下是有关该技术的更多信息:

    1. http://poshcode.org/2198
    2. http://www.leeholmes.com/blog/2009/03/26/more-tied-variables-in-powershell/
    3. http://www.pavleck.net/powershell-cookbook/ch03.html

    李·福尔摩斯 [MSFT] Windows PowerShell 开发

    【讨论】:

      【解决方案2】:

      显然,在您的第二个示例中,您不是从 PSVariable 派生的,您不能期望 $ActiveCell 变量会随着 ActiveCell 属性的值而改变,因为您只捕获了一次它的值。

      我不认为从 PSVariable 派生是受支持的方案,但它确实有效,而且我已经完成它来添加变量,例如 $Now$Today

      最好只向 PowerShell 脚本公开一个 $Application 变量而不是应用程序对象的各种属性。这样做的好处是您不需要创建一堆自动变量,并且 PowerShell 脚本可以通过使用 $Application.ActiveCell 访问 Application 对象必须提供的任何内容。另一个好处是它根本不需要是一个自动变量,因为 Application 对象引用永远不会改变。

      说了这么多,我已经包含了一个 PSVariable 的子类,我不时使用它,它需要一个 ScriptBlock 作为 getter 和 setter。这让我可以从 PowerShell 定义自动变量,而无需为每个变量单独派生类。

      using System;
      using System.Management.Automation;
      
      namespace Einstein.PowerShell
      {
      
          public sealed class DynamicVariable : PSVariable
          {
      
              #region Constructors
      
              /// <summary>
              /// </summary>
              public DynamicVariable(string name, ScriptBlock onGet)
                  : this(name, onGet, null)
              {
              }
      
              /// <summary>
              /// </summary>
              public DynamicVariable(string name, ScriptBlock onGet, ScriptBlock onSet)
                  : base(name, null, ScopedItemOptions.AllScope)
              {
                  OnGet = onGet;
                  OnSet = onSet;
              }
      
              #endregion
      
              #region Properties
      
              /// <summary>
              /// The ScriptBlock that runs to get the value of the variable.
              /// </summary>
              private ScriptBlock OnGet
              {
                  get;
                  set;
              }
      
              /// <summary>
              /// The ScriptBlock that runs to get the value of the variable.
              /// </summary>
              private ScriptBlock OnSet
              {
                  get;
                  set;
              }
      
              /// <summary>
              /// Gets or sets the underlying value of the variable.
              /// </summary>
              public override object Value
              {
                  get
                  {
                      if (OnGet == null) {
                          return null;
                      }
                      return OnGet.Invoke();
                  }
                  set
                  {
                      if (OnSet == null) {
                          throw new InvalidOperationException("The variable is read-only.");
                      }
                      OnSet.Invoke(value);
                  }
              }
      
              #endregion
      
          }
      
      }
      

      【讨论】:

      • 我已经将 Excel.Application 公开为 $Application,我使用 Runspace.SessionStateProxy.SetVariable("Application", app) 并且它工作正常(app 是 Microsoft.Office.Interop.Exce.Application 实例)。我知道我可以使用 Application.ActiveCell 或 Application.ActiveSheet,但我试图创建一个类似于 Excel VBA 的环境,其中 ActiveCell 和 ActiveSheet 可用作全局变量。谢谢。
      猜你喜欢
      • 2016-01-26
      • 2021-09-13
      • 2016-02-12
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-30
      相关资源
      最近更新 更多