Compartilhar via


Criar Power Automate para desktop usando o SDK de Ações

Este artigo descreve como criar e usar ações personalizadas no Power Automate para desktop.

Criando ações personalizadas

Importante

Palavras-chave reservadas não podem ser usadas como nomes de ações e/ou propriedades de ações. O uso de palavras-chave reservadas como nomes de ações e/ou propriedades de ações resulta em comportamento errôneo. Mais informações: Palavras-chave reservadas em fluxos da área de trabalho

Comece criando um novo projeto de biblioteca de classes (.NET Framework). Selecione o .NET framework versão 4.7.2.

Para formar uma ação no módulo personalizado criado:

  • Exclua o arquivo Class1.cs gerado automaticamente.
  • Crie uma nova classe dentro do seu projeto para representar a ação personalizada e dê a ela um nome distinto.
  • Inclua os namespaces Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK e Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes.
  • Todas as classes que representam ações devem ter um atributo [Action] acima de sua classe.
  • A classe deve ter acesso público e herdar da classe 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();
        }
    }
}

Mais ações têm parâmetros (Entrada ou Saída). Os parâmetros de Entrada e Saída são representados pelas propriedades clássicas C#. Cada propriedade deve ter um atributo C# apropriado [InputArgument] ou [OutputArgument] para determinar seu tipo e como eles são apresentados no Power Automate para desktop. Os argumentos de entrada também podem ter valores padrão.

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}";
        }
    }
}

Adicionando descrições a ações personalizadas

Adicione uma descrição e um nome amigável para os módulos e ações para que os desenvolvedores de RPA saibam como utilizá-los da melhor maneira.

O designer do Power Automate para desktop mostra nomes e descrições amigáveis.

Você pode criar um arquivo "Resources.resx" dentro da pasta Propriedades do projeto do módulo. O novo arquivo ".resx" deve ser nomeado "Resources.resx".

O formato das descrições dos Módulos e Ações deve ser o seguinte:

"Module_Description" ou "Action_Description" e "Module_FriendlyName" ou "Action_FriendlyName" respectivamente no campo de nome. A descrição no campo de valor.

Também recomendamos que você forneça descrições e nomes amigáveis ​​para os parâmetros. Seu formato deve ser o seguinte: "Action_Parameter_Description", "Action_Parameter_FriendlyName".

Captura de tela de Recursos para uma ação simples

Dica

Recomenda-se indicar o que você está descrevendo no campo de comentário (por exemplo, Módulo, Ação, etc.)

Eles também podem ser definidos com as propriedades FriendlyName e Description dos atributos [InputArgument], [OutputArgument] e [Action].

Aqui está um exemplo de um arquivo Resources.resx para um módulo personalizado.

Captura de tela de Recursos

Outra maneira de adicionar rapidamente nomes amigáveis e descrições a ações e parâmetros é com as propriedades FriendlyName e Description nos atributos [Action], [InputArguement] e [OutputArguement].

Observação

Para adicionar um nome amigável e uma descrição a um módulo, você deve modificar o respectivo arquivo .resx ou adicionar os respectivos atributos C#.

Adicionando tratamento de erros a ações personalizadas

Para definir exceções personalizadas em sua ação, use o atributo [Throws("ActionError")] acima da classe de ação personalizada. Cada caso de exceção que você deseja definir deve ter seu próprio atributo.

No bloco catch, use o seguinte código:

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

Verifique se o nome ActionException corresponde ao nome fornecido no atributo Throws. Use throw new ActionException para cada caso de exceção e corresponda-o com o nome do atributo Throws correspondente. Todas as exceções definidas com o atributo Throws ficam visíveis na guia Tratamento de erros de ação do designer.

Um exemplo disso pode ser encontrado na seção Ações condicionais.

Localização de recursos

O idioma padrão é o inglês para módulos no Power Automate para desktop.

O arquivo Resources.resx deve estar em inglês.

Quaisquer outros idiomas podem ser adicionados aos arquivos Resources.{locale}.resx para localização. Por exemplo: Resources.fr.resx.

