diff --git a/src/Scripts/EncryptData.ps1 b/src/Scripts/EncryptData.ps1 index fc289bb..57fc782 100644 --- a/src/Scripts/EncryptData.ps1 +++ b/src/Scripts/EncryptData.ps1 @@ -6,13 +6,22 @@ at http://msdn.microsoft.com/en-us/library/ms998283.aspx (How To: Encrypt Configuration Sections in ASP.NET 2.0 Using RSA), but for the FIM Service account. #> +$Error.Clear() + Add-Type -AssemblyName "System.Security" -Add-Type -AssemblyName "MicrosoftServices.IdentityManagement.WorkflowActivityLibrary, Version=2.14.611.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" +# use the full name for WAL assembly to eliminate need to assembly redirects for dependent assemblies. +Add-Type -AssemblyName "MicrosoftServices.IdentityManagement.WorkflowActivityLibrary, Version=2.16.305.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" +if ($Error) +{ + Write-Host "Aborting script execution." + return +} function TestCertificateBasedEncryptionDecryption { $thumbprint = "9C697919FB2FB2D6324ADE42D5F8CB49E8778C08" # cert to be used for encryption. + $outFile = Join-Path -Path $PWD -ChildPath "cert-p.txt" $base64EncodedPublicKeyXml = [MicrosoftServices.IdentityManagement.WorkflowActivityLibrary.Common.ProtectedData]::GetCertificatePublicKeyXml($thumbprint, "My", "LocalMachine") @@ -22,10 +31,10 @@ function TestCertificateBasedEncryptionDecryption $encryptedData = [MicrosoftServices.IdentityManagement.WorkflowActivityLibrary.Common.ProtectedData]::EncryptData($secret, $base64EncodedPublicKeyXml) - $encryptedData | Out-File cert-p.txt - $encryptedDataConfig = "cert:\localmachine\my\$thumbprint,$encryptedData" + $encryptedDataConfig | Out-File $outFile + $decryptedData = [MicrosoftServices.IdentityManagement.WorkflowActivityLibrary.Common.ProtectedData]::DecryptData($encryptedDataConfig) $plainText = [MicrosoftServices.IdentityManagement.WorkflowActivityLibrary.Common.ProtectedData]::ConvertToUnsecureString($decryptedData) @@ -33,6 +42,7 @@ function TestCertificateBasedEncryptionDecryption if ($plainText -eq $secretToEncrypt) { Write-Host "`nEncryption and Decryption test using certificate '$thumbprint' succeeded!`n" + Write-Host "`nThe password config is saved in '$outFile'`n" } else { @@ -43,12 +53,13 @@ function TestCertificateBasedEncryptionDecryption function TestDPAPIBasedEncryptionDecryption { $secretToEncrypt = "Pass@word1" + $outFile = Join-Path -Path $PWD -ChildPath "dpapi-p.txt" $secret = ConvertTo-SecureString -AsPlainText $secretToEncrypt -Force $encryptedData = [MicrosoftServices.IdentityManagement.WorkflowActivityLibrary.Common.ProtectedData]::EncryptData($secret, [System.Security.Cryptography.DataProtectionScope]::LocalMachine) - $encryptedData | Out-File dpapi-p.txt + $encryptedData | Out-File $outFile $decryptedData = [MicrosoftServices.IdentityManagement.WorkflowActivityLibrary.Common.ProtectedData]::DecryptData($encryptedData, [System.Security.Cryptography.DataProtectionScope]::LocalMachine) @@ -57,6 +68,7 @@ function TestDPAPIBasedEncryptionDecryption if ($plainText -eq $secretToEncrypt) { Write-Host "`nEncryption and Decryption test using DPAPI succeeded!`n" + Write-Host "`nThe encrypted password is saved in '$outFile'`n" } else { @@ -64,6 +76,6 @@ function TestDPAPIBasedEncryptionDecryption } } -TestDPAPIBasedEncryptionDecryption +TestCertificateBasedEncryptionDecryption +#TestDPAPIBasedEncryptionDecryption -#TestCertificateBasedEncryptionDecryption \ No newline at end of file diff --git a/src/VersionInfo.cs b/src/VersionInfo.cs index 9c93005..cffc51d 100644 --- a/src/VersionInfo.cs +++ b/src/VersionInfo.cs @@ -22,7 +22,7 @@ internal static class VersionInfo /// Build Number (MMDD) /// Revision (if any on the same day) /// - internal const string Version = "2.16.0130.0"; + internal const string Version = "2.16.0305.0"; /// /// File Version information for the assembly consists of the following four values: @@ -31,6 +31,6 @@ internal static class VersionInfo /// Build Number (MMDD) /// Revision (if any on the same day) /// - internal const string FileVersion = "2.16.0130.0"; + internal const string FileVersion = "2.16.0305.0"; } } \ No newline at end of file diff --git a/src/WorkflowActivityLibrary/Activities/RunPowerShellScript.cs b/src/WorkflowActivityLibrary/Activities/RunPowerShellScript.cs index aee404b..255823e 100644 --- a/src/WorkflowActivityLibrary/Activities/RunPowerShellScript.cs +++ b/src/WorkflowActivityLibrary/Activities/RunPowerShellScript.cs @@ -882,75 +882,78 @@ private object RunScript(string script, IEnumerable scriptArguments, Dictionary< throw Logger.Instance.ReportError(EventIdentifier.RunPowerShellScriptRunScriptInvocationError, new WorkflowActivityLibraryException(Messages.RunPowerShellScript_ScriptInvocationError, ex, ex.Message)); } + // Let's go soft on the the non-terminating errors and trapped exceptions. + // We'll just log the error streams. + // If script wants to kill the activity, it should throw an exception. if (shell.Streams.Error.Count == 0) { - if (this.ReturnType == PowerShellReturnType.None) + StringBuilder message = new StringBuilder(); + message.AppendFormat(Messages.RunPowerShellScript_ScriptExecutionFailedError, shell.Streams.Error.Count); + foreach (ErrorRecord error in shell.Streams.Error) { - return null; + message.AppendFormat("{0}\n", error); } - if (results != null && results.Count == 1) - { - return results[0].BaseObject; - } + Logger.Instance.WriteError(EventIdentifier.RunPowerShellScriptRunScriptExecutionFailedError, message.ToString()); + } - if (results == null || results.Count < 1) - { - return null; - } + if (this.ReturnType == PowerShellReturnType.None) + { + return null; + } - // If multiple values were found for the lookup, verify that they are of a consistent type - Type type = null; - bool consistentType = true; - foreach (PSObject pso in results) - { - if (type == null) - { - type = pso.BaseObject.GetType(); - - Logger.Instance.WriteVerbose(EventIdentifier.RunPowerShellScriptRunScript, "The PowerShell script returned type: '{0}'.", type); - } - else if (pso.BaseObject.GetType() != type) - { - consistentType = false; - Logger.Instance.WriteError(EventIdentifier.RunPowerShellScriptRunScriptInconsistentScriptReturnTypeError, Messages.RunPowerShellScript_InconsistentScriptReturnTypeError, pso.BaseObject.GetType(), type); - } - } + if (results != null && results.Count == 1) + { + return results[0].BaseObject; + } - // If we have multiple values of an inconsistent type, there is a problem - // which needs to be addressed by the administrator - if (!consistentType) - { - throw Logger.Instance.ReportError(EventIdentifier.RunPowerShellScriptRunScriptInconsistentScriptReturnTypeError, new WorkflowActivityLibraryException(Messages.RunPowerShellScript_InvalidReturnTypeError)); - } + if (results == null || results.Count < 1) + { + return null; + } - // Because we have multiple values returned for the PowerShell script, - // we want to return them in the form of a strongly-typed list - // For example: List instead of List - // Use reflection to create a new strongly-typed list - Type listType = typeof(List<>).MakeGenericType(new Type[] { type }); - var typedList = Activator.CreateInstance(listType); - - // Using reflection, fetch the add method for the new list - // and invoke it to add each value from the original PSobject collection to the new collection - // Return the strongly-typed list - MethodInfo add = listType.GetMethod("Add"); - foreach (PSObject pso in results) - { - add.Invoke(typedList, new object[] { pso.BaseObject }); - } + // If multiple values were found for the lookup, verify that they are of a consistent type + Type type = null; + bool consistentType = true; + foreach (PSObject pso in results) + { + if (type == null) + { + type = pso.BaseObject.GetType(); - return typedList; + Logger.Instance.WriteVerbose(EventIdentifier.RunPowerShellScriptRunScript, "The PowerShell script returned type: '{0}'.", type); + } + else if (pso.BaseObject.GetType() != type) + { + consistentType = false; + Logger.Instance.WriteError(EventIdentifier.RunPowerShellScriptRunScriptInconsistentScriptReturnTypeError, Messages.RunPowerShellScript_InconsistentScriptReturnTypeError, pso.BaseObject.GetType(), type); + } + } + + // If we have multiple values of an inconsistent type, there is a problem + // which needs to be addressed by the administrator + if (!consistentType) + { + throw Logger.Instance.ReportError(EventIdentifier.RunPowerShellScriptRunScriptInconsistentScriptReturnTypeError, new WorkflowActivityLibraryException(Messages.RunPowerShellScript_InvalidReturnTypeError)); } - StringBuilder message = new StringBuilder(); - message.AppendFormat(Messages.RunPowerShellScript_ScriptExecutionFailedError, shell.Streams.Error.Count); - foreach (ErrorRecord error in shell.Streams.Error) + // Because we have multiple values returned for the PowerShell script, + // we want to return them in the form of a strongly-typed list + // For example: List instead of List + // Use reflection to create a new strongly-typed list + Type listType = typeof(List<>).MakeGenericType(new Type[] { type }); + var typedList = Activator.CreateInstance(listType); + + // Using reflection, fetch the add method for the new list + // and invoke it to add each value from the original PSobject collection to the new collection + // Return the strongly-typed list + MethodInfo add = listType.GetMethod("Add"); + foreach (PSObject pso in results) { - message.AppendFormat("{0}\n", error); + add.Invoke(typedList, new object[] { pso.BaseObject }); } - throw Logger.Instance.ReportError(EventIdentifier.RunPowerShellScriptRunScriptExecutionFailedError, new WorkflowActivityLibraryException(message.ToString())); + return typedList; } } } diff --git a/src/WorkflowActivityLibrary/Common/ExpressionFunction.cs b/src/WorkflowActivityLibrary/Common/ExpressionFunction.cs index bf24054..75cb312 100644 --- a/src/WorkflowActivityLibrary/Common/ExpressionFunction.cs +++ b/src/WorkflowActivityLibrary/Common/ExpressionFunction.cs @@ -2900,7 +2900,8 @@ private string NormalizeString() { string[] substituionPairs = substitutions.Split(new string[] { "|" }, StringSplitOptions.RemoveEmptyEntries); - foreach (string[] substitution in substituionPairs.Select(substituionPair => substituionPair.Split(new string[] { ":" }, StringSplitOptions.RemoveEmptyEntries)).Where(substitution => substitution.Length == 2)) + // Changed StringSplitOptions for substituionPairs from RemoveEmptyEntries to None so that soft and hard signs such as"Ь" can be simply dropped + foreach (string[] substitution in substituionPairs.Select(substituionPair => substituionPair.Split(new string[] { ":" }, StringSplitOptions.None)).Where(substitution => substitution.Length == 2)) { input = input.Replace(substitution[0].Trim(), substitution[1].Trim()); input = input.Replace(substitution[0], substitution[1].Trim());