You are viewing limited content. For full access, please sign in.

Question

Question

Running Powershell commands from workflow

asked on November 10, 2020

Hello Everyone,

I have tried this code with no success. 

https://answers.laserfiche.com/questions/153212/How-to-run-a-powershell-script-on-another-server-from-workflow

I get this error message at the start of "string acc =" code:

Error    1    A namespace cannot directly contain members such as fields or methods    

Not exactly sure why but what I can tell you is that I have installed and tested the commands I have on the workflow server and they work as expected. So I don't really need to call these commands to a different machine. I'm just looking for a way to pass a simple Powershell command from workflow using some tokens and get it executed. Can anyone help me? I can create the commands in Workflow easily, I just need a way to execute them from Workflow. 

Thank you!

0 0

Answer

SELECTED ANSWER
replied on November 10, 2020 Show version history

so the first thing is that you seem to be missing the Execute method and all of your code is just inside of the Class.

The code should always go

  • Namespace
    • Class
      • Method/Function

 

I'd suggest creating a new SDK script activity to get a clean start, then slowly add code into the Execute method a little at a time so you can test things as you go.

 

namespace WorkflowActivity.Scripting.SDKScript
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Text;
    using Laserfiche.RepositoryAccess;

    /// <summary>
    /// Provides one or more methods that can be run when the workflow scripting activity is performed.
    /// </summary>
    public class Script1 : RAScriptClass104
    {
        /// <summary>
        /// This method is run when the activity is performed.
        /// </summary>
        protected override void Execute()
        {
            // Write your code here. The BoundEntryInfo property will access the entry, RASession will get the Repository Access session
        }
    }
}

When you create a new script activity, it looks like that; notice how yours is missing the "protected override void Execute()" block, and that's the first thing you need to resolve.

1 0

Replies

replied on November 10, 2020 Show version history

It sounds like a problem in how the code is formatted, specifically, that you may have placed a variable or method directly under the namespace; variables should be under the method or class, and methods should be within a class.

0 0
replied on November 10, 2020

Thank you for the response, Jason. This is the code I'm trying to use to execute a Powershell command. Can you tell me what else is messed up about it? I have so many errors right now. lol. 

namespace WorkflowActivity.Scripting.Script
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Text;
    using System.Management.Automation;
    using System.Management.Automation.Runspaces;
    using System.Security;

public class script1 : RAScriptClass104
{

    // Connection credentials
string acc = "MYACCOUNT";
string pwd = "MYPASSWORD";
SecureString spwd = new SecureString();

// Convert password to secure string
foreach (char X in pwd){
    spwd.AppendChar(X);
}

PSCredential credential = new PSCredential(acc,spwd);

WSManConnectionInfo ci = new WSManConnectionInfo();
ci.ComputerName = "ACTIVEDIRECTORYMACHINE"
ci.Credential = credential;
ci.AuthenticationMechanism = AuthenticationMechanism.Default;

using(Runspace rs = RunspaceFactory.CreateRunspace(ci)){
    rs.Open();

    using(Pipeline p = rs.CreatePipeline()){
        Command cmd = new Command("New-ADGroup");
        cmd.Parameters.Add("-Name","TestGroup");
        p.Commands.Add(cmd);
        p.Invoke();

        if(p.Error.Count > 0){
            StringBuilder err = new StringBuilder();
            while(!p.Error.EndOfPipeline){
                err.AppendLine(p.Error.Read().ToString());
            }

            MsgBox(err.ToString());
        }
    }
}
}    
}

 

0 0
SELECTED ANSWER
replied on November 10, 2020 Show version history

so the first thing is that you seem to be missing the Execute method and all of your code is just inside of the Class.

The code should always go

  • Namespace
    • Class
      • Method/Function

 

I'd suggest creating a new SDK script activity to get a clean start, then slowly add code into the Execute method a little at a time so you can test things as you go.

 

