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".
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.
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#.
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.
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.
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.