Поделиться через


Создание действий Power Automate для компьютеров с помощью SDK действий

В этой статье описывается, как создавать пользовательские действия в Power Automate для компьютеров.

Создание пользовательских действий

Внимание

В качестве имен и/или свойств действий нельзя использовать зарезервированные ключевые слова. Использование зарезервированных ключевых слов в качестве имен действий и/или свойств действий приводит к ошибочному поведению. Дополнительные сведения: Зарезервированные ключевые слова в классических потоках

Начните с создания нового проекта библиотеки классов (.NET Framework). Выберите платформу .NET Framework версии 4.7.2.

Для формирования действия в созданном пользовательском модуле выполните следующие действия:

  • Удалите автоматически сгенерированный файл Class1.cs.
  • Создайте новый класс внутри своего проекта, чтобы представить пользовательское действие, и присвойте ему уникальное имя.
  • Включите пространства имен Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK и Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes.
  • Все классы, представляющие действия, должны иметь атрибут [Действие] выше вашего класса.
  • У класса должен быть общий доступ и он должен наследоваться от класса ActionBase.
using System;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes;

namespace Modules.MyCustomModule
{
    [Action(Id = "CustomAction")]
    public class CustomAction : ActionBase
    {
        public override void Execute(ActionContext context)
        {
            throw new NotImplementedException();
        }
    }
}

У большинства действий есть параметры (входные или выходные). Входные и выходные параметры представлены классическими свойствами C#. Каждое свойство должно иметь соответствующий атрибут C# ([InputArgument] или [OutputArgument]), определяющий его тип и представление в Power Automate для компьютеров. Входные аргументы также могут иметь значения по умолчанию.

using System.ComponentModel;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes;

namespace Modules.MyCustomModule
{
    [Action(Id = "CustomAction")]
    public class CustomAction : ActionBase
    {
        [InputArgument, DefaultValue("Developer")]
        public string InputName { get; set; }

        [OutputArgument]
        public string DisplayedMessage { get; set; }

        public override void Execute(ActionContext context)
        {
            DisplayedMessage = $"Hello, {InputName}";
        }
    }
}

Добавление описаний к пользовательским действиям

Добавьте описание и понятное имя для модулей и действий, чтобы разработчики RPA знали, как их лучше всего использовать.

Конструктор Power Automate для компьютеров показывает понятные имена и описания.

Вы можете создать файл "Resources.resx" внутри папки Properties проекта модуля. Новый файл ".resx" должен называться "Resources.resx".

Формат описаний модулей и действий должен быть следующим:

«Module_Description» или «Action_Description» и «Module_FriendlyName» или «Action_FriendlyName» соответственно в поле имени. Описание поля значения.

Мы также рекомендуем указывать для параметров описания и понятные имена. Их формат должен быть следующим: «Action_Parameter_Description», «Action_Parameter_FriendlyName».

Снимок экрана с ресурсами для простого действия

Совет

В поле для комментариев рекомендуется указать, что именно вы описываете (например, модуль, действие и т. д.).

Их также можно задать с помощью свойств FriendlyName и Description [InputArgument], [OutputArgument] и атрибутов [Action].

Вот пример файла Resources.resx для пользовательского модуля.

Снимок экрана с ресурсами

Еще один способ быстро добавить понятные имена и описания к действиям и параметрам — использовать свойства FriendlyName и Description в атрибутах [Действие], [InputArguement] и [OutputArguement].

Заметка

Чтобы добавить к модулю понятное имя и описание, необходимо изменить соответствующий файл .resx или добавить соответствующие атрибуты C#.

Добавление обработки ошибок в пользовательские действия

Чтобы определить пользовательские исключения в действии, используйте атрибут [Throws("ActionError")] над классом пользовательского действия. Каждый случай исключения, который вы хотите определить, должен иметь свой собственный атрибут.

В блоке catch используйте следующий код:

throw new ActionException("ActionError", e.Message, e.InnerException);

Убедитесь, что имя ActionException совпадает с именем, указанным в атрибуте Throws. Используйте throw new ActionException для каждого случая исключения и сопоставьте его с соответствующим именем атрибута Throws. Все исключения, определенные с помощью атрибута Throws, отображаются на вкладке обработки ошибок действий конструктора.

Пример этого можно найти в разделе Условные действия.

Локализация ресурсов

Язык по умолчанию для модулей в Power Automate для компьютеров должен быть английский.

Файл Resources.resx должен быть на английском языке.

Любые другие языки могут быть добавлены с помощью дополнительных файлов Resources.{locale} .resx для локализации. Например: Resources.fr.resx.

Категории пользовательских модулей

Модули могут включать категории и подкатегории для лучшей организации действий.

Чтобы разделить пользовательские действия на категории и подкатегории, измените атрибут [Действие], который предшествует классу, представляющему пользовательское действие, следующим образом:

