适用于 PowerShell 5.1 及以上版本(Windows),PowerShell 7 需安装 PSDesiredStateConfiguration 模块
在运维领域,”配置漂移”是一个永恒的痛点——服务器的实际状态随时间推移逐渐偏离预期配置,导致难以排查的故障和安全隐患。微软的 Desired State Configuration(DSC)正是为解决这个问题而设计的声明式配置管理框架。与 Ansible、Chef、Puppet 类似,DSC 让你用代码定义服务器”应该是什么样”,然后由系统自动确保配置一致。
本文将介绍 DSC 的核心概念、如何编写配置脚本、推拉两种工作模式,以及在 PowerShell 7 中使用 DSC 的注意事项。
DSC 核心概念 DSC 的核心思想是声明式配置——你只需描述期望的最终状态,而不必关心如何达到该状态。DSC 由三个核心组件构成:
配置(Configuration) :定义期望状态的 PowerShell 脚本,类似于 Ansible 的 Playbook
资源(Resource) :实现具体配置逻辑的模块,如管理文件、服务、注册表等
本地配置管理器(LCM) :运行在目标节点上的引擎,负责应用和维持配置
内置资源包括:File、Service、Registry、User、Group、WindowsFeature、Package、Environment、Script 等。
1 2 3 4 5 Get-DscResource | Select-Object Name, Module, Properties | Format-Table -AutoSize Get-DscResource -Name File | Select-Object -ExpandProperty Properties
执行结果示例:
1 2 3 4 5 6 Name Module Properties ---- ------ ---------- File PSDesiredStateC... {DestinationPath, Attributes, Checksum... Service PSDesiredStateC... {Name, BuiltInAccount, Credential, Dep... Registry PSDesiredStateC... {Key, ValueName, Force, Hex... WindowsFeature PSDesiredStateC... {Name, Credential, DependsOn, Ensure...
编写第一个 DSC 配置 DSC 配置使用特殊的 PowerShell 语法,看起来像函数,但实际生成的是 MOF(Managed Object Format)文件。下面是一个配置 Web 服务器的完整示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 configuration WebServerSetup { param ( [string []]$NodeName = 'localhost' , [string ]$WebsitePath = 'C:\inetpub\MyApp' ) Import-DscResource -ModuleName PSDesiredStateConfiguration Node $NodeName { WindowsFeature IIS { Ensure = 'Present' Name = 'Web-Server' } File AppDirectory { Ensure = 'Present' Type = 'Directory' DestinationPath = $WebsitePath DependsOn = '[WindowsFeature]IIS' } File DefaultPage { Ensure = 'Present' Type = 'File' DestinationPath = "$WebsitePath \index.html" Contents = @' <!DOCTYPE html> <html> <head><title>My App</title></head> <body><h1>Hello from DSC!</h1></body> </html> '@ DependsOn = '[File]AppDirectory' } Service W3SVC { Ensure = 'Present' Name = 'W3SVC' State = 'Running' DependsOn = '[WindowsFeature]IIS' } } } WebServerSetup -OutputPath "C:\DSC\WebServerConfig" Get-ChildItem "C:\DSC\WebServerConfig" -Filter *.mof
执行结果示例:
1 2 3 4 5 ---- ------------- ------ ---- - ---- .
注意 :MOF 文件包含配置的完整定义,不能手动编辑。每次修改配置后需要重新编译。
应用配置(推送模式) DSC 支持两种模式:推送(Push)和拉取(Pull)。推送模式下,管理员手动将配置应用到目标节点:
1 2 3 4 5 6 7 8 Start-DscConfiguration -Path "C:\DSC\WebServerConfig" -Wait -Verbose -Force Start-DscConfiguration -Path "C:\DSC\WebServerConfig" -ComputerName SERVER01, SERVER02 -Wait -Verbose Test-DscConfiguration
执行结果示例:
1 2 3 4 5 6 7 8 9 LCM starting to apply configuration ... [VERBOSE] Performing operation "Set" on Target "IIS" [VERBOSE] Performing operation "Set" on Target "AppDirectory" [VERBOSE] Performing operation "Set" on Target "W3SVC" Configuration was applied successfully.PSComputerName ResourcesInDesiredState ResourcesNotInDesiredState InDesiredState localhost 4 0 True
查看和监控配置状态 应用配置后,可以随时检查节点的当前状态是否与期望配置一致:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 Get-DscConfigurationStatus | Select-Object StartDate, Type , Mode, RebootRequested, StatusGet-DscConfiguration Get-DscConfiguration | Where-Object { $_ .ResourceId } | ForEach-Object { $resource = $_ $desired = Get-DscConfiguration | Where-Object { $_ .ConfigurationName -eq $resource .ConfigurationName } [PSCustomObject ]@ { Resource = $resource .ResourceId InDesired = $null -ne $desired } }
执行结果示例:
1 2 3 4 5 6 7 8 9 10 StartDate Type Mode RebootRequested Status 5 /2 /2025 10 :00 :15 AM Consistency Push False SuccessConfigurationName ResourceId InDesired WebServerSetup [WindowsFeature] True WebServerSetup [File ]AppDir True WebServerSetup [File ]DefaultPage True WebServerSetup [Service] True
使用参数化配置管理多环境 在实际运维中,开发、测试、生产环境的配置通常不同。通过参数化 DSC 配置,可以复用同一份配置脚本:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 configuration AppDeployment { param ( [Parameter (Mandatory )] [hashtable []]$Nodes , [Parameter (Mandatory )] [string ]$AppVersion , [string ]$SourcePath = "\\fileserver\releases\$AppVersion " ) Import-DscResource -ModuleName PSDesiredStateConfiguration Node $Nodes { $nodeData = $Nodes | Where-Object { $_ .NodeName -eq $NodeName } File AppFiles { Ensure = 'Present' Type = 'Directory' DestinationPath = $nodeData .AppPath SourcePath = $SourcePath Recurse = $true Checksum = 'SHA256' Force = $true } Registry AppVersion { Ensure = 'Present' Key = 'HKLM:\SOFTWARE\MyApp' ValueName = 'Version' ValueData = $AppVersion ValueType = 'String' DependsOn = '[File]AppFiles' } Service AppService { Ensure = 'Present' Name = $nodeData .ServiceName State = 'Running' DependsOn = '[File]AppFiles' } } } $configData = @ ( @ { NodeName = 'DEV-WEB01' ; AppPath = 'C:\Apps\MyApp' ; ServiceName = 'MyAppDev' } @ { NodeName = 'PROD-WEB01' ; AppPath = 'D:\Apps\MyApp' ; ServiceName = 'MyAppProd' } @ { NodeName = 'PROD-WEB02' ; AppPath = 'D:\Apps\MyApp' ; ServiceName = 'MyAppProd' } ) AppDeployment -Nodes $configData -AppVersion "2.5.0" -OutputPath "C:\DSC\ProdDeploy"
执行结果示例:
1 2 3 4 5 6 7 ---- ------------- ------ ---- - ---- - . - ---- - . - ---- - .
使用 Script 资源处理复杂逻辑 当内置资源无法满足需求时,可以使用 Script 资源编写自定义逻辑。Script 资源需要提供 GetScript、TestScript 和 SetScript 三个脚本块:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 configuration CustomAppSetup { Import-DscResource -ModuleName PSDesiredStateConfiguration Node localhost { Script DownloadAppPackage { GetScript = { @ { Result = (Test-Path 'C:\Downloads\app-v2.5.0.zip' ) } } TestScript = { if (Test-Path 'C:\Downloads\app-v2.5.0.zip' ) { $hash = (Get-FileHash 'C:\Downloads\app-v2.5.0.zip' -Algorithm SHA256).Hash if ($hash -eq 'ABC123DEF456...' ) { Write-Verbose "文件已存在且校验通过" return $true } } Write-Verbose "需要下载应用包" return $false } SetScript = { $url = 'https://releases.example.com/app/v2.5.0/app.zip' $out = 'C:\Downloads\app-v2.5.0.zip' Invoke-WebRequest -Uri $url -OutFile $out Write-Verbose "下载完成:$out " } } Script ExtractAndInstall { DependsOn = '[Script]DownloadAppPackage' GetScript = { @ { Result = (Test-Path 'C:\Apps\MyApp\app.exe' ) } } TestScript = { (Test-Path 'C:\Apps\MyApp\app.exe' ) } SetScript = { Expand-Archive -Path 'C:\Downloads\app-v2.5.0.zip' -DestinationPath 'C:\Apps\MyApp' -Force Write-Verbose "解压安装完成" } } } } CustomAppSetup -OutputPath "C:\DSC\CustomSetup" Start-DscConfiguration -Path "C:\DSC\CustomSetup" -Wait -Verbose
执行结果示例:
1 2 3 4 VERBOSE : 需要下载应用包VERBOSE : 下载完成:C:\Downloads\app-v2.5 .0 .zipVERBOSE : 解压安装完成Configuration was applied successfully.
PowerShell 7 中的 DSC PowerShell 7 默认不包含 DSC 命令,需要手动安装。微软推荐使用新的 PSDesiredStateConfiguration 模块(v2.x):
1 2 3 4 5 6 7 8 9 Install-Module -Name PSDesiredStateConfiguration -Force -AllowClobber Get-Command -Module PSDesiredStateConfigurationGet-Module PSDesiredStateConfiguration -ListAvailable | Select-Object Name, Version
执行结果示例:
1 2 3 4 5 6 7 8 9 10 Name Version PSDesiredStateConfiguration 2.0 .7 CommandType Name Version Source Function Configuration 2.0 .7 PSDesiredStateConfigurationFunction Get -DscConfiguration 2.0 .7 PSDesiredStateConfigurationFunction Start -DscConfiguration 2.0 .7 PSDesiredStateConfigurationCmdlet Test-DscConfiguration 2.0 .7 PSDesiredStateConfiguration
注意 :DSC v3 已作为独立项目发布,采用全新的架构,不再依赖 MOF 文件,而是使用 JSON 配置文档。但目前 v2 仍是生产环境的主流选择。
注意事项
MOF 文件安全 :MOF 文件可能包含凭据等敏感信息,应用后应妥善保管或删除,避免明文泄露
LCM 配置 :使用 Set-DscLocalConfigurationManager 配置 LCM 的刷新模式、频率等参数,拉取模式需配置 Pull Server
依赖关系 :合理使用 DependsOn 建立资源间的执行顺序,避免因执行顺序不当导致配置失败
幂等性 :所有 DSC 资源必须是幂等的——多次执行结果相同。TestScript 返回 $true 时 SetScript 不应执行
凭据加密 :配置中使用的凭据必须通过证书加密,使用 ConfigurationData 中的 CertificateFile 和 Thumbprint 参数
DSC v3 趋势 :微软正在推进 DSC v3,新项目建议关注 DSC v3 的进展,但生产环境仍以 v2 为主