如何根据先前执行的资源在Powershell DSC中有条件地执行资源?

时间:2014-09-29 18:12:30

标签: powershell dsc

说我有两个这样的街区:

Configuration TestConfig
{
    Node ('localhost') {
        File foo {
            DestinationPath = 'C:\foo.txt'
            Contents = 'Bar'
        }
        Script dothing {
            SetScript = {'Baz' | set-content C:\foo.txt}
            TestScript = {return $false}
            GetScript = {
                return @{
                    GetScript = ''
                    SetScript = ''
                    TestScript = ''
                    Credential = $Credential
                    Result = (Invoke-Expression -Command $TestScript)
                }
            }
            DependsOn = '[File]foo'
        }
    }
}

我构建了一个类似这样的测试,但似乎无论File资源的测试输出如何,都会执行Service资源 - 也就是说,如果它实际上对文件做了任何操作。

VERBOSE: [MACHINENAME]: LCM:  [ Start  Set      ]
VERBOSE: [MACHINENAME]: LCM:  [ Start  Resource ]  [[File]foo]
VERBOSE: [MACHINENAME]: LCM:  [ Start  Test     ]  [[File]foo]
VERBOSE: [MACHINENAME]:                            [[File]foo] The destination object was found and no action is required.
VERBOSE: [MACHINENAME]: LCM:  [ End    Test     ]  [[File]foo]  in 0.0040 seconds.
VERBOSE: [MACHINENAME]: LCM:  [ Skip   Set      ]  [[File]foo]
VERBOSE: [MACHINENAME]: LCM:  [ End    Resource ]  [[File]foo]
VERBOSE: [MACHINENAME]: LCM:  [ Start  Resource ]  [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM:  [ Start  Test     ]  [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM:  [ End    Test     ]  [[Script]dothing]  in 0.0050 seconds.
VERBOSE: [MACHINENAME]: LCM:  [ Start  Set      ]  [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM:  [ End    Set      ]  [[Script]dothing]  in 0.0060 seconds.
VERBOSE: [MACHINENAME]: LCM:  [ End    Resource ]  [[Script]dothing]
VERBOSE: [MACHINENAME]: LCM:  [ End    Set      ]
VERBOSE: [MACHINENAME]: LCM:  [ End    Set      ]    in  0.0390 seconds.

除了受控的示例之外,我怎样才能仅在文件资源实际执行某些操作时才执行脚本资源?

我的用例是检查远程位置的文件是否已更改,如果是,请将其复制到本地计算机,然后重新启动服务。我显然不希望重新启动服务,如果文件没有改变,但我看不到一个好的幂等方式来做到这一点,因为文件正在使用哈希测试 - 我必须有我的服务重启步骤执行相同的文件哈希检查。

1 个答案:

答案 0 :(得分:3)

我不认为DSC中有任何原生内容可以让一个资源检测到" Set-TargetResource"函数实际上是在同一配置运行中为不同的资源执行的。

但是,以下脚本资源可以执行您想要的操作,但是它们使用全局脚本级变量进行通信,因此如果您在一个服务中配置了多个服务,它们就会中断单个DSC。 ConfigureService脚本资源更新本地配置文件并设置RestartService资源读取的标志以检查是否进行了更改。它有点脏,但它有效。

Script ConfigureService {
    GetScript  = { return $null; }
    TestScript = {
        # compare remote and local file contents and return 
        # $true if they match, or $false if they're different
        $source = "D:\temp\dsctest\source.txt";
        $target = "D:\temp\dsctest\target.txt";
        $isMatch = [System.IO.File]::ReadAllText($target) -eq [System.IO.File]::ReadAllText($source);
        # set a flag for the RestartService resource to read
        $script:serviceChanged = -not $isMatch;
        write-verbose "isMatch = $isMatch";
        return $isMatch;
    }
    SetScript  = {
        # overwrite the local file
        $source = "D:\temp\dsctest\source.txt";
        $target = "D:\temp\dsctest\target.txt";
        $content = [System.IO.File]::ReadAllText($source);
        write-verbose "overwriting config";
        [System.IO.File]::WriteAllText($target, $content);
    }
}

Script RestartService {
    DependsOn  = "[Script]ConfigureService"
    GetScript  = { return $null; }
    TestScript = {
        write-verbose "serviceChanged = $($script:serviceChanged)";
        return -not $script:serviceChanged;
    }
    SetScript  = {
        # restart the service
        write-verbose "restarting service";
    }
}

或者只是将它全部滚动到一个资源中。如果您希望将其重新用于多个服务,则可以将其移动到完全成熟的ServiceConfiguration自定义资源中。

Script ConfigureService {
    GetScript  = { return $null; }
    TestScript = {
        # compare remote and local file contents and return 
        # $true if they match, or $false if they're different
        $source = "D:\temp\dsctest\source.txt";
        $target = "D:\temp\dsctest\target.txt";
        $isMatch = [System.IO.File]::ReadAllText($target) -eq [System.IO.File]::ReadAllText($source);
        write-verbose "isMatch = $isMatch";
        return $isMatch;
    }
    SetScript  = {
        # overwrite the local file
        $source = "D:\temp\dsctest\source.txt";
        $target = "D:\temp\dsctest\target.txt";
        $content = [System.IO.File]::ReadAllText($source);
        write-verbose "overwriting config";
        [System.IO.File]::WriteAllText($target, $content);
        # restart the service
        write-verbose "restarting service";
    }
}