[Action(Category = "category.subcategory")]

Заметка

Модуль может иметь несколько категорий. Точно так же категории могут состоять из подкатегорий. Эта структура может быть неопределенной.

Свойство Order определяет порядок предварительного просмотра действий в конструкторе.

Action1 принадлежит категории «TestCategory» и это первое действие модуля (так вы объясняете порядок и категорию на примере).

[Action(Id = "Action1", Order = 1, Category = "TestCategory")]

Условные действия

Условные действия — это действия, возвращающие либо «True», либо «False». Действие "Если файл существует" в Power Automate для компьютеров стандартной библиотеки — хороший пример условного действия.

Пример условного действия:

using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes;
using System;
using System.ComponentModel;

namespace Modules.CustomModule
{
    [ConditionAction(Id = "ConditionalAction1", ResultPropertyName = nameof(Result))]
    [Throws("ActionError")] // TODO: change error name (or delete if not needed)
    public class ConditionalAction1 : ActionBase
    {
        #region Properties

        public bool Result { get; private set; }

        [InputArgument]
        public string InputArgument1 { get; set; }

        #endregion

        #region Methods Overrides

        public override void Execute(ActionContext context)
        {
            try
            {
                //TODO: add action execution code here
            }
            catch (Exception e)
            {
                if (e is ActionException) throw;

                throw new ActionException("ActionError", e.Message, e.InnerException);
            }
        }

        #endregion
    }
}

Обратите внимание на логическую переменную Result.

Действие Если файл существует не имеет выходного аргумента. Он возвращает либо true, либо false, в зависимости от того, что содержит логическая переменная Result.

Селекторы пользовательских действий

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

Пример: действие «Запустить Excel» из стандартной библиотеки действий.

При использовании селектора «с пустым документом» поток запускает пустой документ Excel, тогда как при использовании варианта «и открыть следующий документ» требуется путь к файлу.

Снимок экрана селекторов действия

Два действия, упомянутые выше, являются двумя селекторами базового действия «Запустить Excel».

При создании пользовательских действий вам не нужно переписывать функции.

Вы можете создать одно «базовое» действие, задав его входные и выходные параметры, а затем выбрать, что будет отображаться в каждом варианте, используя селекторы действий.

С помощью селекторов действий можно добавить уровень абстракции к одному действию. Это позволяет извлекать определенные функции из одного «базового» действия без необходимости переписывать код для очередного формирования новой вариации одного и того же действия.

Рассматривайте селекторы как варианты выбора, фильтрующие одно действие и предоставляющие только ту информацию, которая требуется для соответствующих селекторов.

Снимок экрана с диаграммой селекторов действий

Чтобы сформировать новый селектор действий, сначала создайте базовое действие, которое будет использоваться селекторами.

Для центрального действия требуется либо логическое значение, либо свойство перечисления в качестве входного аргумента C#.

Значение этого свойства определяет, какой селектор используется.

Наиболее распространенным способом является использование перечисления. Особенно, когда требуется более двух селекторов, перечисления являются единственным возможным вариантом.

Для двух селекторов можно использовать логические значения.

Это свойство, также известное как аргумент ограничения, должно иметь значение по умолчанию.

Центральное действие заявлено как классическое действие.

Обратите внимание, что первое свойство (входной аргумент) — это перечисление. В зависимости от значения этого свойства соответствующий селектор становится активным.

Заметка

Чтобы расположить аргументы в желаемом порядке, вы задаете значение Order рядом с атрибутом InputArgument.

using System.ComponentModel;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Desktop.Actions.SDK;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Desktop.Actions.SDK.Attributes;

namespace Modules.CustomModule
{
    [Action(Id = "CentralCustomAction")]
    public  class CentralCustomAction : ActionBase
    {
        #region Properties

        [InputArgument, DefaultValue(SelectorChoice.Selector1)]
        public SelectorChoice Selector { get; set; }

        [InputArgument(Order = 1)]
        public string FirstName { get; set; }

        [InputArgument(Order = 2)]
        public string LastName { get; set; }

        [InputArgument(Order = 3)]
        public int Age { get; set; }

        [OutputArgument]
        public string DisplayedMessage { get; set; }

        #endregion

        #region Methods Overrides

        public override void Execute(ActionContext context)
        {
            if (Selector == SelectorChoice.Selector1)
            {
                DisplayedMessage = $"Hello, {FirstName}!";
            }
            else if (Selector == SelectorChoice.Selector2)
            {
                DisplayedMessage = $"Hello, {FirstName} {LastName}!";
            }
            else // The 3rd Selector was chosen 
            {
                DisplayedMessage = $"Hello, {FirstName} {LastName}!\nYour age is: {Age}";
            }
        }