Categorias de módulo personalizado

Os módulos podem incluir categorias e subcategorias para melhor organização da ação.

Para separar as ações personalizadas em categorias, subcategorias, modifique o atributo [Action] que precede a classe que representa a ação personalizada da seguinte maneira:

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

Observação

Um Módulo pode ter várias categorias. Da mesma forma, as categorias podem ser compostas por subcategorias. Essa estrutura pode ser indefinida.

A propriedade Order determina a ordem pela qual as ações são visualizadas no designer.

Action1 pertence à categoria "TestCategory" e é a primeira ação do módulo (desta forma você explica Ordem e categoria com um exemplo).

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

Ações condicionais

Ações condicionais são ações que retornam "Verdadeiro" ou "Falso". 'Se o arquivo existir', a ação do Power Automate para desktop da biblioteca padrão é um bom exemplo de uma ação condicional.

Exemplo de ação condicional:

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
    }
}

Observe a variável booleana Result.

A ação Se o arquivo existir não tem um argumento de saída. O que ele retorna é verdadeiro ou falso, dependendo do que a variável booliana Result contém.

Seletores de ação personalizados

Existem casos particulares em que uma ação personalizada pode precisar ter mais de uma variação.

Um exemplo é a ação "Iniciar Excel", da biblioteca padrão de ações.

Usando o seletor "com um documento em branco", o fluxo inicia um documento em branco do Excel, enquanto usar a seleção "e abrir o seguinte documento" requer o caminho do arquivo a ser aberto.

Captura de tela de seletores da ação Iniciar o Excel

As duas ações mencionadas acima são dois seletores da ação base "Iniciar o Excel".

Ao criar ações personalizadas, você não precisa reescrever a funcionalidade.

Você pode criar uma única ação "base", definindo seus parâmetros de entrada e saída e, em seguida, escolher o que seria visível em cada versão, utilizando os seletores de ação.

Por meio de seletores de ação, um nível de abstração pode ser adicionado em uma única ação, permitindo a recuperação de funcionalidade específica da única ação "base" sem ter que reescrever o código para formar uma nova variação da mesma ação todas as vezes.

Pense nos seletores como escolhas, filtrando uma única ação e apresentando apenas as informações necessárias de acordo com os respectivos seletores.

Captura de tela do diagrama de seletores de ação

Para formar um novo seletor de ação, primeiro crie uma ação base a ser utilizada pelos seletores.

A ação central requer uma propriedade booliana ou de enumeração como um argumento C# de entrada.

O valor desta propriedade determina qual seletor é utilizado.

A maneira mais comum é usar uma enumeração. Principalmente quando são necessários mais de dois seletores, as enumerações são a única opção.

Para os casos de dois seletores, os boolianos podem ser usados.

Essa propriedade, também conhecida como argumento de restrição, deve ter um valor padrão.

A ação central é declarada como uma ação clássica.

Observe que a primeira propriedade (argumento de entrada) é uma enumeração. Com base no valor dessa propriedade, o seletor apropriado se torna ativo.

Observação

Para ter os argumentos ordenados da maneira desejada, defina o valor Order ao lado do atributo 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
}

Seletores de ação personalizados usando enumerações

Neste exemplo, você cria três seletores. Uma enumeração simples determina o seletor apropriado a cada vez:

public enum SelectorChoice
{
    Selector1,
    Selector2,
    Selector3
}

Os seletores são representados por classes.

Essas classes devem herdar a classe ActionSelector<TBaseActionClass>.

Observação

TBaseActionClass é o nome da classe de ação base.

No método UseName(), o nome do seletor de ação é declarado. Isso é usado como um nome da ação para resolver os recursos.

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);
    }
}

Observação

As classes do Seletor não devem ser declaradas como ações. A única ação é a central. Os seletores atuam como filtros.

Neste exemplo específico, queremos exibir apenas um dos argumentos, portanto, os outros são filtrados. Da mesma forma para Seletor2:

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

E as classes Selector3:

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

