我尝试将自动变量提供给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全局变量?
答案 0 :(得分:5)
我们的文档错误 - 这是受支持的方案。
以下是关于该技术的更多信息:
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
}
}