        #endregion
    } // you can see below how to implement an action selector
}

Селекторы пользовательских действий, использующие перечисления

В этом примере вы создаете три селектора. Простое перечисление каждый раз определяет соответствующий селектор:

public enum SelectorChoice
{
    Selector1,
    Selector2,
    Selector3
}

Селекторы представлены классами.

Эти классы должны наследовать класс ActionSelector<TBaseActionClass>.

Заметка

TBaseActionClass — имя класса базовых действий.

В методе UseName() объявляется имя селектора действий. Оно используется в качестве имени действия для разрешения ресурсов.

public class Selector1 : ActionSelector<CentralCustomAction>
{
    public Selector1()
    {
        UseName("DisplayOnlyFirstName");
        Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector1);
        ShowAll();
        Hide(p => p.LastName);
        Hide(p => p.Age);
        // or 
        // Show(p => p.FirstName); 
        // Show(p => p.DisplayedMessage);
    }
}

Заметка

Классы Selector не следует объявлять как действия. Единственное действие является центральным. Селекторы действуют как фильтры.

В этом конкретном примере мы хотим отобразить только один из аргументов, поэтому остальные отфильтровываются. Аналогично для Selector2:

public class Selector2 : ActionSelector<CentralCustomAction>
{
    public Selector2()
    {
        UseName("DisplayFullName");
        Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector2);
        ShowAll();
        Hide(p => p.Age);
    }
}

И классы Selector3:

public class Selector3 : ActionSelector<CentralCustomAction>
{
    public Selector3()
    {
        UseName("DisplayFullDetails");
        Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector3);
        ShowAll();
    }
}

Окончательное выполнение достигается с помощью метода Execute(ActionContext context), который находится в центральном действии. В зависимости от селектора отображаются соответствующие отфильтрованные значения.

public override void Execute(ActionContext context)
{
    if (Selector == SelectorChoice.Selector1)
    {
        DisplayedMessage = $"Hello, {FirstName}!";
    }
    else if (Selector == SelectorChoice.Selector2)
    {
        DisplayedMessage = $"Hello, {FirstName} {LastName}!";
    }
    else // The 3rd Selector was chosen 
    {
        DisplayedMessage = $"Hello, {FirstName} {LastName}!\nYour age is: {Age}";
    }
}

Селекторы пользовательских действий, использующие логическое значение

Ниже приведен пример использования логического значения вместо перечисления.

using System.ComponentModel;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.ActionSelectors;
using Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes;

namespace Modules.CustomModule
{
    [Action]
    public class CentralCustomActionWithBoolean : ActionBase
    {
        #region Properties

        [InputArgument, DefaultValue(true)]
        public bool TimeExpired { get; set; }

        [InputArgument]
        public string ElapsedTime { get; set; }

        [InputArgument]
        public string RemainingTime { get; set; }

        [OutputArgument]
        public string DisplayedMessage { get; set; }

        #endregion

        #region Methods Overrides

        public override void Execute(ActionContext context)
        {
            DisplayedMessage = TimeExpired ? $"The timer has expired. Elapsed time: {ElapsedTime}" : $"Remaining time: {RemainingTime}";
        }

        #endregion
    }

    public class NoTime : ActionSelector<CentralCustomActionWithBoolean>
    {
        public NoTime()
        {
            UseName("TimeHasExpired");
            Prop(p => p.TimeExpired).ShouldBe(true);
            ShowAll();
            Hide(p => p.RemainingTime);
        }
    }

    public class ThereIsTime : ActionSelector<CentralCustomActionWithBoolean>
    {
        public ThereIsTime()
        {
            UseName("TimeHasNotExpired");
            Prop(p => p.TimeExpired).ShouldBe(false);
            ShowAll();
            Hide(p => p.RemainingTime);
        }
    }
}

Описание параметров для пользовательских селекторов действий

Чтобы создать описание и сводку для селекторов, используйте следующий формат в файле .resx вашего пользовательского модуля.

SelectorName_Description
SelectorName_Summary

Это также можно сделать в селекторе с помощью методов WithDescription и WithSummary.

Внимание

Файлы .dll, описывающие пользовательские действия, файл зависимостей .dll и файл .cab должны быть надлежащим образом подписаны цифровым сертификатом, которому доверяет ваша организация. Сертификат также должен быть установлен на каждом компьютере, на котором создается/изменяется/выполняется классический поток с зависимостями настраиваемых действий, присутствующий в доверенных корневых центрах сертификации.

Идентификаторы пользовательских модулей

Каждый модуль имеет свой ИД (имя сборки). При создании пользовательских модулей убедитесь, что вы задали уникальные идентификаторы модулей. Чтобы задать имя сборки вашего модуля, измените свойство Имя сборки в разделе «Общие сведения» свойств проекта C#.

Предупреждение

