Cree acciones de Power Automate para escritorio utilizando el SDK de acciones
Este artículo describe cómo crear acciones personalizadas en Power Automate para escritorio.
Crear acciones personalizadas
Importante
Las palabras clave reservadas no se pueden utilizar como nombres de acciones ni propiedades de acciones. El uso de palabras clave reservadas como nombres de acciones y/o propiedades de acciones genera un comportamiento erróneo. Más información: Palabras clave reservadas en flujos de escritorio
Empiece por crear un nuevo proyecto de biblioteca de clases (.NET Framework). Seleccione .NET framework versión 4.7.2.
Para formar una acción en el módulo personalizado creado:
- Elimine el archivo Class1.cs autogenerado.
- Cree una nueva clase dentro de su proyecto para representar la acción personalizada y asígnele un nombre distinto.
- Incluya los espacios de nombres Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK y Microsoft.PowerPlatform.PowerAutomate.Desktop.Actions.SDK.Attributes.
- Todas las clases que representan acciones deben tener un atributo [Acción] sobre su clase.
- La clase debe tener acceso público y heredar de la clase 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();
}
}
}
Las mayoría de acciones pueden tener parámetros (Entrada o Salida). Los parámetros de entrada y salida están representados por propiedades de C# clásicas.
Cada propiedad debe tener un atributo de C# adecuado, bien [InputArgument]
o [OutputArgument]
para dictar su tipo y cómo se presentan en Power Automate para escritorio.
Los argumentos de entrada también pueden tener valores predeterminados.
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}";
}
}
}
Agregar descripciones a acciones personalizadas
Agregue una descripción y un nombre descriptivo para los módulos y acciones para que los desarrolladores de RPA sepan cómo utilizarlos mejor.
Power Automate para el diseñador de escritorio muestra nombres y descripciones descriptivos.
Puede crear un archivo "Resources.resx" dentro de la carpeta Propiedades del proyecto del módulo. El nuevo archivo ".resx" debe llamarse "Resources.resx".
El formato de las descripciones de Módulos y Acciones debe ser el siguiente:
"Module_Description" o "Action_Description" y "Module_FriendlyName" o "Action_FriendlyName" respectivamente en el campo de nombre. La descripción en el campo de valor.
También recomendamos que proporcione descripciones y nombres descriptivos para los parámetros. Su formato debe ser el siguiente: "Action_Parameter_Description", "Action_Parameter_FriendlyName".
Propina
Se recomienda indicar qué es lo que está describiendo en el campo de comentarios (por ejemplo, Módulo, Acción, etc.)
Estos también se pueden establecer con las propiedades FriendlyName y Descripción de los atributos [InputArgument]
, [OutputArgument]
y [Action]
.
He aquí un ejemplo de un archivo Resources.resx para un módulo personalizado.
Otra forma de agregar rápidamente nombres descriptivos y descripciones a acciones y parámetros es con las propiedades FriendlyName y Description en los atributos [Action], [InputArguement] y [OutputArguement].
Nota
Para agregar un nombre descriptivo y una descripción a un módulo, debe modificar el archivo .resx respectivo o agregar los atributos de C# respectivos.
Agregar control de errores a las acciones personalizadas
Para definir excepciones personalizadas en su acción, utilice el atributo [Throws("ActionError")]
situado encima de la clase de acción personalizada. Cada caso de excepción que desee definir debe tener su propio atributo.
En el bloque catch, use el siguiente código:
throw new ActionException("ActionError", e.Message, e.InnerException);
Asegúrese de que el nombre ActionException
coincida con el nombre que proporcionó en el atributo Throws
. Utilice throw new ActionException
para cada caso de excepción y hágalo coincidir con el nombre de atributo correspondiente Throws
. Todas las excepciones definidas con el atributo Throws
son visibles en la pestaña de control de errores de acción del diseñador.
Un ejemplo de esto se puede encontrar en la sección de Acciones condicionales.
Localización de recursos
El idioma predeterminado para los módulos en Power Automate para escritorio se supone que es inglés.
El archivo Resources.resx debe estar en inglés.
Cualquier otro idioma se puede agregar con archivos Resources.{locale}.resx adicionales para localización. Por ejemplo, Resources.fr.resx.
Categorías de módulos personalizados
Los módulos pueden incluir categorías y subcategorías para una mejor organización de las acciones.
Para separar las acciones personalizadas en categorías, subcategorías, modifique el atributo [Action] que precede a la clase que representa la acción personalizada de la siguiente manera:
[Action(Category = "category.subcategory")]
Nota
Un Módulo puede tener varias categorías. Del mismo modo, las categorías pueden estar compuestas por subcategorías. Esta estructura puede ser indefinida.
La propiedad Orden dicta el orden en que se previsualizan las acciones en el diseñador.
Action1
pertenece a la categoría "TestCategory" y es la primera acción del módulo (de esta manera explicas Orden y categoría con un ejemplo).
[Action(Id = "Action1", Order = 1, Category = "TestCategory")]
Acciones condicionales
Las acciones condicionales son acciones que devuelven "Verdadero" o "Falso". La acción 'Si el archivo existe' de Power Automate para escritorio de la biblioteca estándar es un buen ejemplo de una acción condicional.
Ejemplo de acción 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 la variable booleana Resultado.
La acción Si el archivo existe no tiene un argumento de salida. Lo que devuelve es verdadero o falso, dependiendo de lo que contenga la variable booleana Resultado.
Selectores de acción personalizados
Hay casos particulares en los que se puede requerir que una acción personalizada tenga más de una variación.
Un ejemplo es la acción "Ejecutar Excel", de la biblioteca estándar de acciones.
Al usar el selector "con un documento en blanco", el flujo inicia un documento de Excel en blanco, mientras que al usar la selección "y abrir el siguiente documento" se requiere la ruta del archivo para abrir.
Las dos acciones mencionadas anteriormente son dos selectores de la acción base "Iniciar Excel".
Al crear acciones personalizadas, no tiene que volver a escribir la funcionalidad.
Puede crear una sola acción "base", configurando sus parámetros de entrada y salida y luego elegir lo que sería visible en cada tipo utilizando selectores de acción.
A través de los selectores de acción, se puede agregar un nivel de abstracción sobre una sola acción, lo que permite recuperar una funcionalidad específica de la única acción "base" sin tener que volver a escribir el código para formar una nueva variación de la misma acción cada vez.
Piense en los selectores como opciones, filtrando una sola acción y presentando solo la información requerida de acuerdo con los respectivos selectores.
Para formar un nuevo selector de acción, primero cree una acción base para que la utilicen los selectores.
La acción central requiere una propiedad booleana o de enumeración como argumento de entrada de C#.
El valor de esta propiedad determina qué selector se utiliza.
La forma más común es usar una enumeración. Especialmente cuando se necesitan más de dos selectores, las enumeraciones son la única opción.
Para dos casos selectores, se pueden usar booleanos.
Esta propiedad, también conocida como argumento de restricción, debe tener un valor predeterminado.
La acción central se declara como una acción clásica.
Observe que la primera propiedad (argumento de entrada) es una enumeración. Según el valor de esa propiedad, el selector apropiado se activa.
Nota
Para tener los argumentos ordenados de la manera que desee, establezca el valor de Orden junto al 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
}
Selectores de acción personalizados usando enums
En este ejemplo, crea tres selectores. Una enumeración simple dicta el selector apropiado cada vez:
public enum SelectorChoice
{
Selector1,
Selector2,
Selector3
}
Los selectores están representados por clases.
Esas clases deben heredar de la clase ActionSelector<TBaseActionClass>
.
Nota
TBaseActionClass es el nombre de la clase de acción base.
En el método UseName(), se declara el nombre del selector de acción. Se utiliza como nombre de la acción para resolver los 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);
}
}
Nota
Las clases Selector no deben declararse como acciones. La única acción es la central. Los selectores actúan como filtros.
En este ejemplo específico, queremos mostrar solo uno de los argumentos, por lo que los demás se filtran. Del mismo modo para Selector2:
public class Selector2 : ActionSelector<CentralCustomAction>
{
public Selector2()
{
UseName("DisplayFullName");
Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector2);
ShowAll();
Hide(p => p.Age);
}
}
Y las clases Selector3:
public class Selector3 : ActionSelector<CentralCustomAction>
{
public Selector3()
{
UseName("DisplayFullDetails");
Prop(p => p.Selector).ShouldBe(SelectorChoice.Selector3);
ShowAll();
}
}
La ejecución final se logra a través del método Execute(ActionContext context) que reside en la acción central. En función del selector, se muestran los 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}";
}
}
Selectores de acción personalizados usando booleanos
El siguiente es un ejemplo que utiliza Boolean en lugar de enumeraciones.
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);
}
}
}
Configuración de descripciones para selectores de acción personalizados
Para crear una descripción y un resumen de los selectores, utilice el siguiente formato en el archivo .resx de su módulo personalizado.
SelectorName_Description
SelectorName_Summary
Esto también se puede hacer en el selector con los métodos WithDescription y WithSummary.
Importante
Los archivos .dll que describen las acciones personalizadas, sus dependencias .dll y el archivo .cab que contiene todo deben estar debidamente firmados con un certificado digital de confianza para su organización. El certificado también debe instalarse en cada máquina en la que se crea, modifica o ejecuta el flujo de escritorio con dependencias de acción personalizadas, presentes en las entidades de certificación raíz de confianza.
ID de módulos personalizados
Cada módulo tiene su propio ID (nombre del ensamblado). Al crear módulos personalizados, asegúrese de establecer ID de módulo únicos. Para establecer el nombre del ensamblado de su módulo, modifique la propiedad Nombre del ensamblado en la sección General de las propiedades del proyecto de C#.
Advertencia
Incluir módulos con la misma ID en un flujo generará conflictos
Convenciones de nombres de módulos personalizados
Para que los módulos personalizados se puedan leer a través de Power Automate para escritorio, el AssemblyName debe tener un nombre de archivo que siga el siguiente patrón:
?*.Modules.?*
Modules.?*
Por ejemplo, Modules.ContosoActions.dll
El AssemblyTitle en la configuración del proyecto especifica el ID del módulo. Solo puede tener caracteres alfanuméricos y guiones bajos y debe comenzar con una letra.
Firmar todas las DLL dentro del módulo personalizado
Importante
Es obligatorio tener todos los archivos .dll que componen un módulo personalizado (ensamblado generado y todas sus dependencias) firmados con un certificado confiable
Para finalizar la creación del módulo personalizado, todos los archivos .dll generados, que se pueden encontrar en la carpeta bin/release o bin/Debug del proyecto, deben estar firmados.
Firme todos los archivos .dll utilizando un certificado confiable ejecutando el siguiente comando (para cada archivo .dll) en un símbolo del sistema del desarrollador para Visual Studio:
Firme todos los archivos .dll utilizando un certificado confiable ejecutando el siguiente comando (para cada .dll) en un símbolo del sistema del desarrollador para 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
O ejecutando el siguiente comando (creando un script de Windows PowerShell .ps1) que recorre en iteración todos los archivos .dll y firma cada uno con el certificado proporcionado:
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
}
Nota
El certificado digital debe tener una clave privada exportable y capacidades de firma de código
Empaquetado de todo en un archivador
El .dll que contiene las acciones personalizadas y todas sus dependencias (archivos .dll) debe empaquetarse en un archivo contenedor (.cab).
Nota
Al nombrar el archivo .cab, siga la convención de nomenclatura de archivos y carpetas para el sistema operativo Windows. No utilice espacios en blanco o caracteres especiales como < > : " / \ | ? *
.
Cree un script de Windows PowerShell (.ps1) que contenga las siguientes líneas:
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
Este script de Windows PowerShell se puede usar para crear el archivo .cab invocándolo en Windows PowerShell y proporcionando:
- El directorio de los archivos .dll que se van a comprimir.
- El directorio de destino para colocar el archivo .cab generado.
Invoque el script mediante la siguiente sintaxis:
.\{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
Ejemplo:
.\makeCabFile.ps1 "C:\Users\Username\source\repos\MyCustomModule\bin\Release\net472" "C:\Users\Username\MyCustomActions" MyCustomActions.cab
Nota
- Asegúrese de que el archivo .dll de acciones personalizadas real esté en el nivel raíz de la ruta de destino al crear el archivo .cab y no en una subcarpeta.
- El archivo .cab también debe estar firmado. Los archivos .cab sin firmar y/o los .dll sin firmar contenidos en ellos no se podrán utilizar en los flujos de escritorio y darán como resultado un error durante la inclusión.
Pasos siguientes
Cargar acciones personalizadas