ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

扩展 Windows PowerShell Workflow 活动控制器:ActivityControllerExtensibility 样例源码级解析

扩展 Windows PowerShell Workflow 活动控制器:ActivityControllerExtensibility 样例源码级解析 示例工程【免费下载链接】Windows-classic-samplesThis repo contains samples that demonstrate the API used in Windows classic desktop applications.项目地址https://gitcode.com/gh_mirrors/wi/Windows-classic-samples点击查看免费下载本篇文章基于 Windows-classic-samples 仓库中的 ActivityControllerExtensibility 样例系统讲解如何通过自定义PSActivityHostController扩展 Windows PowerShell Workflow 的活动控制器Activity Controller。该样例以 RunspacePool 队列化queuing的方式将工作流中的 PowerShell 活动调度到本地 WinRM 自定义工作流端点执行并完整附带端点搭建脚本。阅读本文后你将掌握活动控制器的扩展点CreatePSActivityHostController、StartResumablePSCommand、ResumeBookmark等、自定义工作流端点的注册方法以及该机制在真实代码中的完整调用链。样例概览它要解决什么问题Windows PowerShell WorkflowWindows 8.1 / Windows Server 2012 R2 引入允许把 PowerShell 命令包装为工作流中的活动Activity。默认情况下活动可以进程内直接执行但对于某些活动宿主希望把执行调度出去——例如放到另一台机器、放到某个专用的 WinRM 端点或自行控制并发排队策略。此时就需要扩展活动控制器。本样例源码位于 Samples/PowerShellWorkflow/ActivityControllerExtensibility/cs演示了两件事如何扩展 Windows PowerShell Workflow 的活动控制器通过继承PSResumableActivityHostController提供自定义执行逻辑并把活动命令放入ConcurrentDictionary队列由线程池线程在自定义 WinRM 工作流端点上执行如何创建自定义工作流端点通过随附的CustomWorkflowEndpointSetup.ps1脚本用Register-PSSessionConfiguration -SessionType Workflow注册一个本地 WinRM 工作流端点。整体架构与执行链路从源码结构看整个样例由 5 个文件构成一个闭环文件作用SampleConfigurationProvider.cs配置宿主运行时注入自定义活动控制器并声明进程外活动清单SampleActivityController.cs核心扩展实现队列化请求、在线程池执行命令、恢复 BookmarkProgram.cs宿主程序加载 XAML 工作流、创建PSWorkflowJob、订阅状态事件并等待完成SampleWorkflow.xamlXAML 工作流定义含一个GetCommand活动CustomWorkflowEndpointSetup.ps1注册自定义 WinRM 工作流端点的 PowerShell 脚本执行链路可以概括为Program.cs 加载 XAML └─ new PSWorkflowRuntime(new SampleConfigurationProvider()) └─ CreatePSActivityHostController() 返回 SampleActivityController └─ JobManager.CreateJob(...) 创建 PSWorkflowJob 并 StartJob └─ 工作流运行到 GetCommand 活动 └─ StartResumablePSCommand() 将命令入队 └─ ThreadPool 线程 ServiceRequests → PerformWork └─ 在自定义端点 RunspacePool 上 Invoke └─ job.ResumeBookmark(...) 恢复工作流 └─ Program 收到 Completed/Failed 事件下面依次剖析每一环的源码实现。注入自定义控制器SampleConfigurationProviderSampleConfigurationProvider.cs 继承自Microsoft.PowerShell.Workflow.PSWorkflowConfigurationProvider负责定义整个PSWorkflowRuntime的配置。它重写了两个关键成员public override Microsoft.PowerShell.Activities.PSActivityHostController CreatePSActivityHostController() { return new SampleActivityController(Runtime); }CreatePSActivityHostController()是扩展活动控制器的唯一入口运行时在此处决定使用默认控制器还是自定义控制器返回SampleActivityController实例构造函数接收PSWorkflowRuntime以便后续恢复 Job。public override IEnumerablestring OutOfProcessActivity { get { yield return GetProcess; } }OutOfProcessActivity属性声明了哪些活动属于进程外活动。源码注释明确说明只有进程外活动才会触发活动控制器调用进程内活动不需要活动控制器。这里将GetProcess列入进程外清单——这意味着任何名为GetProcess的活动都会经由自定义控制器调度执行本例中 XAML 工作流实际使用GetCommand活动但其输出流与执行机制同理。若要扩展更多活动只需继续yield return其他活动名称即可。核心扩展实现SampleActivityControllerSampleActivityController.cs 继承PSResumableActivityHostController是整个样例的精华所在。它实现了先入队、后执行、再恢复的异步调度模型。支持断开式流SupportDisconnectedPSStreamspublic override bool SupportDisconnectedPSStreams { get { return true; } }该属性通知工作流运行时关于流的使用方式如果不需要保持 Job 的实时流则应返回true当支持断开式流时活动甚至可以在另一台计算机上执行Job 完成后数据再回传到实时流。请求入队StartResumablePSCommandpublic override void StartResumablePSCommand(Guid jobInstanceId, Bookmark bookmark, PowerShell command, PowerShellStreamsPSObject, PSObject streams, PSActivityEnvironment environment, PSActivity activityInstance)这是活动执行时被回调的入口方法。注释给出了重要的设计约束强烈建议不要在函数内阻塞式执行活动应把全部信息记入队列后立即返回让工作流并行做其他事由独立线程或另一台机器从队列取出数据执行活动活动完成后恢复 Bookmark。实现方式是把调用参数打包成内部类ActivityActionData以jobInstanceId为键放入ConcurrentDictionaryGuid, ActivityActionData ActivityActionsQueue该类使用并发字典注释指出字典嵌套字典可用于处理多个并行 Job随后用ThreadPool.QueueUserWorkItem(ServiceRequests, jobInstanceId)安排一个线程池线程消费ActivityActionData data new ActivityActionData(); data.jobInstanceId jobInstanceId; data.bookmark bookmark; data.command command; data.streams streams; data.environment environment; ActivityActionsQueue.TryAdd(jobInstanceId, data); ThreadPool.QueueUserWorkItem(ServiceRequests, jobInstanceId);队列消费与真实执行ServiceRequests / PerformWork线程池线程执行ServiceRequests从队列中TryRemove出ActivityActionData然后调用PerformWork真正干活private void PerformWork(ActivityActionData data) { // 1) 把 PowerShell 命令的输出流绑定到工作流提供的流 data.command.Streams.Debug data.streams.DebugStream; data.command.Streams.Error data.streams.ErrorStream; data.command.Streams.Progress data.streams.ProgressStream; data.command.Streams.Verbose data.streams.VerboseStream; data.command.Streams.Warning data.streams.WarningStream; // 2) 连接自定义 WinRM 工作流端点 WSManConnectionInfo connectionInfo new WSManConnectionInfo(); connectionInfo.ShellUri http://schemas.microsoft.com/powershell/CustomeWorkflowEndpoint; // 3) 在自定义端点上创建 RunspacePool 并执行 using (RunspacePool r RunspaceFactory.CreateRunspacePool(1, 1, connectionInfo)) { r.Open(); data.command.RunspacePool r; data.command.Invoke(data.streams.InputStream, data.streams.OutputStream, new PSInvocationSettings()); r.Close(); r.Dispose(); } }几个值得注意的细节流绑定Debug/Error/Progress/Verbose/Warning五类流被显式重定向到工作流提供的流对象保证活动输出能回流到 Job 的实时流中。端点寻址ShellUri必须与CustomWorkflowEndpointSetup.ps1注册的端点名完全一致包括其中CustomeWorkflowEndpoint的拼写——这是脚本与代码约定好的端点名不可更改否则连接会失败。RunspacePool 参数CreateRunspacePool(1, 1, connectionInfo)表示最小/最大运行空间数均为 1即单实例串行执行这也是RunspacePool-based queuing的体现——队列在此排队等待唯一可用的运行空间。恢复执行ResumeBookmark活动执行完成后必须恢复工作流否则工作流会一直挂起。PerformWork的收尾逻辑是PSWorkflowJob job _runtime.JobManager.GetJob(data.jobInstanceId); if (failed) job.ResumeBookmark(data.bookmark, this.SupportDisconnectedPSStreams, data.streams, exception); else job.ResumeBookmark(data.bookmark, this.SupportDisconnectedPSStreams, data.streams);由于执行发生在后台线程任何异常都必须被捕获并随ResumeBookmark传入让工作流以失败状态恢复而不是让异常逃逸出线程池。成功路径则把bookmark、SupportDisconnectedPSStreams和streams回传给运行时工作流从 Bookmark 处继续执行。停止命令StopAllResumablePSCommandspublic override void StopAllResumablePSCommands(Guid jobInstanceId) { this.StopExecution(jobInstanceId); }该方法是 Job 停止时清理执行中命令的扩展点。样例中的StopExecution仅为骨架注释说明可通过持有ActivityActionData引用并调用 command 对象的Stop()来实现实际产品化时可在此补充强制终止逻辑。宿主程序Program.cs 的运行编排Program.cs 演示了宿主如何使用自定义配置运行工作流 Job流程如下// 1) 读取 XAML 工作流定义 string xaml File.ReadAllText(SampleWorkflow.xaml); // 2) 以自定义配置提供器创建运行时 PSWorkflowRuntime runtime new PSWorkflowRuntime(new SampleConfigurationProvider()); // 3) 创建 Job工作流参数可放入字典 Dictionarystring, object parameters new Dictionarystring, object(); PSWorkflowJob job runtime.JobManager.CreateJob( Guid.NewGuid(), xaml, Get-CurrentProcess, SampleWorkflow, parameters); // 4) 启动前订阅状态事件 AutoResetEvent wfEvent new AutoResetEvent(false); job.StateChanged delegate(object sender, JobStateEventArgs e) { switch (e.JobStateInfo.State) { case JobState.Failed: case JobState.Completed: wfEvent.Set(); break; } }; // 5) 启动并等待 job.StartJob(); wfEvent.WaitOne(); if (job.JobStateInfo.State JobState.Completed) { Console.WriteLine(The job has completed successfully.); Console.WriteLine(Total Commands found: job.PSWorkflowInstance.Streams.OutputStream.Count); } else Console.WriteLine(The job has Failed.);要点说明CreateJob的参数依次为 Job 实例 ID、XAML 定义、Job 名称Get-CurrentProcess、工作流名称SampleWorkflow和参数字典。源码注释指出由于这里使用默认的基于文件的存储file-based store因此必须显式提供 XAML 工作流定义。StateChanged事件只关心Failed与Completed两个终态用AutoResetEvent做同步等待避免主线程忙等。Job 完成后通过job.PSWorkflowInstance.Streams.OutputStream.Count读取输出流中累积的对象数量即工作流输出的命令条目数这就是活动流被正确回传的直接证据。工作流定义SampleWorkflow.xamlSampleWorkflow.xaml 是一个最小的 XAML 工作流Sequence中包含一个来自Microsoft.PowerShell.Core.Activities的GetCommand活动并为其Module参数指定了PSDiagnosticsSequence ... ns3:GetCommand DisplayNameGet-Command ... ns3:GetCommand.Module ns2:InArgument x:TypeArgumentss:String[] mpa:PowerShellValue x:TypeArgumentss:String[] ExpressionPSDiagnostics/ /ns2:InArgument /ns3:GetCommand.Module /ns3:GetCommand /Sequence在项目文件 ActivityControllerExtensibilitySample.csproj 中该 XAML 被声明为XamlAppDef且CopyToOutputDirectoryAlways因此编译后会随 exe 一起出现在输出目录运行时File.ReadAllText(SampleWorkflow.xaml)才能正确加载。搭建自定义工作流端点CustomWorkflowEndpointSetup.ps1这是整个方案的基础设施部分脚本完整内容位于 CustomWorkflowEndpointSetup.ps1只有 5 步却环环相扣# 1) 确保 WinRM 已配置并启动 winrm quickconfig -quiet restart-service winrm # 2) 创建工作流会话选项限制最大并发工作流数为 35 $wfExecuteOption New-PSWorkflowExecutionOption -MaxRunningWorkflows 35 # 3) 注册自定义工作流端点 Register-PSSessionConfiguration -Name CustomeWorkflowEndpoint -SessionType Workflow -SessionTypeOption $wfExecuteOption -Force # 4) 验证端点创建会话并运行一个测试工作流 $wfEP New-PSSession -ConfigurationName CustomeWorkflowEndpoint icm $wfEP {workflow TestWorkflow {get-process}} icm $wfEP {TestWorkflow} Remove-PSSession $wfEP对每一步的说明命令作用与参数说明winrm quickconfig -quiet快速完成 WinRM 服务与监听器配置-quiet表示不交互询问restart-service winrm重启 WinRM 服务使配置生效New-PSWorkflowExecutionOption -MaxRunningWorkflows 35创建工作流会话类型选项-MaxRunningWorkflows控制该端点上最多并发运行的工作流数量样例设为 35可按实际负载调整Register-PSSessionConfiguration -Name CustomeWorkflowEndpoint -SessionType Workflow -SessionTypeOption $wfExecuteOption -Force注册名为CustomeWorkflowEndpoint的会话配置-SessionType Workflow指明这是工作流类型端点非默认的DefaultRemoteShell-Force覆盖可能存在的同名配置。注意端点名拼写代码中WSManConnectionInfo.ShellUri指向http://schemas.microsoft.com/powershell/CustomeWorkflowEndpoint二者必须严格一致New-PSSession -ConfigurationName CustomeWorkflowEndpoint用刚注册的端点创建 PSSession用于连通性验证icm $wfEP {workflow TestWorkflow {get-process}}在会话内定义并运行测试工作流确认端点可以承载工作流执行该脚本必须以管理员权限运行注册会话配置需要提升权限且需在运行样例 exe之前完成否则RunspacePool.Open()将因找不到端点而失败。构建与运行系统要求类别要求客户端Windows 8.1服务器Windows Server 2012 R2运行时.NET Framework 4.0项目TargetFrameworkVersion为 v4.0、PowerShell 3.0 及以上工作流功能自 PowerShell 3.0 引入项目引用了Microsoft.PowerShell.Activities、Microsoft.PowerShell.Core.Activities、Microsoft.PowerShell.Management.Activities、Microsoft.PowerShell.Workflow.ServiceCore和System.Management.Automation版本均为 3.0.0.0等程序集这些组件随 Windows 8.1 / Server 2012 R2 自带无需额外安装。构建步骤启动 Visual Studio选择File Open Project/Solution进入 Samples/PowerShellWorkflow/ActivityControllerExtensibility/cs 目录双击ActivityControllerExtensibilitySample.sln打开解决方案解决方案支持 Debug/Release 两种配置平台为 Any CPU按F7或选择Build Build Solution编译。构建成功后ActivityControllerExtensibilitySample.exe以及随输出的SampleWorkflow.xaml会生成在bin\Debug目录下。运行步骤以管理员身份启动 Windows PowerShell切换到 CustomWorkflowEndpointSetup.ps1 所在目录执行该脚本注册CustomeWorkflowEndpoint自定义工作流端点脚本末尾的测试命令会输出get-process结果可据此确认端点可用切换到样例二进制所在目录bin\Debug执行ActivityControllerExtensibilitySample.exe。程序运行时会加载SampleWorkflow.xaml创建 Job 并启动工作流内的GetCommand活动请求经SampleActivityController排队后调度到自定义端点的 RunspacePool 上执行完成后控制台输出The job has completed successfully. Total Commands found: 数量 Press Enter to continue...Total Commands found即工作流输出流中累积的对象数验证了活动在自定义端点上执行、结果流回宿主的完整闭环。扩展设计的工程要点从本样例的源码注释中可以提炼出扩展活动控制器的几条关键设计原则回调函数绝不阻塞StartResumablePSCommand应只做入队等轻量操作后立即返回让工作流引擎继续并行推进其他活动真实执行放到独立线程或独立机器。队列驱动解耦用并发队列样例为ConcurrentDictionaryGuid, ActivityActionData在活动请求与执行者之间解耦键用jobInstanceId天然支持多 Job 并发注释提示字典嵌套字典可扩展到同 Job 多活动并行。Bookmark 是恢复锚点活动完成后必须调用ResumeBookmark恢复工作流挂起点异常必须随ResumeBookmark上报使 Job 进入失败态而非悬挂。流必须显式接线Debug/Error/Progress/Verbose/Warning流的接线决定活动输出能否回传SupportDisconnectedPSStreams返回true意味着 Job 可断开、活动可异地执行。端点与代码强约定自定义端点名出现在脚本注册命令与WSManConnectionInfo.ShellUri两处任何一处改名都会导致运行失败——这是把执行调度到 WinRM 端点时必须牢记的一致性约束。小结ActivityControllerExtensibility 样例用约 200 行 C# 代码完整展示了 Windows PowerShell Workflow 活动控制器扩展的完整范式配置提供器注入自定义控制器、OutOfProcessActivity声明进程外活动、控制器内入队 → 线程池执行 → ResumeBookmark 恢复的三段式调度以及用Register-PSSessionConfiguration -SessionType Workflow搭建自定义工作流端点。这套机制是实现工作流活动异地执行、并发限流与自定义调度策略的参考蓝本适合需要深度定制 PowerShell 工作流执行引擎的开发者研读。若需了解仓库内更多工作流相关样例可继续查阅 Samples/PowerShellWorkflow 目录下的其他子项目。赞分享示例工程【免费下载链接】Windows-classic-samplesThis repo contains samples that demonstrate the API used in Windows classic desktop applications.项目地址https://gitcode.com/gh_mirrors/wi/Windows-classic-samples点击查看免费下载相关推荐使用 Windows PowerShell Activity Generation API 生成 Workflow 活动源码并编译为 DLLActivityGenerator 示例深度解析使用 Windows PowerShell Activity Generation API 生成 Workflow 活动源码并编译为 DLLActivityG示例工程Windows-classic-samples 实战用 PowerShell Workflow 自定义活动Activity接收脚本块参数——ContainerActivity 示例深度解析Windows classic samples 实战用 PowerShell Workflow 自定义活动Activity接收脚本块参数——Contain示例工程Windows PowerShell Debugger API 实战基于 Windows-classic-samples 构建 Workflow 调试器示例Windows PowerShell Debugger API 实战基于 Windows classic samples 构建 Workflow 调试器示例示例工程上一篇python-sdk 服务端资源Resources实战指南从 URI 到模板与多类型返回下一篇Atlas OS中Xbox Game Pass登录问题的深度解析与解决方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表