From 4383306ae01fc38360c1615fa505dbec129cca7a Mon Sep 17 00:00:00 2001 From: Jake Friedman Date: Fri, 30 Dec 2022 15:56:30 -0800 Subject: [PATCH 1/6] codeAndmanualdocs --- README.md | 10 +- build/FixupAPIMarkdown.ps1 | 2 - docs/AddAPILinks.ps1 | 18 +- ...ctory-orchestrator-client-usage-samples.md | 94 ++++---- .../images/connectpage-advancedoptions.png | Bin 0 -> 17839 bytes docs/docs/images/connectpage.png | Bin 32743 -> 62302 bytes docs/docs/service-configuration.md | 98 ++++++-- docs/docs/tasks-and-tasklists.md | 36 +-- docs/docs/use-the-factory-orchestrator-api.md | 20 +- docs/docs/use-the-factory-orchestrator-app.md | 8 +- docs/mkdocs.yml | 9 +- .../TcpIpcClient.cs | 10 +- .../TcpIpcClientOptions.cs | 3 + .../TcpIpcEndpoint.cs | 28 ++- .../TcpIpcEndpointOptions.cs | 7 +- src/App/App.xaml.cs | 4 +- src/App/ConnectionPage.xaml | 37 ++- src/App/ConnectionPage.xaml.cs | 213 ++++++++++++++++-- src/App/Resources/en-US/Resources.resw | 38 +++- src/App/Settings.cs | 76 ++++++- src/App/TaskListExecutionPage.xaml.cs | 8 +- .../FactoryOrchestratorClient.cs | 123 ++++++++-- ...icrosoft.FactoryOrchestrator.Client.csproj | 6 +- src/CoreLibrary/IPCInterface.cs | 18 +- .../Microsoft.FactoryOrchestrator.Core.csproj | 6 +- src/CoreLibrary/SharedClasses.cs | 1 - src/PowerShellLibrary/CmdletClasses.cs | 22 +- .../FactoryOrchestratorClientSync.cs | 43 ++-- src/Service/FactoryServer.pfx | Bin 4158 -> 4053 bytes src/Service/ServiceExe.cs | 170 +++++++++++--- src/UWPClientLibrary/DnsSdHelpers.cs | 8 +- .../FactoryOrchestratorUWPClient.cs | 36 +-- ...osoft.FactoryOrchestrator.UWPClient.csproj | 4 + src/common.props | 2 +- 34 files changed, 888 insertions(+), 270 deletions(-) create mode 100644 docs/docs/images/connectpage-advancedoptions.png diff --git a/README.md b/README.md index 0d7145871..d8e643cf2 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ Factory Orchestrator :green_heart: OSS. * **IpcServiceFramework** - FactoryOrchestrator forks the source of [IpcServiceFramework](https://github.com/jacqueskang/IpcServiceFramework). The fork is equivalent the latest IpcServiceFramework source as of December 2020, with only a project file change to set DisableDynamicCodeGeneration to true so it can be used in .NET Native applications. + FactoryOrchestrator forks the source of [IpcServiceFramework](https://github.com/jacqueskang/IpcServiceFramework). The fork is equivalent the latest IpcServiceFramework source as of December 2020, with additions to support client authentication and logging. * **Pe-Utility** @@ -63,6 +63,14 @@ FactoryOrchestrator ## Prerequisites to build source code +### Git configuration + +You may need to enable long path support to successfully clone this repo. To enable this system-wide, run: + +```powershell +git config --system core.longpaths true +``` + ### Install dependencies Building Factory Orchestrator source requires the [NET 5.0 SDK](https://dotnet.microsoft.com/download/dotnet/5.0), the [NET Core 3.1 runtime.](https://dotnet.microsoft.com/download/dotnet/3.1/runtime/), and [PowerShell 7+](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell) (or Windows PowerShell). If you wish to build the app as well, you also need the Universal Windows Platform Development (10.0.19041.0) SDK. diff --git a/build/FixupAPIMarkdown.ps1 b/build/FixupAPIMarkdown.ps1 index 8f41fc1ad..2d9d62def 100644 --- a/build/FixupAPIMarkdown.ps1 +++ b/build/FixupAPIMarkdown.ps1 @@ -10,7 +10,6 @@ Param $ErrorActionPreference = "stop" Write-Host "Fixing markdown in $DefaultDocumentationFolder." -Write-Host "Replacing 'https://docs.microsoft.com/en-us/dotnet/api/Microsoft.FactoryOrchestrator.Core.' paths..." Write-Host "Replacing '``1'' strings..." $mds = Get-ChildItem -Path $DefaultDocumentationFolder -Include "*.md" -Recurse @@ -18,7 +17,6 @@ $mds = Get-ChildItem -Path $DefaultDocumentationFolder -Include "*.md" -Recurse foreach ($md in $mds) { $content = Get-Content $md - $content = $content.Replace("https://docs.microsoft.com/en-us/dotnet/api/Microsoft.FactoryOrchestrator.Core.", "./../../CoreLibrary/Microsoft-FactoryOrchestrator-Core-") $content = $content.Replace("``1'","'") Set-Content -Path $md -Value $content } \ No newline at end of file diff --git a/docs/AddAPILinks.ps1 b/docs/AddAPILinks.ps1 index 9b7fd8259..3f2a4007e 100644 --- a/docs/AddAPILinks.ps1 +++ b/docs/AddAPILinks.ps1 @@ -10,15 +10,15 @@ $regex = '\(.*\)' $scriptDir = Split-Path $script:MyInvocation.MyCommand.Path $docPath = [System.IO.Path]::Join($scriptDir, "docs") $userDocs = Get-ChildItem -Path $docPath -filter "*.md" -$apiDocs = Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Core-TaskList*.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Core-TaskBase*.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Core-UWPTask.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Core-ExecutableTask.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Core-PowerShellTask.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Core-ExternalTask.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Core-TaskRun*.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-*.md" -Recurse -$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft-FactoryOrchestrator-Client-ServerPoller-*.md" -Recurse +$apiDocs = Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Core_TaskList*.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Core_TaskBase*.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Core_UWPTask.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Core_ExecutableTask.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Core_PowerShellTask.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Core_ExternalTask.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Core_TaskRun*.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_*.md" -Recurse +$apiDocs += Get-ChildItem -Path $docPath -filter "Microsoft_FactoryOrchestrator_Client_ServerPoller-*.md" -Recurse $apiDocs = $apiDocs | Sort-Object -Descending $apiNames = @{} diff --git a/docs/docs/factory-orchestrator-client-usage-samples.md b/docs/docs/factory-orchestrator-client-usage-samples.md index 68e8bfc02..71d6cb17f 100644 --- a/docs/docs/factory-orchestrator-client-usage-samples.md +++ b/docs/docs/factory-orchestrator-client-usage-samples.md @@ -7,7 +7,7 @@ This page describes how to perform a variety of tasks with the Factory Orchestra Remember: - All C# client APIs are asynchronous, but all PowerShell APIs are synchronous. -- To use the C# client APIs in a UWP app, use an instance of FactoryOrchestratorUWPClient instead of [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/). +- To use the C# client APIs in a UWP app, use an instance of FactoryOrchestratorUWPClient instead of [FactoryOrchestratorClient]((../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_FactoryOrchestratorClient%28System_Net_IPAddress_int%29/). - 'device' is used below to refer to the PC running the Factory Orchestrator service you connect to with the client. This could be the same PC as the client. **All C# code snippets assume you have:** @@ -33,12 +33,12 @@ using Microsoft.FactoryOrchestrator.Client; Install-Module Microsoft.FactoryOrchestrator.Client ``` -# Factory Orchestrator .NET client sample +## Factory Orchestrator .NET client sample A sample .NET Core program that communicates with the Factory Orchestrator service is available in the Factory Orchestrator GitHub repo at: [https://github.com/microsoft/FactoryOrchestrator/tree/main/src/ClientSample](https://github.com/microsoft/FactoryOrchestrator/tree/main/src/ClientSample). You can build it with Visual Studio 2019 or the .NET Core 3.1+ SDK. The sample shows you how to connect to a remote (or local) device running Factory Orchestrator service, copy test files to that device, sideload UWP apps, execute test content, and retrieve the test results from the device. -## Factory Orchestrator client sample usage +### Factory Orchestrator client sample usage Once the sample is built, create a folder on your PC with test content and a [FactoryOrchestratorXML](../tasks-and-tasklists/#author-and-manage-factory-orchestrator-tasklists) file that references the test content in the location it will execute from on the test device. Then, run the sample by calling: ```cmd @@ -47,7 +47,7 @@ dotnet ClientSample.dll x.IsRunningOrPending)) await client.GetDirectoryFromDevice(await client.GetLogFolder(), @"C:\some_folder_on_client_for_logs"); ``` -## Modify an existing [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/) -This example shows how to modify an existing [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/) using [QueryTaskList](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-QueryTaskList%28System-Guid%29/) and [UpdateTaskList](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-UpdateTaskList%28Microsoft-FactoryOrchestrator-Core-TaskList%29/). +### Modify an existing [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/) +This example shows how to modify an existing [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/) using [QueryTaskList](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_QueryTaskList%28System_Guid%29/) and [UpdateTaskList](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_UpdateTaskList%28Microsoft_FactoryOrchestrator_Core_TaskList%29/). ```csharp // Assumes you have an existing TaskList in the service with a GUID of 34d0534b-ed09-46c2-b6bb-73cef9574944. var taskListGuid = new Guid("34d0534b-ed09-46c2-b6bb-73cef9574944"); @@ -141,8 +153,8 @@ taskList.AllowOtherTaskListsToRun = false; // Update the TaskList on the service. await client.UpdateTaskList(taskList); ``` -## Get all existing TaskLists and print out information about each [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/). -This example uses the [GetTaskListSummaries](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetTaskListSummaries%28%29/) and [QueryTaskList](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-QueryTaskList%28System-Guid%29/) methods print out information about running [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/) instances. +### Get all existing TaskLists and print out information about each [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/). +This example uses the [GetTaskListSummaries](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetTaskListSummaries%28%29/) and [QueryTaskList](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_QueryTaskList%28System_Guid%29/) methods print out information about running [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/) instances. ```csharp var summaries = await client.GetTaskListSummaries(); @@ -162,14 +174,14 @@ foreach (var summary in summaries) } ``` -## Stop executing an existing & running [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/) +### Stop executing an existing & running [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/) ```csharp // Assumes you have an existing TaskList in the service with a GUID of 34d0534b-ed09-46c2-b6bb-73cef9574944. await client.AbortTaskList(new Guid("34d0534b-ed09-46c2-b6bb-73cef9574944")); ``` -## Check for service events. Use WaitingForExternalTaskRun to handle every [ExternalTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-ExternalTask/) requiring manual completion. -This example uses the GetServiceEvents method to check if an [ExternalTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-ExternalTask/) needs manual completion. If so, it uses [QueryTaskRun](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-QueryTaskRun%28System-Guid%29/) and [UpdateTaskRun](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-UpdateTaskRun%28Microsoft-FactoryOrchestrator-Core-TaskRun%29/) to complete the [ExternalTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-ExternalTask/). +### Check for service events. Use WaitingForExternalTaskRun to handle every [ExternalTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_ExternalTask/) requiring manual completion. +This example uses the GetServiceEvents method to check if an [ExternalTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_ExternalTask/) needs manual completion. If so, it uses [QueryTaskRun](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_QueryTaskRun%28System_Guid%29/) and [UpdateTaskRun](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_UpdateTaskRun%28Microsoft_FactoryOrchestrator_Core_TaskRun%29/) to complete the [ExternalTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_ExternalTask/). ```csharp ulong lastEvent = 0; @@ -204,8 +216,8 @@ await Task.Delay(5000); } ``` -## Run a program to completion and print output to console -This example uses the [RunExecutable](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-RunExecutable%28string_string_string_bool%29/)() method to run a program outside of a [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/). It then uses [QueryTaskRun](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-QueryTaskRun%28System-Guid%29/) to monitor the program's status. +### Run a program to completion and print output to console +This example uses the [RunExecutable](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_RunExecutable%28string_string_string_bool%29/)() method to run a program outside of a [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/). It then uses [QueryTaskRun](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_QueryTaskRun%28System_Guid%29/) to monitor the program's status. ```csharp // Start the program @@ -245,10 +257,10 @@ foreach ($line in $($taskRun.TaskOutput)) } ``` -# Using [ServerPoller](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-ServerPoller-ServerPoller%28System-Nullable-System-Guid-_System-Type_int_bool_int%29/) instances to monitor [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/) & [TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/) execution asynchronously with C# events -The [ServerPoller](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-ServerPoller-ServerPoller%28System-Nullable-System-Guid-_System-Type_int_bool_int%29/) class is used to automatically poll the service for updates, and generates an [OnUpdatedObject](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-ServerPoller-OnUpdatedObject/) event only when the chosen [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/) or [TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/) object you are polling updates. It can also be used to query all TaskLists for their high-level status. [ServerPoller](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-ServerPoller-ServerPoller%28System-Nullable-System-Guid-_System-Type_int_bool_int%29/) objects are a good choice to asynchronously update your UI or console output. +## Using [ServerPoller](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_ServerPoller_ServerPoller%28System_Nullable_System_Guid__System_Type_int_bool_int%29/) instances to monitor [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/) & [TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/) execution asynchronously with C# events +The [ServerPoller](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_ServerPoller_ServerPoller%28System_Nullable_System_Guid__System_Type_int_bool_int%29/) class is used to automatically poll the service for updates, and generates an [OnUpdatedObject](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_ServerPoller_OnUpdatedObject/) event only when the chosen [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/) or [TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/) object you are polling updates. It can also be used to query all TaskLists for their high-level status. [ServerPoller](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_ServerPoller_ServerPoller%28System_Nullable_System_Guid__System_Type_int_bool_int%29/) objects are a good choice to asynchronously update your UI or console output. -This example uses the ServerPoller's [StartPolling](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-ServerPoller-StartPolling%28Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient%29/) method and [OnUpdatedObject](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-ServerPoller-OnUpdatedObject/) event to monitor TaskList and [TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/) objects. +This example uses the ServerPoller's [StartPolling](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_ServerPoller_StartPolling%28Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient%29/) method and [OnUpdatedObject](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_ServerPoller_OnUpdatedObject/) event to monitor TaskList and [TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/) objects. ```csharp object consoleLock = new object(); @@ -342,8 +354,8 @@ void OnUpdatedTaskRun(object source, ServerPollerEventArgs e) } ``` -# Install an app, enable local loopback on the installed app, and then launch it (Windows Only & requires Windows Device Portal is running) -This example uses [SendAndInstallApp](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-SendAndInstallApp%28string_System-Collections-Generic-List-string-_string%29/), [EnableLocalLoopbackForApp](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-EnableLocalLoopbackForApp%28string%29/), and [RunApp](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-RunApp%28string%29/) to install a UWP app on the device, enable local loopback on the app (enabling it to talk to a localhost Factory Orchestrator service), and launch the app. +## Install an app, enable local loopback on the installed app, and then launch it (Windows Only & requires Windows Device Portal is running) +This example uses [SendAndInstallApp](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_SendAndInstallApp%28string_System-Collections-Generic-List-string-_string%29/), [EnableLocalLoopbackForApp](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_EnableLocalLoopbackForApp%28string%29/), and [RunApp](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_RunApp%28string%29/) to install a UWP app on the device, enable local loopback on the app (enabling it to talk to a localhost Factory Orchestrator service), and launch the app. ```csharp // Assumes appFolder is a "standard" Visual Studio 2019 published app package with an appx/msix, a .cer certificate, and a dependencies folder. @@ -377,10 +389,10 @@ await client.EnableLocalLoopbackForApp("Contoso.TestApp_8wekyb3d8bbwe"); await client.RunApp("Contoso.TestApp_8wekyb3d8bbwe"); ``` -# System information +## System information The following examples show how to get information about the hardware and software of the device the service is running on. -## Get OS and Factory Orchestrator build versions -This example uses [GetOSVersionString](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetOSVersionString%28%29/), [GetOEMVersionString](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetOEMVersionString%28%29/), [GetServiceVersionString](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetServiceVersionString%28%29/), and [GetClientVersionString](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetClientVersionString%28%29/) to get various system & Factory Orchestrator information. +### Get OS and Factory Orchestrator build versions +This example uses [GetOSVersionString](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetOSVersionString%28%29/), [GetOEMVersionString](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetOEMVersionString%28%29/), [GetServiceVersionString](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetServiceVersionString%28%29/), and [GetClientVersionString](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetClientVersionString%28%29/) to get various system & Factory Orchestrator information. ```csharp // GetOSVersionString() & GetOEMVersionString() are Windows only @@ -390,7 +402,7 @@ var servicebuild = await client.GetServiceVersionString(); var clientbuild = await client.GetClientVersionString(); ``` -## Get network adapter info with [GetIpAddressesAndNicNames](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetIpAddressesAndNicNames%28%29/) +### Get network adapter info with [GetIpAddressesAndNicNames](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetIpAddressesAndNicNames%28%29/) ```csharp var networkinfo = await client.GetIpAddressesAndNicNames(); Console.WriteLine($"The following networks are present on {client.IpAddress}:"); @@ -400,7 +412,7 @@ foreach (var network in networkinfo) } ``` -## Get installed UWP apps (Windows only) with [GetInstalledApps](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetInstalledApps%28%29/) +### Get installed UWP apps (Windows only) with [GetInstalledApps](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetInstalledApps%28%29/) ```csharp var appAUMIDs = await client.GetInstalledApps(); Console.WriteLine($"The following UWPs are installed on {client.IpAddress}:"); @@ -410,20 +422,20 @@ foreach (var aumid in appAUMIDs) } ``` -# System interaction -## Reboot device with [RebootDevice](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-RebootDevice%28uint%29/) +## System interaction +### Reboot device with [RebootDevice](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_RebootDevice%28uint%29/) ```csharp await client.RebootDevice(); ``` -## Shutdown device with [ShutdownDevice](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-ShutdownDevice%28uint%29/) +### Shutdown device with [ShutdownDevice](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_ShutdownDevice%28uint%29/) ```csharp await client.ShutdownDevice(); ``` -# File system interactions +## File system interactions The following examples show how to perform file system operations on the device the service is running on. -## List files & folders on device with EnumerateDirectories and EnumerateFiles +### List files & folders on device with EnumerateDirectories and EnumerateFiles ```csharp // List all folders under %windir% recursively var dirsRecursive = await client.EnumerateDirectories(@"%windir%", true); @@ -431,27 +443,27 @@ var dirsRecursive = await client.EnumerateDirectories(@"%windir%", true); var filesNonRecursve = await client.EnumerateFiles(@"%windir%", false); ``` -## Copy a file or folder from device to client with [GetFileFromDevice](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetFileFromDevice%28string_string_bool%29/) or [GetDirectoryFromDevice](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetDirectoryFromDevice%28string_string_bool%29/) +### Copy a file or folder from device to client with [GetFileFromDevice](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetFileFromDevice%28string_string_bool%29/) or [GetDirectoryFromDevice](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetDirectoryFromDevice%28string_string_bool%29/) ```csharp // C:\destination_folder_on_client is created if needed var bytesReceived = await client.GetDirectoryFromDevice(@"C:\source_folder_on_device", @"C:\destination_folder_on_client"); bytesReceived += await client.GetFileFromDevice(@"C:\different_folder_on_device\file.txt", @"C:\destination_folder_on_client\file.txt"); ``` -## Copy a file or folder from client to device with [SendFileToDevice](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-SendFileToDevice%28string_string_bool%29/) or [SendDirectoryToDevice](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-SendDirectoryToDevice%28string_string_bool%29/) +### Copy a file or folder from client to device with [SendFileToDevice](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_SendFileToDevice%28string_string_bool%29/) or [SendDirectoryToDevice](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_SendDirectoryToDevice%28string_string_bool%29/) ```csharp // C:\destination_folder_on_device is created if needed var bytesSent = await client.SendDirectoryToDevice(@"C:\source_folder_on_client", @"C:\destination_folder_on_device"); bytesSent += await client.SendFileToDevice(@"C:\different_source_folder_on_client\file.txt", @"C:\destination_folder_on_device\file.txt"); ``` -## Move a file or folder with [MoveFileOrFolder](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-MoveFileOrFolder%28string_string_bool%29/) +### Move a file or folder with [MoveFileOrFolder](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_MoveFileOrFolder%28string_string_bool%29/) ```csharp await client.MoveFileOrFolder(@"C:\folder_on_device\file.txt", @"C:\different_folder_on_device\file.txt"); await client.MoveFileOrFolder(@"C:\folder_on_device", @"C:\different_folder_on_device"); ``` -## Delete a file or folder with [DeleteFileOrFolder](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-DeleteFileOrFolder%28string_bool%29/) +### Delete a file or folder with [DeleteFileOrFolder](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_DeleteFileOrFolder%28string_bool%29/) ```csharp await client.DeleteFileOrFolder(@"C:\folder_on_device\file.txt"); await client.DeleteFileOrFolder(@"C:\folder_on_device"); diff --git a/docs/docs/images/connectpage-advancedoptions.png b/docs/docs/images/connectpage-advancedoptions.png new file mode 100644 index 0000000000000000000000000000000000000000..5372fc7021396b5024506e641d8eceeb41f8247f GIT binary patch literal 17839 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 literal 0 HcmV?d00001 diff --git a/docs/docs/images/connectpage.png b/docs/docs/images/connectpage.png index 00a546c7c43f5ab026715d697a93a82148210dbb..fa02a6d39a5c4d96455f356b82b7d8c80141cb02 100644 GIT binary patch literal 62302 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

q9q?O+0elK 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 literal 32743 zcmeFZdsvd`_b+Uxsiv86%5NuAtg);q&C1L?0MlVIGqpTqN=gkHlceMUPY5*Cj5Vob zmgbQuH3bFp04R#qRHB(OnLvs_g-VJ*9smV__p#>poA3U;*WT}b|JwWA*Xwm<@&Na9 zueCn+XRUj!bw4*w_CGm13m}L%xZ}%=FTkvUN66NG$h{4?3<_a{}yo2l@VrUgfy?i2LhAB6$YQm z7+9)}ZuPaZx5M9`T6RXXq2jRD%3(^8_s%m3mDg^5edF5T@7uq<68+%YOHZ1Z7S~fB z9`)s-v7HyQ9iZ`zK^tShJTRIj3f4!Yv95VljGgm&p;r(sI{P!;{ zzhXasdFO#!^ICYkW!a~38W$f}Gk-bnQv5A7TZL0SZ8K?2#;2!Eb0pJLqR?rk!Zb}X zw&W24nA6U(xwV9ewKn)UsSQ(JV~6V)2;9aL=EV zHtE&8vu-Dk+Wb810N?gtF>_h^D%xDS>7z}nYrDiKB

E83iWYrN1U?xwF}byZem1 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 # Factory Orchestrator service configuration using appsettings.json + The Factory Orchestrator service has many configurable settings that impact its startup behavior, enabled features, and more. This configuration is easily modified using an [appsettings.json file](https://docs.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#json-configuration-provider). The appsettings.json file is checked for in the following locations in order, with the last appsettings.json file found 'winning' if there are conflicts: @@ -19,16 +20,18 @@ The following table describes each setting and its usage: | RunInitialTaskListsOnFirstBoot | bool | If set to "true", the TaskLists defined by InitialTaskLists are run on first boot of the DUT (or the first time the service is run). They are not run on subsquent boots. | | [FirstBootTasks](#initialtasklists-firstboottasks-and-everyboottasks) | string | Path to a [FactoryOrchestratorXML](tasks-and-tasklists.md#author-and-manage-factory-orchestrator-tasklists) file. These TaskLists are run once, and then "hidden", on the first boot of the DUT (or the first time the service is run). They are not run on subsquent boots. [See below for more details.](#initialtasklists-firstboottasks-and-everyboottasks) | | [EveryBootTasks](#initialtasklists-firstboottasks-and-everyboottasks) | string | Path to a [FactoryOrchestratorXML](tasks-and-tasklists.md#author-and-manage-factory-orchestrator-tasklists) file. These TaskLists are run on every boot of the DUT, including first boot. They are then "hidden". [See below for more details.](#initialtasklists-firstboottasks-and-everyboottasks) | -| [EnableNetworkAccess](#network-access) | bool | If set to "true", the service will allow connections from clients/apps anywhere on your local network. Defaults to false. **⚠ [See below for more details.](#network-access) ⚠** | +| [EnableNetworkAccess](#network-access) | bool | If set to "true", the service will allow connections from clients/apps anywhere on your local network. Defaults to false. **⚠ It is recommended to only enable this if you also use the SSLCertificateFile and SSLAllowedClientCertificates settings. [See "Network Access" below for more details.](#network-access) ⚠** | | NetworkPort | int | The network port the service uses to communicate with clients, even local loopback clients. Defaults to 45684. | -| TaskRunLogFolder | string | Path of the directory where you want Task run logs saved. This setting is a first run default; it can be overriden at runtime by the [SetLogFolder](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-SetLogFolder%28string_bool%29/)() API. See [Tasks and Tasklists](tasks-and-tasklists.md#factory-orchestrator-task-log-files) for details about the log files for individual Task runs. | +| SSLCertificateFile | string | Path to the .PFX certificate (X509Certificate2) file used for the service's identity. If provided, the Factory Orchestrator Service will use the provided certificate for SSL encryption to communicate with clients. If not provided, a default SSL certificate is used. [See "Network Access" below for more details.](#network-access) | +| SSLAllowedClientCertificates | string | Semi-colon separated list of file paths to allowed client .PFX certificates. If provided, the Factory Orchestrator Service will only allow clients to connect to the Service if the client provided a certificate matching one in the list. If you really want to allow any client to connect, even a client with no certificate, set this value to "*". [See below for more details.](#network-access) | +| SSLUseDefaultClientCertificateValidation | bool | If set to "true", the Factory Orchestrator Service will ensure the certificate chain is valid and no certificate in the chain has been revoked. The certificate must also apply to the given hostname. [See "Network Access" below for more details.](#network-access) | +| TaskRunLogFolder | string | Path of the directory where you want Task run logs saved. This setting is a first run default; it can be overriden at runtime by the [SetLogFolder](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_SetLogFolder%28string_bool%29/)() API. See [Tasks and Tasklists](tasks-and-tasklists.md#factory-orchestrator-task-log-files) for details about the log files for individual Task runs. | | AllowedLocalLoopbackApps | string | **Windows only.** Semi-colon separated list of Windows app "Package Family Name"(s). The Factory Orchestrator service will enable local loopback on the given apps every boot. Requires "checknetisolation.exe" is found in your %PATH%. See [this Windows IoT page](https://docs.microsoft.com/en-us/windows/iot-core/develop-your-app/loopback#enabling-loopback-for-a-uwp-application) for more information. | DisableCommandPromptPage | bool | If set to "true", the Factory Orchestrator app will not show the "Command prompt" page. | | DisableWindowsDevicePortalPage | bool | **Windows only.** If set to "true", the Factory Orchestrator app will not show the "Device portal" page. | | DisableUWPAppsPage | bool | **Windows only.** If set to "true", the Factory Orchestrator app will not show the "UWP apps" page. | | DisableManageTasklistsPage | bool | If set to "true", the Factory Orchestrator app will not show the "Manage TaskLists" page. | | DisableFileTransferPage | bool | If set to "true", the Factory Orchestrator app will not show the "File Transfer" page. | -| SSLCertificateFile | string | Path to X509Certificate2 file. If provided the Factory Orchestrator Service will use the provided certificate for ssl encryption to communicate with client. | | IpcLogLevel | [LogLevel enum](https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.logging.loglevel) | Sets the logging level for the IPC binaries. If set to "Debug", or lower information about every client API call will be saved to the [service log](#factory-orchestrator-service-log-file). | | DisableContainerSupport | bool | **Windows only.** If set to "true", the service will not check for a container running Factory Orchestrator on your PC. | @@ -38,35 +41,73 @@ Here's an example of what a valid appsettings.json file looks like. { "EnableNetworkAccess":"true", "NetworkPort":"45000", + "SSLCertificateFile":"/etc/FactoryOrchestrator/ServiceCert.pfx", + "SSLAllowedClientCertificates":"/etc/FactoryOrchestrator/AllowedClientCert1.pfx;/etc/FactoryOrchestrator/AllowedClientCert2.pfx", "DisableFileTransferPage":"true", - "InitialTaskLists":"/etc/InitialTaskLists.xml" + "InitialTaskLists":"/etc/FactoryOrchestrator/InitialTaskLists.xml" } ``` -# Additional details + ## Network Access -By default, the Factory Orchestrator service only allows client connections from the same device the service is running on (i.e. localhost only). However, service can be configured to allow connections from clients anywhere on your local network, by setting EnableNetworkAccess to "true" in your [appsettings.json file](#factory-orchestrator-service-configuration-using-appsettings.json). - -

⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠

-

WARNING: Please read and understand the following before enabling network access!

-

⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠⚠

-
+By default, the Factory Orchestrator service only allows client connections from the same device the service is running on (i.e. localhost only). However, service can be configured to allow connections from clients anywhere on your local network, by setting EnableNetworkAccess to "true" in your [appsettings.json file](#factory-orchestrator-service-configuration-using-appsettingsjson). -- ⚠ The service allows any client to connect to it without authentication. Any connected client has full access to the service's computer, including the ability to send or copy files, and/or run any command or program with administrator rights. ⚠ (The service has SSL encryption, but it is server-only, clients are not authenticated.) -- ⚠ If you configure the service to automatically start, the service is configured to run from boot. Depending on the service & PC configuration it may even be running before a user has logged on to the computer. ⚠ -- ⚠ Once network access is enabled, it will remain enabled until "EnableNetworkAccess" is set to "false" and the service is restarted. ⚠ -- ⚠ The service and client send information over the network in SSL encrypted JSON using TCP. It is vulnerable to man-in-the-middle attacks, as the service defaults to a predefined SSL certificate unless a custom certificate is used. ⚠ -- ⚠ The service currently has minimal logging about what clients are connected to it and what commands each client has executed. ⚠ +### Network access caveats -To check if network access is currently enabled use one of the following: +- It is strongly recommend you use [your own SSL certificates](#ssl-certificates-and-authentication) for the service and clients as the service uses an insecure certificate and allows any client to connect to it without authentication by default. Any connected client has full access to the service's computer, including the ability to send or copy files, and/or run any command or program with administrator rights. +- If you configure the service to automatically start, the service is configured to run from boot. Depending on the service & PC configuration it may even be running before a user has logged on to the computer. +- The service has minimal logging about what clients are connected to it and what commands each client has executed. -- The Factory Orchestrator app's "About" page. -- The console output from Microsoft.FactoryOrchestrator.Service.exe -- The [service log file](#factory-orchestrator-service-log-file) -- The [IsNetworkAccessEnabled](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-IsNetworkAccessEnabled%28%29/) API. +### SSL certificates and authentication + +Factory Orchestrator supports using both client and service SSL certificates, enabling End-to-End authentication and encryption for all commands and data. **It is strongly recommend you use your own SSL certificates for the service AND all clients.** If you do not use your own certificates, Factory Orchestrator will still attempt (but not enforce) SSL encryption, but with no client authentication and will be vulnerable to impersonation and man-in-the-middle attacks. + +You can easily generate self-signed SSL certificates using the following openssl commands to generate a .pfx file for use by either the service or client(s): + +```bash +openssl req -x509 -sha256 -days 365 -nodes -newkey rsa:4096 -subj "/CN=MyFactoryOrchestrator" -keyout FactoryOrchestrator.key -out FactoryOrchestrator.crt +openssl pkcs12 -export -in FactoryOrchestrator.crt -inkey FactoryOrchestrator.key -out FactoryOrchestratorCerificate.pfx +``` + +_📝 PFX certificate passwords are not supported on the certificates used by Factory Orchestator. 📝_ + +#### Client authentication + +Since Factory Orchestrator clients have near complete control of the service's computer, client authentication is stricter than Service authentication. + +If **SSLAllowedClientCertificates** is set to a semi-colon separated list of .PFX certificate file paths, the Factory Orchestrator Service will only allow a client to connect if the certificate provided by the client matches on in the **SSLAllowedClientCertificates** list. The client's certificate must be an **exact** match to one in the list. + +If **SSLUseDefaultClientCertificateValidation** is true, the Factory Orchestrator Service will only allow a client to connect if the client's provided certificate has a valid certificate chain (on the Service's PC) and no certificate in the chain has been revoked. The certificate must also apply to the given hostname. + +Both settings may be used together for the strictest validation. + +If using the app, use the "Advanced Options" button on the Connect page to provide a Client certificate. + +If using C# or PowerShell, you can provide a client certificate to your [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) instance in either the [constructor](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) or with the instance's [ClientCertificate](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_ClientCertificate/) parameter. + +See [client usage samples for an example](../factory-orchestrator-client-usage-samples/#connect-to-the-service-running-on-a-remote-device-with-client-and-service-authentication). + +#### Service authentication + +Use the **SSLCertificateFile** option to provide a custom .PFX certificate for the Factory Orchestrator Service authentication. If one is not provided, a default certificate is used, but that is insecure and not recommended. + +Factory Orchestrator uses the Service's certificate "Thumbprint" and Identity/"Subject" for authentication by a [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) instance. To see the thumbprint and subject for a .PFX certificate, you can run the following PowerShell command: + +```powershell +Get-PfxCertificate ".\FactoryOrchestratorCerificate.pfx" | Select Thumbprint, Subject +``` + +If using the app, use the "Advanced Options" button on the Connect page to provide the expected Service certificate Identity and Thumbprint. + +If using C# or PowerShell, these values are provided in the [FactoryOrchestratorClient constructor](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_FactoryOrchestratorClient(System_Net_IPAddress_int_string_string_System_Security_Cryptography_X509Certificates_X509Certificate2)/) or with the [CertificateHash](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_CertificateHash/) and [ServerIdentity](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_ServerIdentity/) properties. + +See [client usage samples for an example](../factory-orchestrator-client-usage-samples/#connect-to-the-service-running-on-a-remote-device-with-client-and-service-authentication). + +You can also provide your own [certificate validation callback](https://learn.microsoft.com/en-us/dotnet/api/system.net.security.remotecertificatevalidationcallback?f1url=%3FappId%3DDev16IDEF1%26l%3DEN-US%26k%3Dk(System.Net.Security.RemoteCertificateValidationCallback)%3Bk(SolutionItemsProject)%3Bk(SolutionItemsProject)%3Bk(DevLang-csharp)%26rd%3Dtrue&view=netstandard-2.0) to the FactoryOrchestratorClient instance (either in the [constructor](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) or with the [ServerCertificateValidationCallback parameter](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_ServerCertificateValidationCallback/)) if you prefer to do your own validation of the Service's certificate. ### Firewall configuration + Depending on the configuration of the OS you are using, you may need to configure the firewall to allow the Factory Orchestrator service to communicate over your local network. Factory Orchestrator uses TCP port 54684 for client<->service communication and UDP port 5353 for [DNS-SD](find-factory-orchestrator-devices.md). On Windows, run the following command from an Administrator PowerShell window to allow Factory Orchestrator through the Windows firewall: @@ -84,6 +125,15 @@ sudo ufw allow 5353 If you set a custom network port via the NetworkPort setting, use that port number instead of 45684. +### Checking for network access + +To check if network access is currently enabled use one of the following: + +- The Factory Orchestrator app's "About" page. +- The console output from Microsoft.FactoryOrchestrator.Service.exe +- The [service log file](#factory-orchestrator-service-log-file) +- The [IsNetworkAccessEnabled](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_IsNetworkAccessEnabled%28%29/) API. + ## InitialTaskLists, FirstBootTasks, and EveryBootTasks  _💡 [We are considering reworking InitialTaskLists and \*BootTasks, as it is hard to understand the use cases and tradeoffs for each type](https://github.com/microsoft/FactoryOrchestrator/issues/109). 💡_ @@ -106,10 +156,10 @@ FirstBootTasks & EveryBootTasks have the following 'rules': You can inspect the [FactoryOrchestrator service and Task run log files](service-configuration.md#factory-orchestrator-logs) for details about the status and/or results of the \*BootTasks FactoryOrchestratorXML files, in "EveryBootTaskLists" & "FirstBootTaskLists" subfolders in the task run log directory. -# Factory Orchestrator logs -## Factory Orchestrator service log file +## Factory Orchestrator logs +### Factory Orchestrator service log file The service log file contains details about the operation of the Factory Orchestrator service. It is always found at `%ProgramData%\FactoryOrchestrator\FactoryOrchestratorService.log` on Windows and `/var/log/FactoryOrchestrator/FactoryOrchestratorService.log` on Linux. Inspect this log for details about the service's operation. -## Factory Orchestrator Task log files +### Factory Orchestrator Task log files See [Tasks and Tasklists](tasks-and-tasklists.md#factory-orchestrator-task-log-files) for details about the log files for individual Task runs. diff --git a/docs/docs/tasks-and-tasklists.md b/docs/docs/tasks-and-tasklists.md index 3dfe1b6f7..15be84359 100644 --- a/docs/docs/tasks-and-tasklists.md +++ b/docs/docs/tasks-and-tasklists.md @@ -6,7 +6,7 @@ Factory Orchestrator uses "Tasks" to capture a single action. Tasks can be executables, scripts, apps, TAEF tests, or external actions. TasksLists are used to order and group Tasks. -You can define a collection of tasks in a **[TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/)**. Tasks in a TaskList are run in a defined order, and can be a mixture that includes any type of tasks that's supported by Factory Orchestrator. TaskList data persists through reboots. TaskList data is stored and maintained by the Factory Orchestrator service, and doesn't depend on the app being open or running. Tasks in a TaskList can be configured to run in series, parallel, or in the background. +You can define a collection of tasks in a **[TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/)**. Tasks in a TaskList are run in a defined order, and can be a mixture that includes any type of tasks that's supported by Factory Orchestrator. TaskList data persists through reboots. TaskList data is stored and maintained by the Factory Orchestrator service, and doesn't depend on the app being open or running. Tasks in a TaskList can be configured to run in series, parallel, or in the background. Factory Orchestrator supports using environment variables (ex: %ProgramData%, $TMPDIR) in all Tasks. @@ -58,18 +58,18 @@ Factory Orchestrator TaskLists allow adding different types of tasks: ### Background tasks -A [BackgroundTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun-BackgroundTask/) is a type of Task which is not expected to return a pass/fail result. Instead, [BackgroundTasks](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList-BackgroundTasks/) are started before any Tasks defined in the TaskList, and are not tracked by the Factory Orchestrator Service, though their output is logged to a file. [BackgroundTasks](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList-BackgroundTasks/) are intended to be used for logging/monitoring tasks that need to be running before any Task in the TaskList executes. +A [BackgroundTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun_BackgroundTask/) is a type of Task which is not expected to return a pass/fail result. Instead, [BackgroundTasks](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList-BackgroundTasks/) are started before any Tasks defined in the TaskList, and are not tracked by the Factory Orchestrator Service, though their output is logged to a file. [BackgroundTasks](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList-BackgroundTasks/) are intended to be used for logging/monitoring tasks that need to be running before any Task in the TaskList executes. BackgroundTasks are defined the exactly the same as a normal Task with the following exceptions: -- [BackgroundTasks](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList-BackgroundTasks/) can only be an Executable, PowerShell, or BatchFile Task -- [BackgroundTasks](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList-BackgroundTasks/) cannot have Timeout or [MaxNumberOfRetries](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskBase-MaxNumberOfRetries/) set +- [BackgroundTasks](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList_BackgroundTasks/) can only be an Executable, PowerShell, or BatchFile Task +- [BackgroundTasks](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList_BackgroundTasks/) cannot have Timeout or [MaxNumberOfRetries](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskBase-MaxNumberOfRetries/) set When editing a task from the Factory Orchestrator app, you can choose the option of making the task a background task by choosing the "Add as background task?" option. -Once you've run a task, the Factory Orchestrator service creates a **[TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/)** that is the output and results of the task, as well as other details about the task such as runtime. +Once you've run a task, the Factory Orchestrator service creates a **[TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/)** that is the output and results of the task, as well as other details about the task such as runtime. -# Author and manage Factory Orchestrator TaskLists with FactoryOrchestratorXML +## Author and manage Factory Orchestrator TaskLists with FactoryOrchestratorXML Factory Orchestrator uses XML files, called FactoryOrchestratorXML, to manage TaskLists and their associated Tasks. An XML file can contain one or more TaskLists, each with any number of Tasks. @@ -77,7 +77,7 @@ The XML can either be hand-authored; or authored, imported, and/or exported usin You can get started with Factory Orchestrator TaskLists by using the [**Manage TaskLists**](use-the-factory-orchestrator-app.md#managing-tasklists) page in the Factory Orchestrator app to create a TaskList. -## Factory Orchestrator XML Schema +### Factory Orchestrator XML Schema When hand-authoring FactoryOrchestratorXML files, you'll need to follow the FactoryOrchestratorXML schema. At the end of this topic, we've also provided a [sample FactoryOrchestratorXML file](#sample-factory-orchestrator-xml-file): @@ -162,7 +162,7 @@ A TaskList element defines a Factory Orchestrator TaskList. The following define | Guid  | String  | N  | The GUID used to identify the TaskList. If not set, it will be assigned by the Factory Orchestrator Service automatically when the FactoryOrchestratorXML is loaded.  | | RunInParallel  | Bool  | Y  | If "true", the Tasks in this TaskList are executed in parallel. If "false", the Tasks in this TaskList are executed in order, one at a time.  | | AllowOtherTaskListsToRun  | Bool  | Y  | If "false", while this TaskList is running all other TaskLists are blocked from executing. If "true", other TaskLists may execute while this TaskList is running.   | -| TerminateBackgroundTasksOnCompletion  | Bool  | N  | If "true", any [BackgroundTasks](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList-BackgroundTasks/) defined in this TaskList are forcibly terminated when the TaskList's Tasks complete. If "false", any [BackgroundTasks](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList-BackgroundTasks/) defined in this TaskList continue executing. Defaults to "true". | +| TerminateBackgroundTasksOnCompletion  | Bool  | N  | If "true", any [BackgroundTasks](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList-BackgroundTasks/) defined in this TaskList are forcibly terminated when the TaskList's Tasks complete. If "false", any [BackgroundTasks](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList-BackgroundTasks/) defined in this TaskList continue executing. Defaults to "true". | #### Sample TaskList element @@ -177,16 +177,16 @@ A Task element defines a Factory Orchestrator Task. Tasks are pass/fail executab | Attribute Name  | Type  | Required?  | Details  | |------------------------|--------------|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| xsi:type  | See details  | Y  | The type of the Task. Allowed values are: [ExecutableTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-ExecutableTask/), [PowerShellTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-PowerShellTask/), BatchFileTask, TAEFTest, [UWPTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-UWPTask/), and [ExternalTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-ExternalTask/).  | +| xsi:type  | See details  | Y  | The type of the Task. Allowed values are: [ExecutableTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_ExecutableTask/), [PowerShellTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_PowerShellTask/), BatchFileTask, TAEFTest, [UWPTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_UWPTask/), and [ExternalTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_ExternalTask/).  | | Name  | String  | N  | The "friendly name" of the Task. If not set, it will be assigned by the Factory Orchestrator Service automatically when the FactoryOrchestratorXML is loaded, based on the Task type and other attributes.  | | Guid  | String  | N  | The GUID used to identify the Task. If not set, it will be assigned by the Factory Orchestrator Service automatically when the FactoryOrchestratorXML is loaded.  | | Path  | String  | Depends | See the [Path table below](#path-definitions) to see which Tasks require you to include a Path element. | | | Arguments  | String  | N  | For Executable, PowerShell, BatchFile, and TAEF Tasks: this is the list of arguments to provide to the executable you specified in the "Path".

For UWP Tasks: this can be used to provide details about the Task to the client. It is NOT passed to the UWP app.

For External Tasks: this can be used to provide details about the Task to the client.  | | Timeout  | Int  | N  | In seconds, the amount of time to wait for the Task to be completed. Defaults to "-1" (infinite).

 If "-1", the Task will never timeout.

If the timeout is reached, the Task status is set to "Timeout", a failed state. The Task's executable is also forcibly terminated (if it has one).  | | MaxNumberOfRetries  | Int  | N  | The number of times the Task should automatically be re-run if it completes in a failed state (Aborted/Failed/Timeout). Defaults to "0" (do not retry).

For example, if this is set to "2", the Task could be run up to 3 times automatically.    | -| AbortTaskListOnFailed  | Bool  | N  | If "true", if the Task is run during a TaskList and the Task fails (Aborted/Failed/Timeout), the TaskList is aborted in its current state. Any other pending or running Tasks will be aborted.

This action takes place after any re-runs specified by [MaxNumberOfRetries](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskBase-MaxNumberOfRetries/).

While allowed, it is not recommended to use this for "RunInParallel" TaskLists, as the execution order of such a TaskList is not guaranteed, and Tasks may be aborted mid-execution.    | -| TerminateOnCompleted | Bool | N | By default, an app is terminated when the [UWPTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-UWPTask/) completes. Set to false to not terminate after a [UWPTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-UWPTask/) completes. TerminateOnCompleted is ignored if AutoPassedIfLaunched=`true` | -| AutoPassedIfLaunched | Bool | N | By default, a [UWPTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-UWPTask/) waits for its [TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/) to be completed by a Factory Orchestrator Client. Setting this to true marks the UWP task completed when the app is launched. | +| AbortTaskListOnFailed  | Bool  | N  | If "true", if the Task is run during a TaskList and the Task fails (Aborted/Failed/Timeout), the TaskList is aborted in its current state. Any other pending or running Tasks will be aborted.

This action takes place after any re-runs specified by [MaxNumberOfRetries](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskBase-MaxNumberOfRetries/).

While allowed, it is not recommended to use this for "RunInParallel" TaskLists, as the execution order of such a TaskList is not guaranteed, and Tasks may be aborted mid-execution.    | +| TerminateOnCompleted | Bool | N | By default, an app is terminated when the [UWPTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_UWPTask/) completes. Set to false to not terminate after a [UWPTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_UWPTask/) completes. TerminateOnCompleted is ignored if AutoPassedIfLaunched=`true` | +| AutoPassedIfLaunched | Bool | N | By default, a [UWPTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_UWPTask/) waits for its [TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/) to be completed by a Factory Orchestrator Client. Setting this to true marks the UWP task completed when the app is launched. | #### Path definitions @@ -216,9 +216,9 @@ The `TerminateBackgroundTasksOnCompletion` attribute on the owning TaskList dete Background Tasks are defined the exactly the same as a normal Task with the following exceptions: - Any Executable, PowerShell, or Batch File Task can be made a Background Task. -- Background Tasks cannot have Timeout or [MaxNumberOfRetries](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskBase-MaxNumberOfRetries/) set +- Background Tasks cannot have Timeout or [MaxNumberOfRetries](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskBase-MaxNumberOfRetries/) set -#### Sample [BackgroundTasks](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList-BackgroundTasks/) element +#### Sample [BackgroundTasks](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList-BackgroundTasks/) element ```xml @@ -226,7 +226,7 @@ Background Tasks are defined the exactly the same as a normal Task with the foll ``` -## Validate Factory Orchestrator XML +### Validate Factory Orchestrator XML You can validate FactoryOrchestratorXML using the Factory Orchestrator app on a Windows PC, even without having to connect to a Factory Orchestrator service. @@ -238,9 +238,9 @@ You can validate FactoryOrchestratorXML using the Factory Orchestrator app on a - If the FactoryOrchestratorXML is valid you will see a success message saying that "FactoryOrchestratorXML was successfully validated." - If the FactoryOrchestratorXML is invalid, you'll see a message that says "FactoryOrchestratorXML failed validation", with a description of why it failed validation. -## Sample Factory Orchestrator XML file +### Sample Factory Orchestrator XML file -The following sample FactoryOrchestratorXML file shows two TaskLists containing various types of tests, as well as a [BackgroundTask](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun-BackgroundTask/) that is part of the first TaskList. +The following sample FactoryOrchestratorXML file shows two TaskLists containing various types of tests, as well as a [BackgroundTask](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun-BackgroundTask/) that is part of the first TaskList. ```xml @@ -286,4 +286,4 @@ See [Service Configuration](service-configuration.md#configure-factory-orchestra ## Factory Orchestrator Task log files -The Task log files contain details about the execution of a specific of the Factory Orchestrator Task. There is one log file generated for each run of a Task ([TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/)). The files are saved to `%ProgramData%\FactoryOrchestrator\Logs\` on a Windows and `/var/log/FactoryOrchestrator/logs` on Linux, but this location can be changed using the [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/).[SetLogFolder](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-SetLogFolder%28string_bool%29/)() API. Use the [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/).[GetLogFolder](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-GetLogFolder%28%29/)() API to programmatically retrieve the active log folder. +The Task log files contain details about the execution of a specific of the Factory Orchestrator Task. There is one log file generated for each run of a Task ([TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/)). The files are saved to `%ProgramData%\FactoryOrchestrator\Logs\` on a Windows and `/var/log/FactoryOrchestrator/logs` on Linux, but this location can be changed using the [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_FactoryOrchestratorClient%28System_Net_IPAddress_int%29/).[SetLogFolder](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_SetLogFolder%28string_bool%29/)() API. Use the [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_FactoryOrchestratorClient%28System_Net_IPAddress_int%29/).[GetLogFolder](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_GetLogFolder%28%29/)() API to programmatically retrieve the active log folder. diff --git a/docs/docs/use-the-factory-orchestrator-api.md b/docs/docs/use-the-factory-orchestrator-api.md index cba271094..4e1934f67 100644 --- a/docs/docs/use-the-factory-orchestrator-api.md +++ b/docs/docs/use-the-factory-orchestrator-api.md @@ -2,18 +2,18 @@ # Factory Orchestrator Client API Overview -The Factory Orchestrator service, Microsoft.FactoryOrchestrator.Service.exe, provides a [robust API surface](../ClientLibrary/Microsoft-FactoryOrchestrator-Client) for clients to interact with test devices via C# .NET, C# UWP, or PowerShell code. You can use these APIs to author advanced task orchestration code to programmatically interact with the service outside of what the app provides. Like the app, you can connect to a service running either on the same device or a service running on a remote device available over the network. +The Factory Orchestrator service, Microsoft.FactoryOrchestrator.Service.exe, provides a robust API surface via the [FactoryOrchestratorClient class](../ClientLibrary/Microsoft_FactoryOrchestrator_Client) for clients to interact with test devices via C# .NET, C# UWP, or PowerShell code. You can use these APIs to author advanced task orchestration code to programmatically interact with the service outside of what the app provides. Like the app, you can connect to a service running either on the same device or a service running on a remote device available over the network. -All [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) and FactoryOrchestratorUWPClient C# (.NET and UWP) API calls are [asynchronous](https://docs.microsoft.com/dotnet/csharp/async). +All [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) and FactoryOrchestratorUWPClient C# (.NET and UWP) API calls are [asynchronous](https://docs.microsoft.com/dotnet/csharp/async). -You can see [the full API reference for the Microsoft.FactoryOrchestrator.Client namespace here](../ClientLibrary/Microsoft-FactoryOrchestrator-Client). You can also see [the Microsoft.FactoryOrchestrator.Core namespace reference here](../CoreLibrary/Microsoft-FactoryOrchestrator-Core). The FactoryOrchestrator.Core namespace contains class definitions for objects some client APIs use and/or return, such as [TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/) instances. +You can see [the full API reference for the Microsoft.FactoryOrchestrator.Client namespace here](../ClientLibrary/Microsoft_FactoryOrchestrator_Client). You can also see [the Microsoft.FactoryOrchestrator.Core namespace reference here](../CoreLibrary/Microsoft_FactoryOrchestrator_Core). The FactoryOrchestrator.Core namespace contains class definitions for objects some client APIs use and/or return, such as [TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/) instances. **See [Factory Orchestrator API usage samples](../factory-orchestrator-client-usage-samples) for code snippets that show how to perform various activities using the Factory Orchestrator client APIs.** ## Using the Factory Orchestrator client API in C# .NET The recommended method to use the Factory Orchestrator C# client library in your .NET code is by adding a reference to the [Microsoft.FactoryOrchestrator.Client NuGet package](https://www.nuget.org/packages/Microsoft.FactoryOrchestrator.Client/) in your .NET project. -Before executing other APIs, the[Connect](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-Connect%28bool%29/)() or [TryConnect](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-TryConnect%28bool%29/)() API must be called. Once the[Connect](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-Connect%28bool%29/)() or [TryConnect](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-TryConnect%28bool%29/)() API succeeds, you can use all other APIs. All calls are asynchronous. +Before executing other APIs, the [Connect](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_Connect%28bool%29/)() or [TryConnect](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_TryConnect%28bool%29/)() API must be called. Once the [Connect](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_Connect%28bool%29/)() or [TryConnect](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_TryConnect%28bool%29/)() API succeeds, you can use all other APIs. All calls are asynchronous. ```csharp // Create client instance targeting service at desired IP Address @@ -26,12 +26,12 @@ await client.Connect(); await client.RunExecutable(@"%windir%\system32\ping.exe"); ``` -## Using [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) in PowerShell -The [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) PowerShell module is available on [PowerShell Gallery as Microsoft.FactoryOrchestrator.Client](https://www.powershellgallery.com/packages/Microsoft.FactoryOrchestrator.Client/). Currently, the module is only supported on PowerShell 6+. +## Using [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) in PowerShell +The [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) PowerShell module is available on [PowerShell Gallery as Microsoft.FactoryOrchestrator.Client](https://www.powershellgallery.com/packages/Microsoft.FactoryOrchestrator.Client/). Currently, the module is only supported on PowerShell 6+. -To use the PowerShell module, install Microsoft.FactoryOrchestrator.Client and then use the New-FactoryOrchestratorClient cmdlet to create a [FactoryOrchestratorClient](.\ClientLibrary\Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient.md) instance. The PowerShell [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) instance returned by New-FactoryOrchestratorClient has the exact same methods as the C# [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) class. **However, unlike [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) and FactoryOrchestratorUWPClient C# classes, all calls are synchronous.** You can also discover devices running Factory Orchestrator with the [Get-FactoryOrchestratorClient cmdlet](factory-orchestrator-client-usage-samples.md#find-devices-running-factory-orchestrator). +To use the PowerShell module, install Microsoft.FactoryOrchestrator.Client and then use the New-FactoryOrchestratorClient cmdlet to create a [FactoryOrchestratorClient](.\ClientLibrary\Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient.md) instance. The PowerShell [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) instance returned by New-FactoryOrchestratorClient has the exact same methods as the C# [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) class. **However, unlike [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) and FactoryOrchestratorUWPClient C# classes, all calls are synchronous.** You can also discover devices running Factory Orchestrator with the [Get-FactoryOrchestratorClient cmdlet](factory-orchestrator-client-usage-samples.md#find-devices-running-factory-orchestrator). -Other supported cmdlets are: New-FactoryOrchestratorTask, New-FactoryOrchestratorTaskList, and New-FactoryOrchestratorServerPoller. They return new [Task](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskBase), [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList), and [ServerPoller](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-ServerPoller) objects respectively. +Other supported cmdlets are: New-FactoryOrchestratorTask, New-FactoryOrchestratorTaskList, and New-FactoryOrchestratorServerPoller. They return new [Task](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskBase), [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList), and [ServerPoller](../ClientLibrary/Microsoft_FactoryOrchestrator_Client-ServerPoller) objects respectively. Below is a sample PowerShell script showing how you can use these cmdlets: ```powershell @@ -52,12 +52,12 @@ $client.RunExecutable("$env:windir\system32\ping.exe"); ## Using FactoryOrchestratorUWPClient in a UWP The recommended method to use the Factory Orchestrator C# UWP client library in your .NET code is by adding a reference to the [Microsoft.FactoryOrchestrator.UWPClient NuGet package](https://www.nuget.org/packages/Microsoft.FactoryOrchestrator.UWPClient/) in your UWP project. -If you are writing a UWP app that uses the Factory Orchestrator Client API, you must use the FactoryOrchestratorUWPClient class instead of [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/). The FactoryOrchestratorUWPClient APIs are identical to the [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) APIs. Like the [FactoryOrchestratorClient](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-FactoryOrchestratorClient%28System-Net-IPAddress_int%29/) C# class, all FactoryOrchestratorUWPClient API calls are [asynchronous](https://docs.microsoft.com/dotnet/csharp/async). +If you are writing a UWP app that uses the Factory Orchestrator Client API, you must use the FactoryOrchestratorUWPClient class instead of [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/). The FactoryOrchestratorUWPClient APIs are identical to the [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) APIs. Like the [FactoryOrchestratorClient](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient/) C# class, all FactoryOrchestratorUWPClient API calls are [asynchronous](https://docs.microsoft.com/dotnet/csharp/async). The FactoryOrchestratorUWPClient requires the app have the [privateNetworkClientServer capability](https://docs.microsoft.com/en-us/windows/uwp/packaging/app-capability-declarations) declared in its appxmanifest. You also need local loopback enabled if you wish to connect to localhost. You can have the Factory Orchestrator service enable local loopback for you on service start with the [AllowedLocalLoopbackApps setting](service-configuration.md). ## Factory Orchestrator Versioning -Factory Orchestator uses [semver](https://semver.org/) versioning. If there is a major version mismatch between the client and service your program may not work as expected and either the client program or target service should be updated so the major versions match. Major versions are checked when the client connects to the service via the[Connect](../ClientLibrary/Microsoft-FactoryOrchestrator-Client-FactoryOrchestratorClient-Connect%28bool%29/)() API. You can also manually check the version of the client API by: +Factory Orchestator uses [semver](https://semver.org/) versioning. If there is a major version mismatch between the client and service your program may not work as expected and either the client program or target service should be updated so the major versions match. Major versions are checked when the client connects to the service via the[Connect](../ClientLibrary/Microsoft_FactoryOrchestrator_Client_FactoryOrchestratorClient_Connect%28bool%29/)() API. You can also manually check the version of the client API by: - Manually inspecting the properties of the Microsoft.FactoryOrchestrator.Client.dll file used by your program diff --git a/docs/docs/use-the-factory-orchestrator-app.md b/docs/docs/use-the-factory-orchestrator-app.md index 472e64748..9cba4a983 100644 --- a/docs/docs/use-the-factory-orchestrator-app.md +++ b/docs/docs/use-the-factory-orchestrator-app.md @@ -8,6 +8,10 @@ The app is a Windows-only app and it depends on the service to run. However, it ![Connect page of app](./images/connectpage.png) +You can use the "Advanced Options" button on the connect page to select a [client certificate](../service-configuration/#client-authentication) (if required by the service) or configure a manual connection. + +![Connect page advanced options](./images/connectpage-advancedoptions.png) + ## Run a TaskList When you first connect to a device with the Factory Orchestrator app, you're presented with the 'Run TaskLists' tab. If you're opening the app for the first time, the app likely won't show any TaskLists. Once you create a TaskList, it will show up on this screen. @@ -35,7 +39,7 @@ A 'Re-run' button will also appear next to a Task if the TaskList is done execut ![Results of an aborted running TaskList](./images/re-run-task.png) -If you click on a Task, the results page will load and show you the status of the latest "run" ([TaskRun](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskRun/)) of that Task, including the any output of the Task. The results page also allows you to see the log file path for that run. You can also use the buttons at the top of the page to view older or newer runs of the Task, provided it has been run multiple times. +If you click on a Task, the results page will load and show you the status of the latest "run" ([TaskRun](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskRun/)) of that Task, including the any output of the Task. The results page also allows you to see the log file path for that run. You can also use the buttons at the top of the page to view older or newer runs of the Task, provided it has been run multiple times. ![Clicking on a Task that has run](./images/test-results.png) @@ -57,7 +61,7 @@ The 'Manage TaskLists' tab in the Factory Orchestrator app allows you to create, - **Choose individual files to add to a TaskList** - Use `Create new TaskList` to create a new [TaskList](../CoreLibrary/Microsoft-FactoryOrchestrator-Core-TaskList/) where you can individual tasks one-at-a-time to your TaskList. When you add tasks this way, you choose the type of task that you're adding and can configure arguments, timeout settings, etc as you add tasks. + Use `Create new TaskList` to create a new [TaskList](../CoreLibrary/Microsoft_FactoryOrchestrator_Core_TaskList/) where you can individual tasks one-at-a-time to your TaskList. When you add tasks this way, you choose the type of task that you're adding and can configure arguments, timeout settings, etc as you add tasks. ![Create new TaskList button](./images/create-new-tasklist.png) diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 812728858..e1b60b299 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -23,10 +23,11 @@ nav: - Tasks & TaskLists : 'tasks-and-tasklists.md' - Service configuration : 'service-configuration.md' - Using the application: 'use-the-factory-orchestrator-app.md' - - Using PowerShell or C# code: 'use-the-factory-orchestrator-api.md' + - Writing PowerShell or C# code: + - Factory Orchestrator API overview: 'use-the-factory-orchestrator-api.md' + - PowerShell and C# code samples: 'factory-orchestrator-client-usage-samples.md' + - Client Library Class Reference: 'ClientLibrary\Microsoft_FactoryOrchestrator_Client.md' + - Core Library Class Reference: 'CoreLibrary\Microsoft_FactoryOrchestrator_Core.md' - Find Factory Orchestrator devices: 'find-factory-orchestrator-devices.md' - - Client API samples: 'factory-orchestrator-client-usage-samples.md' - - Client Library Class Reference: 'ClientLibrary\Microsoft-FactoryOrchestrator-Client.md' - - Core Library Class Reference: 'CoreLibrary\Microsoft-FactoryOrchestrator-Core.md' - Uninstall Factory Orchestrator: 'uninstall-factory-orchestrator.md' diff --git a/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClient.cs b/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClient.cs index 5dcdd038c..6ba4830d0 100644 --- a/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClient.cs +++ b/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClient.cs @@ -2,6 +2,7 @@ using System.IO; using System.Net.Security; using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; @@ -11,6 +12,7 @@ internal class TcpIpcClient : IpcClient where TInterface : class { private readonly TcpIpcClientOptions _options; + private readonly X509CertificateCollection _clientCertificateCollection = new X509CertificateCollection(); public TcpIpcClient(string name, TcpIpcClientOptions options) : base(name, options) @@ -51,7 +53,13 @@ protected override Task ConnectToServerAsync(CancellationToken // set client mode and specify the common name(CN) of the server if (_options.SslServerIdentity != null) { - ssl.AuthenticateAsClient(_options.SslServerIdentity); + if (_options.ClientCertificate != null && _clientCertificateCollection.Count != 1) + { + _clientCertificateCollection.Clear(); + _clientCertificateCollection.Add(_options.ClientCertificate); + } + + ssl.AuthenticateAsClient(_options.SslServerIdentity, _clientCertificateCollection, System.Security.Authentication.SslProtocols.None, _options.CheckSslCertificateRevocation); } stream = ssl; } diff --git a/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClientOptions.cs b/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClientOptions.cs index 30114d515..b81a8a66e 100644 --- a/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClientOptions.cs +++ b/oss/IpcFramework/JKang.IpcServiceFramework.Client.Tcp/TcpIpcClientOptions.cs @@ -1,5 +1,6 @@ using System.Net; using System.Net.Security; +using System.Security.Cryptography.X509Certificates; namespace JKang.IpcServiceFramework.Client.Tcp { @@ -10,5 +11,7 @@ public class TcpIpcClientOptions : IpcClientOptions public bool EnableSsl { get; set; } public string SslServerIdentity { get; set; } public RemoteCertificateValidationCallback SslValidationCallback { get; set; } + public X509Certificate ClientCertificate { get; set; } + public bool CheckSslCertificateRevocation { get; set; } = false; } } diff --git a/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpoint.cs b/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpoint.cs index 9a3419757..bae52d193 100644 --- a/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpoint.cs +++ b/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpoint.cs @@ -41,7 +41,10 @@ protected override async Task WaitAndProcessAsync( { Stream server = client.GetStream(); - string ipString = ((IPEndPoint)client.Client?.RemoteEndPoint)?.Address?.ToString() == null ? "UNKNOWN" : ((IPEndPoint)client.Client.RemoteEndPoint)?.Address?.ToString(); + IPAddress remoteIp = ((IPEndPoint)client.Client?.RemoteEndPoint)?.Address; + string remoteIpString = remoteIp == null ? "UNKNOWN" : remoteIp.ToString(); + + bool isLocalLoopback = IPAddress.IsLoopback(remoteIp); if (_options.StreamTranslator != null) { @@ -51,20 +54,33 @@ protected override async Task WaitAndProcessAsync( // if SSL is enabled, wrap the stream in an SslStream in client mode if (_options.EnableSsl) { - using (var ssl = new SslStream(server, false)) + using (var ssl = new SslStream(server, false, _options.AlwaysAllowLocalhostSslClients && isLocalLoopback ? null : _options.RemoteSslCertificateValidationCallback)) { + bool requireClientCert; + if (isLocalLoopback) + { + requireClientCert = (!_options.AlwaysAllowLocalhostSslClients) && (_options.RemoteSslCertificateValidationCallback != null); + } + else + { + requireClientCert = _options.RemoteSslCertificateValidationCallback != null; + } + ssl.AuthenticateAsServer(_options.SslCertificate - ?? throw new IpcHostingConfigurationException("Invalid TCP IPC endpoint configured: SSL enabled without providing certificate.")); - await process(ssl, ipString, cancellationToken).ConfigureAwait(false); + ?? throw new IpcHostingConfigurationException("Invalid TCP IPC endpoint configured: SSL enabled without providing certificate."), requireClientCert, System.Security.Authentication.SslProtocols.None, _options.CheckSslCertificateRevocation); + + await process(ssl, remoteIpString, cancellationToken).ConfigureAwait(false); } } else { - await process(server, ipString, cancellationToken).ConfigureAwait(false); + await process(server, remoteIpString, cancellationToken).ConfigureAwait(false); } client.Close(); } } - } + } + + } diff --git a/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpointOptions.cs b/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpointOptions.cs index 938214bbb..465df94c2 100644 --- a/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpointOptions.cs +++ b/oss/IpcFramework/JKang.IpcServiceFramework.Hosting.Tcp/TcpIpcEndpointOptions.cs @@ -1,4 +1,6 @@ -using System.Net; +using System.Collections.Generic; +using System.Net; +using System.Net.Security; using System.Security.Cryptography.X509Certificates; namespace JKang.IpcServiceFramework.Hosting.Tcp @@ -9,5 +11,8 @@ public class TcpIpcEndpointOptions : IpcEndpointOptions public int Port { get; set; } public bool EnableSsl { get; set; } public X509Certificate SslCertificate { get; set; } + public RemoteCertificateValidationCallback RemoteSslCertificateValidationCallback { get; set; } = null; + public bool CheckSslCertificateRevocation { get; set; } = false; + public bool AlwaysAllowLocalhostSslClients { get; set; } = true; } } diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index 199e08876..9c4ab40af 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -117,7 +117,7 @@ protected override async void OnActivated(IActivatedEventArgs args) { if (rootFrame.Content == null) { - Client = new FactoryOrchestratorUWPClient(IPAddress.Loopback, 45684); + Client = new FactoryOrchestratorUWPClient(IPAddress.Loopback, Constants.DefaultServerPort); Client.OnConnected += OnIpcConnected; if (await Client.TryConnect(IgnoreVersionMismatch)) @@ -355,7 +355,7 @@ protected override async void OnLaunched(LaunchActivatedEventArgs e) { if (rootFrame.Content == null) { - Client = new FactoryOrchestratorUWPClient(IPAddress.Loopback, 45684); + Client = new FactoryOrchestratorUWPClient(IPAddress.Loopback, Constants.DefaultServerPort); Client.OnConnected += OnIpcConnected; if (await Client.TryConnect(IgnoreVersionMismatch)) diff --git a/src/App/ConnectionPage.xaml b/src/App/ConnectionPage.xaml index c4d88232a..65f51079a 100644 --- a/src/App/ConnectionPage.xaml +++ b/src/App/ConnectionPage.xaml @@ -107,22 +107,36 @@ + + + - - - - - - - - -