Search code examples
t-sqlpowershelldsc

Reference credential in CMD called by DSC


I was wondering how I can reference credential in CMD called by DSC. This is the configuration that I'm trying to deploy, but it doesn't receive credentials.

configuration SQLCMD
{
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [PSCredential]
        $Credential

    )

    Import-DscResource -ModuleName xSqlServer

    Node localhost
    {

        LocalConfigurationManager
        {
            ConfigurationMode = 'ApplyOnly'
            RebootNodeIfNeeded = $true
            ActionAfterReboot = 'ContinueConfiguration'
            AllowModuleOverwrite = $true
        }

        Script DeployDBmoveTempDB 
        { 
            SetScript = { 
$SourceFile = 'C:\DatabaseTest.dacpac'
$TargetServerName = 'localhost'
$TargetDatabaseName = 'TestDB1'
$databaseSizeSQLCMD = '200MB'
$databaseLogSizeSQLCMD = '20MB'
$tempdbSizeSQLCMD = '1900MB'
$tempdbLogSizeSQLCMD = '1900MB'


trap {
    Write-Error $_
    Exit 1
}

 $args = @('/Action:Publish'
             ,"/SourceFile:$SourceFile"
             ,"/TargetServerName:$TargetServerName"
             ,"/TargetUser:$Credential.UserName"
             ,"/TargetPassword:$Credential"
             ,"/TargetDatabaseName:$TargetDatabaseName"
             ,"/v:databaseSizeSQLCMD=$databaseSizeSQLCMD"
             ,"/v:databaseLogSizeSQLCMD=$databaseLogSizeSQLCMD"
             ,"/v:tempdbSizeSQLCMD=$databaseSizeSQLCMD"
             ,"/v:tempdbLogSizeSQLCMD=$databaseLogSizeSQLCMD"
             ,'/p:BlockOnPossibleDataLoss=false'
             )            

    try {
        & "C:\Program Files (x86)\Microsoft SQL Server\130\DAC\bin\SqlPackage.exe" $args


    }
    catch {
        Write-Host $_ ;
    }   

        } 

            TestScript = { 
            Test-Path D:\TestDB1_primary.mdf
        } 
            GetScript = { <# This must return a hash table #> }
        }

    }
}

However, the following configuration works fine:

configuration SQLCMD
{
    param
    (
        [Parameter(Mandatory=$true)]
        [ValidateNotNullorEmpty()]
        [PSCredential]
        $Credential

    )

    Import-DscResource -ModuleName xSqlServer

    Node localhost
    {

        LocalConfigurationManager
        {
            ConfigurationMode = 'ApplyOnly'
            RebootNodeIfNeeded = $true
            ActionAfterReboot = 'ContinueConfiguration'
            AllowModuleOverwrite = $true
        }

        Script DeployDBmoveTempDB 
        { 
            SetScript = { 
$ErrorActionPreference = "Stop"
$SourceFile = 'C:\DatabaseTest.dacpac'
$TargetServerName = 'localhost'
$user_name = 'mySqlAdmin'
$user_pwd = 'blabla'
$TargetDatabaseName = 'TestDB1'
$databaseSizeSQLCMD = '200MB'
$databaseLogSizeSQLCMD = '20MB'
$tempdbSizeSQLCMD = '1900MB'
$tempdbLogSizeSQLCMD = '1900MB'


trap {
    Write-Error $_
    Exit 1
}

 $args = @('/Action:Publish'
             ,"/SourceFile:$SourceFile"
             ,"/TargetServerName:$TargetServerName"
             ,"/TargetUser:$user_name"
             ,"/TargetPassword:$user_pwd"
             ,"/TargetDatabaseName:$TargetDatabaseName"
             ,"/v:databaseSizeSQLCMD=$databaseSizeSQLCMD"
             ,"/v:databaseLogSizeSQLCMD=$databaseLogSizeSQLCMD"
             ,"/v:tempdbSizeSQLCMD=$databaseSizeSQLCMD"
             ,"/v:tempdbLogSizeSQLCMD=$databaseLogSizeSQLCMD"
             ,'/p:BlockOnPossibleDataLoss=false'
             )            

    try {
        & "C:\Program Files (x86)\Microsoft SQL Server\130\DAC\bin\SqlPackage.exe" $args


    }
    catch {
        Write-Host $_ ;
    }   

        } 

            TestScript = { 
            Test-Path D:\TestDB1_primary.mdf
        } 
            GetScript = { <# This must return a hash table #> }
        }

    }
}

Solution

  • DSC-configurations store scripts as strings in the generated mof and does not expand variables by default since it wouldn't know which to expand and which to keep as part of the script. However, by specifying the $using:-Scope, you can include variables defined in the configuration. During mof-compilcation, the variables are then added at the start of each of the Get-/Set-/TestScript scriptblocks. Ex:

    configuration SQLCMD
    {
        param
        (
            [Parameter(Mandatory=$true)]
            [ValidateNotNullorEmpty()]
            [PSCredential]
            $Credential    
        )
    
        Import-DscResource -ModuleName xSqlServer
    
        $user_name = $Credential.UserName
        $user_pwd = $Credential.GetNetworkCredential().Password
    
        Node localhost
        {    
            Script DeployDBmoveTempDB 
            { 
                SetScript = { 
    
                    $TargetDatabaseName = 'TestDB1'
                    $args = @(,"/TargetUser:$using:user_name"
                                 ,"/TargetPassword:$using:user_pwd"
                                 ,"/TargetDatabaseName:$TargetDatabaseName")                
                    try {
                        & "C:\Program Files (x86)\Microsoft SQL Server\130\DAC\bin\SqlPackage.exe" $args
                    }
                    catch { Write-Host $_  }       
                }     
                TestScript = { Test-Path "D:\TestDB1_primary.mdf" }             
                GetScript = { <# This must return a hash table #> }
            }
    
        }
    }
    

    Be aware that the password will be stored in plain text in the mof-file. Ex:

    SetScript = "$user_name ='User1'\n$user_pwd ='Password1'\n \n\n                $TargetDatabaseName = 'TestDB1'\n                $args = @(,\"/TargetUser:$user_name\"\n                       
          ,\"/TargetPassword:$user_pwd\"\n                             ,\"/TargetDatabaseName:$TargetDatabaseName\")            \n\n                try {\n                    & \"C:\\Program File
    s (x86)\\Microsoft SQL Server\\130\\DAC\\bin\\SqlPackage.exe\" $args\n                }\n                catch { Write-Host $_  }   \n\n            ";