A execução final é conseguida através do método Executar (contexto ActionContext) que reside na ação central. Com base no seletor, são exibidos os respectivos valores filtrados.

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}";
    }
}

Seletores de ação personalizados usando boolianos

O seguinte é um exemplo utilizando Booliano, em vez de enumerações.

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);
        }
    }
}

Descrições de configuração para seletores de ação personalizados

Para criar uma descrição e um resumo para seletores, use o seguinte formato no arquivo .resx de seu módulo personalizado.

SelectorName_Description
SelectorName_Summary

Isso também pode ser feito no seletor com os métodos WithDescription e WithSummary.

Importante

Arquivos .dll que descrevem ações personalizadas, suas dependências .dll e o arquivo .cab devem ser devidamente assinados com um certificado digital confiável de sua organização. O certificado também deve ser instalado em cada máquina na qual um fluxo da área de trabalho com dependências de ação personalizada é criado/modificado/executado, presente nas Autoridades de Certificação Raiz Confiáveis.

IDs de módulos personalizados

Cada módulo possui seu próprio ID (nome do assembly). Ao criar módulos personalizados, certifique-se de definir as IDs de módulo exclusivas. Para definir o nome do assembly do seu módulo, modifique a propriedade Nome do assembly na seção General das propriedades do projeto C#.

Aviso

Incluir módulos com a mesma ID em um fluxo resultará em conflitos

Convenções de nome de módulo personalizado

Para que os módulos personalizados sejam legíveis por meio do Power Automate para desktop, o AssemblyName deve ter um nome de arquivo que siga o padrão abaixo:

?*.Modules.?*
Modules.?*

Por exemplo, Modules.ContosoActions.dll

O AssemblyTitle nas configurações do projeto especifica a ID do módulo. Pode ter apenas caracteres alfanuméricos e sublinhados e deve começar com uma letra.

Assinar todas as DLLs dentro do módulo personalizado

Importante

É obrigatório ter todos os arquivos .dll que compõem um módulo customizado (assembly gerado e todas as suas dependências) assinados com um certificado confiável

Para finalizar a criação do módulo personalizado, todos os arquivos .dll gerados, que podem ser encontrados na pasta bin/release ou bin/Debug do projeto, devem ser assinados.

Assine todos os arquivos .dll usando um certificado confiável executando o seguinte comando (para cada arquivo .dll) em um prompt de comando do desenvolvedor para o Visual Studio:

Assine todos os arquivos .dll usando um certificado confiável executando o seguinte comando (para cada dll) em um Prompt de Comando do Desenvolvedor para o 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

ou executando o seguinte comando (criando um .ps1 do Script do Windows PowerShell) que percorre todos os arquivos .dll e assina cada um com o certificado fornecido:

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
}

Observação

O certificado digital deve ter uma chave privada exportável e recursos de assinatura de código

Empacotando tudo em um arquivo de gabinete

O .dll que contém as ações personalizadas e todas as suas dependências (arquivos .dll) deve ser empacotado em um arquivo gabinete (.cab).

Observação

Ao nomear o arquivo .cab, siga a convenção de nomenclatura de arquivo e pasta para o sistema operacional Windows. Não use espaços em branco ou caracteres especiais como < > : " / \ | ? * .

Crie um script do Windows PowerShell (.ps1) contendo as seguintes linhas:

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

Esse script do Windows PowerShell pode ser usado para criar o arquivo .cab invocando-o no Windows PowerShell e fornecendo:

  • O diretório para os arquivos .dll a serem compactados.
  • O diretório de destino para colocar o arquivo .cab gerado.

Chame o script usando a seguinte sintaxe:

.\{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

Exemplo:

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

Observação

  • Certifique-se de que o arquivo .dll de ações personalizadas reais esteja no nível raiz do caminho de destino ao criar o arquivo .cab e não em uma subpasta.
  • O arquivo .cab também deve ser assinado. Arquivos .cab não assinados e/ou .dlls não assinados contidos neles não poderão ser usados em fluxos da área de trabalho e resultarão em erro durante a inclusão.

Próximas etapas

Carregar ações personalizadas