Description of Problem
As an example, in Microsoft365DSC, resource PlannerTask, function Export-TargetResource
, line 787:
$content = Convert-DSCStringParamToVariable -DSCBlock $content `
-ParameterName 'Credential'
The function is called to ensure that quotes are removed around the values that are variables and not strings, i.e. instead of the following which does not work in quotes:
PlannerTask 7ad38863-ce48-4b8e-b169-f292222471e6
{
...
Credential = "$ConfigurationData.NonNodeData.Credential"
...
}
we remove the quote, so the variable sis actually resolved:
PlannerTask 7ad38863-ce48-4b8e-b169-f292222471e6
{
...
Credential = $ConfigurationData.NonNodeData.TenantId
...
}
However, the presence of Credential
is dependent on if Credential was used to authenticate, so it may not exist - ApplicationId with CertificateThumbprint may for instance be used instead. If so, the function Convert-DSCStringParamToVariable
throws an exception when looking for Credential on the line below # MY COMMENT
:
$startPosition = -1
do
{
$startPosition = $DSCBlock.IndexOf(' ' + $ParameterName + ' ', $startPosition + 1)
# MY COMMENT: the lines below fails if $ParameterName is not found i.e. $startPosition is still -1, since you cannot start at position -1
$testValidStartPositionEqual = $DSCBlock.IndexOf("=", $startPosition)
$testValidStartPositionQuotes = $DSCBlock.IndexOf("`"", $startPosition)
} while ($testValidStartPositionEqual -gt $testValidStartPositionQuotes -and
$startPosition -ne -1)
The exception:
System.Management.Automation.MethodInvocationException: Exception calling "IndexOf" with "2" argument(s): "Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: startIndex" ---> System.ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: startIndex
at System.String.IndexOf(String value, Int32 startIndex, Int32 count, StringComparison comparisonType)
at CallSite.Target(Closure , CallSite , String , String , Object )
--- End of inner exception stack trace ---
at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
at Convert-DSCStringParamToVariable(Closure , FunctionContext )
at System.Management.Automation.PSScriptCmdlet.RunClause(Action`1 clause, Object dollarUnderbar, Object inputToProcess)
at System.Management.Automation.PSScriptCmdlet.DoEndProcessing()
at System.Management.Automation.CommandProcessorBase.Complete()
"Error during Export:"
at Convert-DSCStringParamToVariable, C:\Modules\ReverseDSC\2.0.0.13\ReverseDSC.Core.psm1: line 688
at Export-TargetResource, C:\Modules\Microsoft365DSC\DSCResources\MSFT_PlannerTask\MSFT_PlannerTask.psm1: line 787
...
Suggested solution
If $ParameterName is not found, return the original $DSCBlock:
$startPosition = -1
do
{
$startPosition = $DSCBlock.IndexOf(' ' + $ParameterName + ' ', $startPosition + 1)
# If the ParameterName is not found, $startPosition is still -1, and .IndexOf($string, $startPosition) does not work, so skip
if ($startPosition -ne -1)
{
$testValidStartPositionEqual = $DSCBlock.IndexOf("=", $startPosition)
$testValidStartPositionQuotes = $DSCBlock.IndexOf("`"", $startPosition)
}
} while ($testValidStartPositionEqual -gt $testValidStartPositionQuotes -and
$startPosition -ne -1)
# If $ParameterName was not found i.e. $startPosition is still -1, skip this section as well. We
# just want the original $DSCBlock to be returned without modification
if ($startPosition -ne -1) {
$endOfLinePosition = $DSCBlock.IndexOf(";`r`n", $startPosition)
if ($endOfLinePosition -eq -1)
{
$endOfLinePosition = $DSCBlock.Length
}
$startPosition = $DSCBlock.IndexOf("`"", $startPosition)
}