Создание автоматических переменных PowerShell из C # - PullRequest
3 голосов
/ 03 января 2011

Я пытаюсь сделать автоматические переменные доступными для Excel VBA (например, ActiveSheet или ActiveCell), также доступными для PowerShell как «автоматические переменные». Механизм PowerShell размещается в надстройке Excel VSTO, и приложение Excel.Application доступно для него как Globals.ThisAddin.Application. Я нашел этот поток здесь в StackOverflow и начал создавать производные классы 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 здесь и увидел это:

"Не существует установленного сценария для наследования от этого класса. Чтобы программно создать переменную оболочки, создайте экземпляр этого класса и установите его с помощью класса 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?

Ответы [ 2 ]

5 голосов
/ 03 января 2011

Наша документация неверна - это поддерживаемый сценарий.

Вот еще немного о технике:

  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

0 голосов
/ 03 января 2011

Очевидно, что во втором примере, где вы не производите от PSVariable, вы не можете ожидать, что переменная $ ActiveCell изменится со значением свойства ActiveCell, поскольку вы захватываете его значение только один раз.

Я не верю, что наследование от PSVariable является поддерживаемым сценарием, но он работает, и я сделал это, чтобы добавить такие переменные, как $Now и $Today.

Может быть, лучше представить переменную $ Application в сценарии PowerShell вместо различных свойств объекта Application. Плюсом этого является то, что вам не нужно создавать кучу автоматических переменных, и сценарии PowerShell могут получить доступ ко всему, что может предложить объект Application, используя $ Application.ActiveCell. Другим преимуществом является то, что она вообще не должна быть автоматической переменной, потому что ссылка на объект приложения никогда не изменится.

Сказав все это, я включил подкласс PSVariable, который я использую время от времени, который принимает 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

    }

}
...