How do I compile MOF file with variables inside script expanded

Hello,

Due to issue of File resource adding BOM header to contents of text files being written I have to resort to writing Script resource to curcumvent it. Unfortunately none of variables inside script are being expanded when MOF is compiled (unlike File resource which does). Is it possible to compile MOF file with variables intact or what would be the solution to write out string passed during compilation to file system when DSC is invoked?

Configuration SwarmManager
{
    # Parameter help description
    param
    (   
        [Parameter(Mandatory)]       
        [string] $privateKey 
    )
   
    Node localhost
    {
 
        File MyFile {
            Contents        = $privateKey
            DestinationPath = "$env:HOMEPATH\fromFile.txt"
        }

        Script MyScript {
            SetScript  = {
                $privateKey | out-file -FilePath "$env:HOMEPATH\FromScript.txt" -Encoding ascii -Verbose
               
            }
            TestScript = { 
                (Test-Path -Path "$env:HOMEPATH\FromScript.txt") 
            }
            GetScript  = { @{CertFiles = (Test-Path "C:\ProgramData\docker\certs.d\ca.cer" )}	
            }
        }
    }

}
SwarmManager -Verbose

Mof file contents are below

instance of MSFT_FileDirectoryConfiguration as $MSFT_FileDirectoryConfiguration1ref
{
ResourceID = "[File]MyFile";
 Contents = "abc";
 DestinationPath = "\\Users\\gsuvalia\\fromFile.txt";
 ModuleName = "PSDesiredStateConfiguration";
 SourceInfo = "D:\\test\\dsctest.ps1::13::9::File";

ModuleVersion = "1.0";

 ConfigurationName = "SwarmManager";

};
instance of MSFT_ScriptResource as $MSFT_ScriptResource1ref
{
ResourceID = "[Script]MyScript";
 GetScript = " @{CertFiles = (Test-Path \"C:\\ProgramData\\docker\\certs.d\\ca.cer\" )}	\n            ";
 TestScript = " \n                (Test-Path -Path \"$env:HOMEPATH\\FromScript.txt\") \n               \n            ";
 SourceInfo = "D:\\test\\dsctest.ps1::18::9::Script";
 SetScript = "\n                $privateKey | out-file -FilePath \"$env:HOMEPATH\\FromScript.txt\" -Encoding ascii -Verbose\n               \n            ";
 ModuleName = "PsDesiredStateConfiguration";

Hi,

You may try to build your scriptblocks based on a string:

SetScript  = [Scriptblock]::Create("'$privateKey' | out-file -FilePath '$env:HOMEPATH\FromScript.txt' -Encoding ascii -Verbose")

Also, you are 90% of the way to creating a new resource. I would consider doing that instead of using the Script resource.

Scriptblock did not do it either, still appears as variable in final MOF file.

instance of MSFT_ScriptResource as $MSFT_ScriptResource1ref
{
ResourceID = "[Script]MyScript";
 GetScript = " @{CertFiles = (Test-Path \"C:\\ProgramData\\docker\\certs.d\\ca.cer\" )}	\n            ";
 TestScript = " \n                (Test-Path -Path \"$env:HOMEPATH\\FromScript.txt\") \n            ";
 SourceInfo = "C:\\gd\\Documents\\dockerswarmarm\\dsctest.ps1::18::9::Script";
 SetScript = "\n                [Scriptblock]::Create(\"'$privateKey' | out-file -FilePath '$env:HOMEPATH\\FromScript.txt' -Encoding ascii -Verbose\")\n                #$privateKey | out-file -FilePath \"$env:HOMEPATH\\FromScript.txt\" -Encoding ascii -Verbose\n               \n            ";
 ModuleName = "PsDesiredStateConfiguration";

I guess you placed the [Scriptblock]::Create(“”) inside your {}.

You should have something like that:

Script MyScript {
    SetScript = [Scriptblock]::Create("'$privateKey' | out-file -FilePath '$env:HOMEPATH\FromScript.txt' -Encoding ascii -Verbose")
    TestScript = [Scriptblock]::Create("(Test-Path -Path '$env:HOMEPATH\FromScript.txt')") 
    GetScript  = [Scriptblock]::Create("@{CertFiles = '$env:HOMEPATH\FromScript.txt'}")	
}

Output mof:

ResourceID = "[Script]MyScript";
 GetScript = "@{CertFiles = '\\Users\\Julien\\FromScript.txt'}";
 TestScript = "(Test-Path -Path '\\Users\\Julien\\FromScript.txt')";
 SourceInfo = "::12::9::Script";
 SetScript = "'test' | out-file -FilePath '\\Users\\Julien\\FromScript.txt' -Encoding ascii -Verbose";
 ModuleName = "PsDesiredStateConfiguration";

But as said by Michael, you should create a custom resource. See https://docs.microsoft.com/en-us/powershell/dsc/authoringresourcemof

You’ll be able to easily reuse your ‘Ascci File DSC Resource’ and have a cleaner DSC recipe.

Note: your test function doesn’t actually test if the content of the file is correct.