namespace WorkflowActivity.Scripting.SDKScript
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.Text;
    using Laserfiche.RepositoryAccess;

    /// <summary>
    /// Provides one or more methods that can be run when the workflow scripting activity is performed.
    /// </summary>
    public class Script1 : RAScriptClass104
    {
        /// <summary>
        /// This method is run when the activity is performed.
        /// </summary>
        protected override void Execute()
        {
            // Write your code here. The BoundEntryInfo property will access the entry, RASession will get the Repository Access session
        }
    }
}

When you create a new script activity, it looks like that; notice how yours is missing the "protected override void Execute()" block, and that's the first thing you need to resolve.

1 0
replied on November 10, 2020

Thank you so much, Jason. You are a lifesaver. This is going to allow me to dynamically add users to AD groups so that my HR person has control of user access rights with a simple field value and I don't have to teach her how to manage access right. I'll have a workflow do the work and I can control everything. 

0 0
replied on November 10, 2020

Actually... if your goal is to allow Workflow to add people to AD groups, I can do you one better. PowerShell works fine and all, but it does add another layer to things that can make it harder to detect when something goes wrong and it isn't entirely necessary if you have the right code.

C# has the DirectoryServices library, which can provide access to the same functionality without the overhead of PowerShell. This example isn't an SDK Script because it isn't using any LF functionality, but...

namespace WorkflowActivity.Scripting.Script
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Data.SqlClient;
    using System.DirectoryServices.AccountManagement;
    using System.Text;

    public class Script1 : ScriptClass90
    {
        protected override void Execute()
        {
            // variables for results/output
            bool success = false;
            string message = string.Empty;
            
            // domain and container for your AD Domain
            string domain = "DOMAIN";
            string container = "DC=" + domain + ",DC=LOCAL";
            
            // credentials for modifying Active Directory
            string username = "username";
            string password = "password";
            
            // user and target group
            string account = GetTokenValue("Account").ToString();
            string groupName = GetTokenValue("GroupName").ToString();
            
            try {
                // get principal context for working in directory
                using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain, container, username, password)){
                    // get group principal object based on name
                    using (GroupPrincipal g = GroupPrincipal.FindByIdentity(pc, groupName)){
                        // if group found
                        if (g != null){
                            // get principal object (could be user or group)
                            using (Principal p = Principal.FindByIdentity(pc, account)){
                                // if account found
                                if (p != null){
                                    // check if account is already in group to prevent errors
                                    if (!p.IsMemberOf(g)){
                                        // add account to group
                                        g.Members.Add(p);
                                        g.Save();
                                        
                                        message = "Account added to group";
                                    }
                                    // track result if user already in group
                                    else {
                                        message = "Account already in group";
                                    }
                                    
                                    // success to true if user is added or already in group
                                    success = true;
                                }
                                // account not found
                                else {
                                    message = "Account not found";
                                }
                            }
                        }
                        // group not found
                        else {
                            message = "Group not found";
                        }
                    }
                }
            }
            catch (Exception ex){
                // track error to output
                message = ex.Message;
            }
            finally {
                // output results to tokens that can be evaluated by the workflow
                SetTokenValue("Success",success);
                SetTokenValue("Message",message);
            }
        }
    }
}

I had this left over because we do something similar to automate account changes initiated by HR. I've since built a full API for Active Directory so WF now just does all of this with API calls, but this is something I used early on in testing.

It looks like your previous test script was actually creating a group rather than adding members, which would be a different process, but that's something you can also do with DirectoryServices if you really wanted.

1 1
replied on November 11, 2020

I'll give this a try. Thank you so much. I was at first trying to create the group because I had so many to create for the way I wanted security to work, but then I deligated that part. lol. Now that I have all the groups, I just need to add users and remove users per the discretion of HR. I really liked the idea of them being in "control" without having to teach them Access rights and AD group managment. (Which really just gives me more work and support) The idea is to put a field on a folder, then they can see the user that has access and change if needed. Only the HR admins would see and be able to modify this field. 

Thank you so much for the help, I love this site when I get an "Answer" like this!!

 

0 0
You are not allowed to follow up in this post.

Sign in to reply to this post.