├── ConvertWorkflowFW.csproj
├── Program.cs
├── README.md
├── SS.png
└── SS1.png
/ConvertWorkflowFW.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {4442A724-1D87-43ED-9D94-C5D878AC729A}
8 | Exe
9 | ConvertWorkflowFW
10 | ConvertWorkflowFW
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | bin\Debug\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 | ..\packages\AngleSharp.0.9.9\lib\net45\AngleSharp.dll
38 |
39 |
40 | ..\packages\Microsoft.Azure.ActiveDirectory.GraphClient.2.1.0\lib\portable-net4+sl5+win+wpa+wp8\Microsoft.Azure.ActiveDirectory.GraphClient.dll
41 |
42 |
43 | ..\packages\Microsoft.Azure.KeyVault.Core.1.0.0\lib\net40\Microsoft.Azure.KeyVault.Core.dll
44 |
45 |
46 | ..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll
47 |
48 |
49 | ..\packages\Microsoft.Data.Edm.5.8.4\lib\net40\Microsoft.Data.Edm.dll
50 |
51 |
52 | ..\packages\Microsoft.Data.OData.5.8.4\lib\net40\Microsoft.Data.OData.dll
53 |
54 |
55 | ..\packages\Microsoft.Data.Services.Client.5.8.4\lib\net40\Microsoft.Data.Services.Client.dll
56 |
57 |
58 | ..\packages\Microsoft.Graph.1.9.0\lib\net45\Microsoft.Graph.dll
59 |
60 |
61 | ..\packages\Microsoft.Graph.Core.1.9.0\lib\net45\Microsoft.Graph.Core.dll
62 |
63 |
64 | ..\packages\Microsoft.IdentityModel.7.0.0\lib\net35\microsoft.identitymodel.dll
65 |
66 |
67 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.dll
68 |
69 |
70 | ..\packages\Microsoft.IdentityModel.Clients.ActiveDirectory.3.19.8\lib\net45\Microsoft.IdentityModel.Clients.ActiveDirectory.Platform.dll
71 |
72 |
73 | ..\packages\Microsoft.IdentityModel.JsonWebTokens.5.2.4\lib\net451\Microsoft.IdentityModel.JsonWebTokens.dll
74 |
75 |
76 | ..\packages\Microsoft.IdentityModel.Logging.5.2.4\lib\net451\Microsoft.IdentityModel.Logging.dll
77 |
78 |
79 | ..\packages\Microsoft.IdentityModel.Tokens.5.2.4\lib\net451\Microsoft.IdentityModel.Tokens.dll
80 |
81 |
82 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.Office.Client.Policy.dll
83 |
84 |
85 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.Office.Client.TranslationServices.dll
86 |
87 |
88 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.Office.SharePoint.Tools.dll
89 |
90 |
91 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.Online.SharePoint.Client.Tenant.dll
92 |
93 |
94 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.ProjectServer.Client.dll
95 |
96 |
97 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.dll
98 |
99 |
100 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.DocumentManagement.dll
101 |
102 |
103 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.Publishing.dll
104 |
105 |
106 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.Runtime.dll
107 |
108 |
109 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.Runtime.Windows.dll
110 |
111 |
112 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.Search.dll
113 |
114 |
115 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.Search.Applications.dll
116 |
117 |
118 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.Taxonomy.dll
119 |
120 |
121 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.UserProfiles.dll
122 |
123 |
124 | ..\packages\Microsoft.SharePointOnline.CSOM.16.1.20317.12000\lib\net45\Microsoft.SharePoint.Client.WorkflowServices.dll
125 |
126 |
127 | ..\packages\WindowsAzure.Storage.7.0.0\lib\net40\Microsoft.WindowsAzure.Storage.dll
128 |
129 |
130 | ..\packages\Newtonsoft.Json.11.0.1\lib\net45\Newtonsoft.Json.dll
131 |
132 |
133 | ..\packages\SharePointPnPCoreOnline.3.24.2008.1\lib\net461\OfficeDevPnP.Core.dll
134 |
135 |
136 | ..\packages\SharePointPnP.IdentityModel.Extensions.1.2.4\lib\net45\SharePointPnP.IdentityModel.Extensions.dll
137 |
138 |
139 |
140 | ..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 | ..\packages\System.IdentityModel.Tokens.Jwt.5.2.4\lib\net451\System.IdentityModel.Tokens.Jwt.dll
149 |
150 |
151 | ..\packages\System.IO.4.3.0\lib\net462\System.IO.dll
152 | True
153 | True
154 |
155 |
156 | ..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll
157 |
158 |
159 | ..\packages\System.Net.Http.4.3.1\lib\net46\System.Net.Http.dll
160 | True
161 | True
162 |
163 |
164 | ..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll
165 |
166 |
167 |
168 | ..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll
169 |
170 |
171 | ..\packages\System.Runtime.4.3.0\lib\net462\System.Runtime.dll
172 | True
173 | True
174 |
175 |
176 | ..\packages\System.Runtime.CompilerServices.Unsafe.4.7.1\lib\net461\System.Runtime.CompilerServices.Unsafe.dll
177 |
178 |
179 |
180 | ..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net463\System.Security.Cryptography.Algorithms.dll
181 | True
182 | True
183 |
184 |
185 | ..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll
186 | True
187 | True
188 |
189 |
190 | ..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll
191 | True
192 | True
193 |
194 |
195 | ..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll
196 | True
197 | True
198 |
199 |
200 |
201 | ..\packages\System.Spatial.5.8.4\lib\net40\System.Spatial.dll
202 |
203 |
204 | ..\packages\System.Text.Encodings.Web.4.7.1\lib\net461\System.Text.Encodings.Web.dll
205 |
206 |
207 | ..\packages\System.Text.Json.4.7.2\lib\net461\System.Text.Json.dll
208 |
209 |
210 | ..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll
211 |
212 |
213 | ..\packages\System.ValueTuple.4.5.0\lib\net47\System.ValueTuple.dll
214 |
215 |
216 |
217 |
218 | ..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text;
3 | using System.Threading.Tasks;
4 | using System.Net.Http;
5 | using System.Xml;
6 | using Microsoft.IdentityModel.Clients.ActiveDirectory;
7 | using System.Net.Http.Headers;
8 | using System.Text.Json;
9 |
10 | namespace ConvertWorkflowFW
11 | {
12 | class Program
13 | {
14 | /*****************
15 | * TODO: Replace user, password, and SharePoint Online URL.
16 | */
17 | private static readonly HttpClient client = new HttpClient();
18 | private static readonly string user = "username@domain.onmicrosoft.com";
19 | private static readonly string password = "password";
20 | private static readonly string url = "https://domain.sharepoint.com";
21 | static async Task Main(string[] args)
22 | {
23 | await GetLegacyWorkflow(); //Legacy Authentication must be enabled within tenant(https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/sharepoint-online-authentication-in-powershell-for-csom-when/ba-p/510114)
24 | await CreateNewWorkflow();
25 | }
26 |
27 | /*****************
28 | * TODO: Enable Legacy Authentication
29 | * Replace workflow site collection URL, workflow name
30 | */
31 | private static async Task GetLegacyWorkflow()
32 | {
33 | string workflowSiteCollectionURL = "/sites/SiteCollectionName";
34 | string workflowName = "TestWorkflow";
35 | /*****************
36 | * Get Security Token for required FedAuth and rtFa cookies.
37 | */
38 | XmlDocument doc = new XmlDocument();
39 | doc.LoadXml("" +
42 | "" +
43 | "http://schemas.xmlsoap.org/ws/2005/02/trust/RST/Issue" +
44 | "" +
45 | "http://www.w3.org/2005/08/addressing/anonymous" +
46 | "" +
47 | "https://login.microsoftonline.com/extSTS.srf" +
48 | "" +
50 | "" +
51 | "" + user + "" +
52 | "" + password + "" +
53 | "" +
54 | "" +
55 | "" +
56 | "" +
57 | "" +
58 | "" +
59 | "" +
60 | "" + url + workflowSiteCollectionURL + "" +
61 | "" +
62 | "" +
63 | "http://schemas.xmlsoap.org/ws/2005/05/identity/NoProofKey" +
64 | "http://schemas.xmlsoap.org/ws/2005/02/trust/Issue" +
65 | "urn:oasis:names:tc:SAML:1.0:assertion" +
66 | "" +
67 | "" +
68 | "");
69 |
70 | HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://login.microsoftonline.com/extSTS.srf");
71 | request.Content = new StringContent(doc.InnerXml, Encoding.UTF8, "application/xml");
72 | HttpResponseMessage response;
73 | response = await client.SendAsync(request);
74 | var responseString = await response.Content.ReadAsStringAsync();
75 |
76 | doc = new XmlDocument();
77 | doc.LoadXml(responseString);
78 | XmlNodeList nodeList = doc.GetElementsByTagName("wsse:BinarySecurityToken");
79 | string token = string.Empty;
80 | foreach (XmlNode node in nodeList)
81 | {
82 | token = node.InnerText;
83 | }
84 | /*****************
85 | * Send Security Token to get FedAuth and rtFa cookies.
86 | */
87 | request = new HttpRequestMessage(HttpMethod.Post, url + "/_forms/default.aspx?wa=wsignin1.0");
88 | request.Headers.Add("Accept", "application/json; odata=verbose");
89 | request.Content = new StringContent(token);
90 | response = await client.SendAsync(request);
91 |
92 | /*****************
93 | * Since we are using the same HttpClient object, the FedAuth and rtFa cookies are now contained in it.
94 | * Get the .xoml file for the relevant workflow.
95 | */
96 | request = new HttpRequestMessage(HttpMethod.Post, url + workflowSiteCollectionURL + "/_vti_bin/_vti_aut/author.dll");
97 | request.Headers.Add("X-Vermeer-Content-Type", "application/x-www-form-urlencoded");
98 | request.Content = new StringContent("method=get+document:15.0.0.4455&service_name=" +
99 | workflowSiteCollectionURL +
100 | "&document_name=Workflows/" + workflowName + "/" +
101 | workflowName +
102 | ".xoml&old_theme_html=false&force=true&get_option=none&doc_version=&timeout=0&expandWebPartPages=true",
103 | Encoding.UTF8, "application/x-www-form-urlencoded");
104 |
105 | response = await client.SendAsync(request);
106 | responseString = await response.Content.ReadAsStringAsync();
107 |
108 | /*****************
109 | * Since we are using the same HttpClient object, the FedAuth and rtFa cookies are now contained in it.
110 | * Get the .xoml.wfconfig.xml file for the relevant workflow.
111 | */
112 | request = new HttpRequestMessage(HttpMethod.Post, url + workflowSiteCollectionURL + "/_vti_bin/_vti_aut/author.dll");
113 | request.Headers.Add("X-Vermeer-Content-Type", "application/x-www-form-urlencoded");
114 | request.Content = new StringContent("method=get+document:15.0.0.4455&service_name=" +
115 | workflowSiteCollectionURL +
116 | "&document_name=Workflows/" + workflowName + "/" +
117 | workflowName +
118 | ".xoml.wfconfig.xml&old_theme_html=false&force=true&get_option=none&doc_version=&timeout=0&expandWebPartPages=true",
119 | Encoding.UTF8, "application/x-www-form-urlencoded");
120 |
121 | response = await client.SendAsync(request);
122 | responseString = await response.Content.ReadAsStringAsync();
123 | }
124 |
125 | /*****************
126 | * TODO: Create app registration for CDS authentication(https://docs.microsoft.com/en-us/powerapps/developer/common-data-service/walkthrough-register-app-azure-active-directory#create-an-application-registration),
127 | * Replace clientID with app registration Client Id,
128 | * Replace Power Automate Web API URL(https://docs.microsoft.com/en-us/power-automate/web-api#compose-http-requests),
129 | * Replace clientData with content from relevant Power Automate flow(https://docs.microsoft.com/en-us/power-automate/web-api#list-flows)
130 | */
131 | private static async Task CreateNewWorkflow()
132 | {
133 | string resource = "https://org00000000.crm.dynamics.com";
134 | string authorityURI = "https://login.microsoftonline.com/common";
135 | string clientID = "000000000-0000-0000-0000-000000000";
136 | Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext authContext = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authorityURI, false);
137 | UserPasswordCredential credentials = new UserPasswordCredential(user, password);
138 | AuthenticationResult authResult = await authContext.AcquireTokenAsync(resource, clientID, credentials);
139 | string accessToken = authResult.AccessToken;
140 | //Replace with clientData from preferred Power Automate flow.
141 | string clientData = "{\"properties\":{\"connectionReferences\":{\"shared_commondataservice\":{\"connectionName\":\"shared-commondataser-00000000-0000-0000-0000-000000000004\",\"source\":\"Invoker\",\"id\":\"/providers/Microsoft.Power Apps/apis/shared_commondataservice\"}},\"definition\":{\"$schema\": \"https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#\",\"contentVersion\": \"1.0.0.0\",\"parameters\": {\"$connections\": {\"defaultValue\": {},\"type\": \"Object\"},\"$authentication\": {\"defaultValue\": {},\"type\": \"SecureObject\"}},\"triggers\": {\"Recurrence\": {\"recurrence\": {\"frequency\": \"Minute\",\"interval\": 1},\"type\": \"Recurrence\"}},\"actions\": {\"List_records\": {\"runAfter\": {},\"metadata\": {\"flowSystemMetadata\": {\"swaggerOperationId\": \"GetItems_V2\"}},\"type\": \"ApiConnection\",\"inputs\": {\"host\": {\"api\": {\"runtimeUrl\": \"https://firstrelease-001.azure-apim.net/apim/commondataservice\"},\"connection\": {\"name\": \"@parameters('$connections')['shared_commondataservice']['connectionId']\"}},\"method\": \"get\",\"path\": \"/v2/datasets/@{encodeURIComponent(encodeURIComponent('default.cds'))}/tables/@{encodeURIComponent(encodeURIComponent('accounts'))}/items\",\"queries\": {\"$top\": 1},\"authentication\": \"@parameters('$authentication')\"}}},\"outputs\": {}}},\"schemaVersion\":\"1.0.0.0\"}";
142 | WorkFlow workflow = new WorkFlow
143 | {
144 | category = 5,
145 | statecode = 0,
146 | name = "Sample Flow",
147 | type = 1,
148 | description = "Sample flow to test programmatic creation.",
149 | primaryentity = "none",
150 | clientdata = clientData
151 | };
152 | client.DefaultRequestHeaders.Accept.Add(
153 | new MediaTypeWithQualityHeaderValue("application/json"));
154 | HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, resource + "/api/data/v9.1/workflows");
155 | request.Content = new StringContent(JsonSerializer.Serialize(workflow), Encoding.UTF8, "application/json");
156 | request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
157 | HttpResponseMessage response = client.SendAsync(request).Result;
158 | if (!response.IsSuccessStatusCode)
159 | {
160 | Console.WriteLine("Error creating workflow: " + response.StatusCode + " - " + response.ReasonPhrase);
161 | }
162 | }
163 | }
164 | public class WorkFlow
165 | {
166 | public int category { get; set; }
167 | public int statecode { get; set; }
168 | public string name { get; set; }
169 | public int type { get; set; }
170 | public string description { get; set; }
171 | public string primaryentity { get; set; }
172 | public string clientdata { get; set; }
173 | }
174 | }
175 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SharePointWorkflowConverter
2 | A proof-of-concept C# console application for retrieving legacy 2010 & 2013 custom SharePoint workflow definition files, and creating new Power Automate flows programmatically.
3 |
4 | ### General Notes:
5 | 1. This project is a proof-of-concept to demonstrate that it's *possible* to programmatically retrieve/parse SharePoint legacy workflow definition files and create new Power Automate flows. As for specific use cases and implementation, this is a launch pad for you to build those out.
6 | 1. Only compatible with SharePoint Online.
7 | 2. Tested with a tenant [global admin](https://docs.microsoft.com/en-us/microsoft-365/admin/add-users/about-admin-roles?view=o365-worldwide#commonly-used-microsoft-365-admin-center-roles) account.
8 | 3. Uses the 4.7.2 [.NET Framework](https://docs.microsoft.com/en-us/dotnet/standard/choosing-core-framework-server).
9 | 4. The code for retrieving legacy workflows and the code for creating a new Power Automate flow are contained in 2 separate respective functions: `GetLegacyWorkflow()` and `CreateNewWorkflow()`. If you don't need one or the other for your purposes, simply comment them out.
10 | ### Notes about retrieving legacy 2010/2013 workflows:
11 | 1. [Legacy authentication](https://techcommunity.microsoft.com/t5/microsoft-sharepoint-blog/sharepoint-online-authentication-in-powershell-for-csom-when/ba-p/510114) must be enabled in the tenant for this code to work.
12 | 2. All custom list/library workflows created within SharePoint Designer will have `*.xoml` and `*.xoml.wfconfig.xml` files. Each file contains pertinent information describing the workflow, such as list/library associations, actions, etc. You can manually view these files in [SharePoint Designer 2013](https://www.microsoft.com/en-us/download/details.aspx?id=35491) by clicking *All Files* from the left-hand navigation and selecting > *Workflows*. The files can be programmatically retrieved using this project and parsed to map to equivalent Power Automate connections, actions, etc.
13 | 
14 | 3. Declarative `*.xoml` and `*.xoml.wfconfig.xml` files do not appear to exist for workflows created from [OOB SharePoint 2010 or 2013 workflow templates](https://support.microsoft.com/en-us/office/overview-of-workflows-included-with-sharepoint-d74fcceb-3a64-40fb-9904-cc33ca49da56). *(If you can find them - I'll buy you a beverage of your choice!)*
15 | ### Notes about creating Power Automate flows:
16 | 1. This project leverages the [Power Automate Management Web API](https://docs.microsoft.com/en-us/power-automate/web-api) to create a new Power Automate flow.
17 | 2. Per Microsoft's [documentation](https://docs.microsoft.com/en-us/power-automate/web-api), flows shown in the *My Flows* tab are not supported by these APIs. Instead you will find flows created via the API in your *[Solutions](https://flow.microsoft.com/en-us/blog/solutions-in-microsoft-flow/) > Default Solution* tab.
18 | *(I have opened a [GitHub issue](https://github.com/MicrosoftDocs/power-automate-docs/issues/323) inquiring about how to programmatically create Power Automate flows within solutions other than Default.)*
19 | 3. The meat and potatoes of the flow payload is in the `clientdata` property. To help determine appropriate content for this section, I recommend manually creating the desired Power Automate flow using the UI. Then, you can [leverage the API](https://docs.microsoft.com/en-us/power-automate/web-api#list-flows) to get the `clientdata` content for your manual flow and copy/paste it into the payload for your new flow.
20 | *(Also a great strategy for programmatically bulk-creating Power Automate flows in an environment!)*
21 | 4. Once you successfully create a new Power Automate flow via the API, you will need to turn it on. Then, do a Ctrl+F5 refresh to confirm your connections appear as expected.
22 | 
23 |
24 | ### Happy Automating! :-)
25 |
--------------------------------------------------------------------------------
/SS.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dev-Mom/SharePointWorkflowConverter/b13d2a83fb657eb0d52dc9d8488911093405d51f/SS.png
--------------------------------------------------------------------------------
/SS1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Dev-Mom/SharePointWorkflowConverter/b13d2a83fb657eb0d52dc9d8488911093405d51f/SS1.png
--------------------------------------------------------------------------------