从C#创建PowerShell自动变量

时间:2011-01-02 21:59:25

标签: c# powershell excel-addins

我尝试将自动变量提供给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派生类吗?有没有其他方法可以让PowerShell使用Excel全局变量?

2 个答案:

答案 0 :(得分:5)

我们的文档错误 - 这是受支持的方案。

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

  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
  4. Lee Holmes [MSFT] Windows PowerShell开发

答案 1 :(得分:0)

显然在你的第二个例子中,你没有从PSVariable派生,你不能指望$ ActiveCell变量随着ActiveCell属性的值而改变,因为你只捕获它的值一次。

我不相信从PSVariable派生的是支持的场景,但它确实有用,我已经完成了添加$Now$Today等变量。

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

说了这么多,我已经包含了一个我不时使用的PSVariable的子类,它为getter和setter提供了一个ScriptBlock。这允许我从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

    }

}