Включение модулей с одинаковым идентификатором в поток приведет к конфликтам

Соглашения об присвоении имен для пользовательских модулей

Чтобы пользовательские модули были доступны для чтения через Power Automate для компьютеров, для параметра AssemblyName должно быть присвоено имя файла, соответствующее следующему шаблону:

?*.Modules.?*
Modules.?*

Например, Модули.ContosoActions.dll

AssemblyTitle в параметрах проекта указывает ИД модуля. Он может содержать только буквенно-цифровые символы и символы подчеркивания и должен начинаться с буквы.

Подпишите все библиотеки DLL внутри пользовательского модуля

Важно

Все файлы .dll, составляющие пользовательский модуль (сгенерированная сборка и все ее зависимости), обязательно должны быть подписаны доверенным сертификатом

Чтобы завершить создание пользовательского модуля, все созданные файлы .dll, которые можно найти в папке bin/release или bin/Debug проекта, должны быть подписаны.

Подпишите все файлы .dll, используя доверенный сертификат, выполнив следующую команду (для каждого файла .dll) в командной строке разработчика для Visual Studio:

Подпишите все файлы .dll, используя доверенный сертификат, выполнив следующую команду (для каждого файла .dll) в командной строке разработчика для Visual Studio:

Signtool sign /f {your certificate name}.pfx /p {your password for exporting the certificate} /fd 
SHA256 {path to the .dll you want to sign}.dll

или выполнив следующую команду (путем создания сценария Windows PowerShell .ps1), которая перебирает все файлы .dll и подписывает каждый из них предоставленным сертификатом:

Get-ChildItem {the folder where dll files of custom module exist} -Filter *.dll | 
Foreach-Object {
	Signtool sign /f {your certificate name}.pfx /p {your password for exporting the certificate} /fd SHA256 $_.FullName
}

Заметка

Цифровой сертификат должен иметь экспортируемый закрытый ключ и возможностями подписи кода

Упакуйте все в CAB-файл

DLL-файл, содержащий пользовательские действия и все его зависимости (файлы .dll), должны быть упакованы в CAB-файл (.cab).

Заметка

При присвоении имени файлу .cab следуйте соглашению об именовании файлов и папок для операционной системы Windows. Не используйте пробелы или специальные символы, такие как < > : " / \ | ? * .

Создайте сценарий Windows PowerShell (.ps1), содержащий следующие строки:

param(

    [ValidateScript({Test-Path $_ -PathType Container})]
	[string]
	$sourceDir,
	
	[ValidateScript({Test-Path $_ -PathType Container})]
    [string]
    $cabOutputDir,

    [string]
    $cabFilename
)

$ddf = ".OPTION EXPLICIT
.Set CabinetName1=$cabFilename
.Set DiskDirectory1=$cabOutputDir
.Set CompressionType=LZX
.Set Cabinet=on
.Set Compress=on
.Set CabinetFileCountThreshold=0
.Set FolderFileCountThreshold=0
.Set FolderSizeThreshold=0
.Set MaxCabinetSize=0
.Set MaxDiskFileCount=0
.Set MaxDiskSize=0
"
$ddfpath = ($env:TEMP + "\customModule.ddf")
$sourceDirLength = $sourceDir.Length;
$ddf += (Get-ChildItem $sourceDir -Filter "*.dll" | Where-Object { (!$_.PSIsContainer) -and ($_.Name -ne "Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.dll") } | Select-Object -ExpandProperty FullName | ForEach-Object { '"' + $_ + '" "' + ($_.Substring($sourceDirLength)) + '"' }) -join "`r`n"
$ddf | Out-File -Encoding UTF8 $ddfpath
makecab.exe /F $ddfpath
Remove-Item $ddfpath

Затем этот сценарий Windows PowerShell можно использовать для создания CAB-файла, вызвав его в Windows PowerShell и указав следующее:

  • Каталог файлов .dll для сжатия.
  • Целевой каталог для размещения сгенерированного CAB-файла.

Вызовите сценарий, используя следующий синтаксис:

.\{name of script containing the .cab compression directions}.ps1 "{absolute path  to the source directory containing the .dll files}" "{target dir to save cab}" {cabName}.cab

Пример:

.\makeCabFile.ps1 "C:\Users\Username\source\repos\MyCustomModule\bin\Release\net472" "C:\Users\Username\MyCustomActions" MyCustomActions.cab

Заметка

  • Убедитесь, что фактический DLL-файл настраиваемых действий находится на корневом уровне целевого пути при создании CAB-файла, а не во вложенной папке.
  • CAB-файл также должен быть подписан. Неподписанные CAB-файлы и/или неподписанные DLL-файлы, содержащиеся в них, нельзя будет использовать в классических потоках, что приведет к ошибке при включении.

Следующие шаги

Отправить пользовательские действия