Skip to content

Commit

Permalink
New function DateTimeUtcToLocalTimeFunction. New optional culture nam…
Browse files Browse the repository at this point in the history
…e parameter to DateTimeFormat function.

Added support for WAL Lookup resolution for PowerShellUserName and PowerShellUserPassword properties of RunPowerShellScript activity.
  • Loading branch information
NileshGhodekar committed May 23, 2020
1 parent b170d76 commit addd2ef
Show file tree
Hide file tree
Showing 11 changed files with 291 additions and 40 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,5 @@ GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
/src/ReferencedAssemblies
/src/Scripts
/src/SolutionOutput
/src/WAL.snk
18 changes: 17 additions & 1 deletion ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,19 @@ All notable changes to MIMWAL project will be documented in this file. The "Unre
* Support for `[//Value]` lookups in Query definitions across rest of the activities.
------------

### Version 2.19.0111.0
### Version 2.20.0523.0

#### Added

* New [IndexByValueFunction][IndexByValue] function
* New [CRFunction][CR] function
* New [DateTimeUtcToLocalTimeFunction][DateTimeUtcToLocalTime] function
* New optional culture name parameter to [DateTimeFormatFunction][DateTimeFormat] function
* Added support for WAL Lookup resolution for PowerShellUserName and PowerShellUserPassword properties of [Run PowerShell Script][RunPowerShellScript] activity.

------------

### Version 2.19.0112.0

#### Changed

Expand Down Expand Up @@ -225,13 +237,15 @@ To get the backward compatible behaviour, define the app setting GenerateUniqueV
[CreateSqlParameterFunction]: https://github.com/Microsoft/MIMWAL/wiki/CreateSqlParameter-Function
[CreateSqlParameter2Function]: https://github.com/Microsoft/MIMWAL/wiki/CreateSqlParameter2-Function
[CRLFFunction]: https://github.com/Microsoft/MIMWAL/wiki/CRLF-Function
[CRFunction]: https://github.com/Microsoft/MIMWAL/wiki/CR-Function
[DateTimeAddFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeAdd-Function
[DateTimeFormatFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeFormat-Function
[DateTimeFromFileTimeUTCFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeFromFileTimeUTC-Function
[DateTimeFromStringFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeFromString-Function
[DateTimeNowFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeNow-Function
[DateTimeSubtractFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeSubtract-Function
[DateTimeToFileTimeUTCFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeToFileTimeUTC-Function
[DateTimeUtcToLocalTimeFunction]: https://github.com/Microsoft/MIMWAL/wiki/DateTimeUtcToLocalTime-Function
[DivideFunction]: https://github.com/Microsoft/MIMWAL/wiki/Divide-Function
[EqFunction]: https://github.com/Microsoft/MIMWAL/wiki/Eq-Function
[EscapeDNComponentFunction]: https://github.com/Microsoft/MIMWAL/wiki/EscapeDNComponent-Function
Expand All @@ -244,6 +258,7 @@ To get the backward compatible behaviour, define the app setting GenerateUniqueV
[GreaterThanFunction]: https://github.com/Microsoft/MIMWAL/wiki/GreaterThan-Function
[IIFFunction]: https://github.com/Microsoft/MIMWAL/wiki/IIF-Function
[InsertValuesFunction]: https://github.com/Microsoft/MIMWAL/wiki/InsertValues-Function
[IndexByValueFunction]: https://github.com/Microsoft/MIMWAL/wiki/IndexByValue-Function
[IsPresentFunction]: https://github.com/Microsoft/MIMWAL/wiki/IsPresent-Function
[LastFunction]: https://github.com/Microsoft/MIMWAL/wiki/Last-Function
[LeftFunction]: https://github.com/Microsoft/MIMWAL/wiki/Left-Function
Expand Down Expand Up @@ -288,3 +303,4 @@ To get the backward compatible behaviour, define the app setting GenerateUniqueV
[WrapXPathFilterFunction]: https://github.com/Microsoft/MIMWAL/wiki/WrapXPathFilter-Function
[MIMWalFunctionsTable]: https://github.com/Microsoft/MIMWAL/wiki/Functions-Table
[GenerateUniqueValueActivity]: https://github.com/Microsoft/MIMWAL/wiki/Generate-Unique-Value-Activity
[RunPowerShellScriptActivity]: https://github.com/Microsoft/MIMWAL/wiki/Run-PowerShell-Script-Activity
72 changes: 72 additions & 0 deletions src/Scripts/EncryptConnectionString.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<#
This script demonstrates how to encrypt connection strings used by WAL ExecutSql* functions.
If a connection string contains SQL user's password information, it's highly recommended that you do not leave them unencrypted in the app config file.
For more information, see: https://docs.microsoft.com/en-us/dotnet/framework/data/adonet/connection-strings-and-configuration-files#encrypting-configuration-file-sections-using-protected-configuration
NOTE: This script will need to to be run on each FIMService server.
#>

param (
[string] $sectionName = "connectionStrings",
[string] $dataProtectionProvider = "DataProtectionConfigurationProvider"
)

$Error.Clear()

#The System.Configuration assembly must be loaded
$configurationAssembly = "System.Configuration, Version=2.0.0.0, Culture=Neutral, PublicKeyToken=b03f5f7f11d50a3a"
[void] [Reflection.Assembly]::Load($configurationAssembly)

function TestIsAdministrator
{
$currentUser = [Security.Principal.WindowsIdentity]::GetCurrent()
(New-Object Security.Principal.WindowsPrincipal $currentUser).IsInRole([Security.Principal.WindowsBuiltinRole]::Administrator)
}

if(!(TestIsAdministrator))
{
throw $("Admin rights are required to run this script.")
}

Write-Host "Encrypting configuration section: '$sectionName'.."

$appService = "FIMService"
$appPath = [string](Get-WmiObject -Query "Select * from Win32_Service Where Name='$appService'").PathName

if ($appPath -eq $null)
{
Write-Error "Unable to find get application path for windows service '$appService'."
return
}
else
{
$appPath = $appPath.Trim('"')
}

Write-Host "The app config file path is: '$appPath'."

$appConfig = [System.Configuration.ConfigurationManager]::OpenExeConfiguration($appPath)
$section = $appConfig.GetSection($sectionName)

if (!$section.SectionInformation.IsProtected)
{
$section.SectionInformation.ProtectSection($dataProtectionProvider);
$section.SectionInformation.ForceSave = [System.Boolean]::True;
$appConfig.Save([System.Configuration.ConfigurationSaveMode]::Modified);

if ($Error.Count -eq 0)
{
Write-Host "Success!! Encrypted the config section '$sectionName' in the app config file '$appPath'."
}
}
else
{
Write-Host "The config section '$sectionName' in the app config file '!$appPath' is already encrypted."
}

if ($Error)
{
Write-Host "There were errors executing the script."
}
4 changes: 2 additions & 2 deletions src/Scripts/EncryptData.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
Finding Assembly verion and PublicKeyToken
gacutil.exe -l | findstr WorkflowActivityLibrary
Creatinig a self signed certificate for MIMWAL (You can use a legacy CSP such as Microsoft Strong Cryptographic Provider as shown in the example below)
$cert = New-SelfSignedCertificate -DnsName "MIMWAL" -CertStoreLocation "cert:\LocalMachine\My" -Provider "Microsoft Strong Cryptographic Provider"
$cert = New-SelfSignedCertificate -DnsName "MIMWAL Encryption (Do Not Delete)" -CertStoreLocation "cert:\LocalMachine\My" -Provider "Microsoft Strong Cryptographic Provider" -NotAfter (Get-Date).AddYears(20)
$cert.Thumbprint
As of version v2.18.1110.0, only FIMService account needs read access to the private key of the MIMWAL certificate created above.
#>

$Error.Clear()

$walAssemblyVersion = "2.16.0710.0"
$walAssemblyVersion = "2.20.0523.0"
$walAssemblyPublicKeyToken = "31bf3856ad364e35"
$encryptionCertThumbprint = "9C697919FB2FB2D6324ADE42D5F8CB49E8778C08" # cert to be used for encryption (from the cert:\localmachine\my\ store).

Expand Down
4 changes: 2 additions & 2 deletions src/VersionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ internal static class VersionInfo
/// Build Number (MMDD)
/// Revision (if any on the same day)
/// </summary>
internal const string Version = "2.19.0112.0";
internal const string Version = "2.20.0523.0";

/// <summary>
/// File Version information for the assembly consists of the following four values:
Expand All @@ -31,6 +31,6 @@ internal static class VersionInfo
/// Build Number (MMDD)
/// Revision (if any on the same day)
/// </summary>
internal const string FileVersion = "2.19.0112.0";
internal const string FileVersion = "2.20.0523.0";
}
}
8 changes: 4 additions & 4 deletions src/WorkflowActivityLibrary.UI/ActivitySettings.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions src/WorkflowActivityLibrary.UI/ActivitySettings.resx
Original file line number Diff line number Diff line change
Expand Up @@ -658,19 +658,19 @@
<value>PowerShell Script User</value>
</data>
<data name="PowerShellUserHelpText" xml:space="preserve">
<value>Specify the user to be used to construct PowerShell Credential object. When impersonating, the user name must be in the domain\userName or UPN format.</value>
<value>Specify the user to be used to construct PowerShell Credential object. When impersonating, the user name must be in the domain\userName or UPN format or must be a valid WAL Lookup expression.</value>
</data>
<data name="PowerShellUserPassword" xml:space="preserve">
<value>PowerShell Script User Password</value>
</data>
<data name="PowerShellUserPasswordHelpText" xml:space="preserve">
<value>Specify the password to be used to construct PowerShell Credential object. The expected format is: [base64EncodedEncryptedData] | [app:\appSettings\[key],[LocalMachine|CurrentUser]] | [cert:\[LocalMachine|CurrentUser]\my\[thumbprint],base64EncodedEncryptedData]]</value>
<value>Specify the password to be used to construct PowerShell Credential object. The expected format is: [base64EncodedEncryptedData] | [app:\appSettings\[key],[LocalMachine|CurrentUser]] | [cert:\[LocalMachine|CurrentUser]\my\[thumbprint],base64EncodedEncryptedData]]. It can also be a valid WAL Lookup expression returing data in any one of these formats.</value>
</data>
<data name="PowerShellImpersonationSettingsValidationError" xml:space="preserve">
<value>Specify UserName and Password of the impersonated user.</value>
</data>
<data name="PowerShellUserFormatValidationError" xml:space="preserve">
<value>The PowerShell user must be specified in the domain\userName or UPN format when Impersonate PowerShell User option is selected.</value>
<value>The PowerShell user must be specified in the domain\userName or UPN format or must be a valid WAL Lookup expression when Impersonate PowerShell User option is selected.</value>
</data>
<data name="RequestActorValidationError" xml:space="preserve">
<value>Authorization Policy cannot be applied when Request Actor is Service Account</value>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -554,7 +554,9 @@ public override bool ValidateInputs()

if (!string.IsNullOrEmpty(this.powerShellUser.Value))
{
if (this.impersonatePowerShellUser.Value)
var powerShellUserIsExpression = evaluator.ParseIfExpression(this.powerShellUser.Value);

if (this.impersonatePowerShellUser.Value && !powerShellUserIsExpression)
{
if (!this.powerShellUser.Value.Contains(@"\") && !this.powerShellUser.Value.Contains("@"))
{
Expand Down
56 changes: 51 additions & 5 deletions src/WorkflowActivityLibrary/Activities/RunPowerShellScript.cs
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,16 @@ private void Prepare_ExecuteCode(object sender, EventArgs e)
// If the activity is configured for conditional execution, parse the associated expression
this.ActivityExpressionEvaluator.ParseIfExpression(this.ActivityExecutionCondition);

if (!string.IsNullOrEmpty(this.PowerShellUser))
{
this.ActivityExpressionEvaluator.ParseIfExpression(this.PowerShellUser);
}

if (!string.IsNullOrEmpty(this.PowerShellUserPassword))
{
this.ActivityExpressionEvaluator.ParseIfExpression(this.PowerShellUserPassword);
}

if (this.InputType == PowerShellInputType.Arguments &&
this.Arguments != null &&
this.Arguments.Count > 0)
Expand Down Expand Up @@ -1018,18 +1028,54 @@ private PSCredential GetPowerShellCredential()
return null;
}

var userName = this.PowerShellUser;
var userPassword = this.PowerShellUserPassword;

if (ExpressionEvaluator.IsExpression(userName))
{
try
{
object resolved = this.ActivityExpressionEvaluator.ResolveExpression(userName);
if (resolved != null)
{
userName = resolved.ToString();
}
}
catch (WorkflowActivityLibraryException)
{
// This may happen if the design time username starts with a $
// Do nothing. Any valid error should already be reported.
}
}

if (ExpressionEvaluator.IsExpression(userPassword))
{
try
{
object resolved = this.ActivityExpressionEvaluator.ResolveExpression(userPassword);
if (resolved != null)
{
userPassword = resolved.ToString();
}
}
catch (WorkflowActivityLibraryException)
{
// Do nothing. Any valid error should already be reported.
}
}

if (this.ImpersonatePowerShellUser)
{
string[] userParts = this.PowerShellUser.Split(new string[] { @"\" }, StringSplitOptions.RemoveEmptyEntries);
if (userParts.Length != 2 && !this.PowerShellUser.Contains("@"))
string[] userParts = userName.Split(new string[] { @"\" }, StringSplitOptions.RemoveEmptyEntries);
if (userParts.Length != 2 && !userName.Contains("@"))
{
throw Logger.Instance.ReportError(EventIdentifier.RunPowerShellScriptRunScriptExecutionFailedError, new WorkflowActivityLibraryException(Messages.RunPowerShellActivity_InvalidUserFormat, this.PowerShellUser));
throw Logger.Instance.ReportError(EventIdentifier.RunPowerShellScriptRunScriptExecutionFailedError, new WorkflowActivityLibraryException(Messages.RunPowerShellActivity_InvalidUserFormat, userName));
}
}

SecureString password = ProtectedData.DecryptData(this.PowerShellUserPassword);
SecureString password = ProtectedData.DecryptData(userPassword);

return new PSCredential(this.PowerShellUser, password);
return new PSCredential(userName, password);
}

/// <summary>
Expand Down
33 changes: 24 additions & 9 deletions src/WorkflowActivityLibrary/Common/EventIdentifier.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1296,7 +1296,12 @@ public static class EventIdentifier
/// <summary>
/// The event identifier for ExpressionFunction CR events
/// </summary>
public const int ExpressionFunctionCr = 11688;
public const int ExpressionFunctionCR = 11688;

/// <summary>
/// The event identifier for ExpressionFunction DateTimeUtcToLocalTime events
/// </summary>
public const int ExpressionFunctionDateTimeUtcToLocalTime = 11689;

/// <summary>
/// The event identifier for LookupEvaluator Constructor events
Expand Down Expand Up @@ -2358,6 +2363,11 @@ public static class EventIdentifier
/// </summary>
public const int ExpressionFunctionDateTimeFormatInvalidFirstFunctionParameterTypeError = 41621;

/// <summary>
/// The event identifier for ExpressionFunction DateTimeFormat events
/// </summary>
public const int ExpressionFunctionDateTimeFormatInvalidThirdFunctionParameterTypeError = 41621;

/// <summary>
/// The event identifier for ExpressionFunction DateTimeNow events
/// </summary>
Expand Down Expand Up @@ -2758,11 +2768,6 @@ public static class EventIdentifier
/// </summary>
public const int ExpressionFunctionCrlfInvalidFunctionParameterCountError = 41658;

/// <summary>
/// The event identifier for ExpressionFunction CR events
/// </summary>
public const int ExpressionFunctionCrInvalidFunctionParameterCountError = 41658;

/// <summary>
/// The event identifier for ExpressionFunction EscapeDNComponent events
/// </summary>
Expand Down Expand Up @@ -3194,14 +3199,24 @@ public static class EventIdentifier
public const int ExpressionFunctionModInvalidSecondFunctionParameterTypeError = 41686;

/// <summary>
/// The event identifier for ExpressionFunction ValueByIndex events
/// The event identifier for ExpressionFunction IndexByValue events
/// </summary>
public const int ExpressionFunctionIndexByValueInvalidFunctionParameterCountError = 41687;

/// <summary>
/// The event identifier for ExpressionFunction IndexByValue events
/// The event identifier for ExpressionFunction CR events
/// </summary>
public const int ExpressionFunctionCRInvalidFunctionParameterCountError = 41688;

/// <summary>
/// The event identifier for ExpressionFunction DateTimeUtcToLocalTime events
/// </summary>
public const int ExpressionFunctionDateTimeUtcToLocalTimeInvalidFunctionParameterCountError = 41689;

/// <summary>
/// The event identifier for ExpressionFunction DateTimeUtcToLocalTime events
/// </summary>
public const int ExpressionFunctionIndexByValueNullFunctionParameterError = 41645;
public const int ExpressionFunctionDateTimeUtcToLocalTimeInvalidSecondFunctionParameterTypeError = 41689;

/// <summary>
/// The event identifier for LookupEvaluator Constructor events
Expand Down
Loading

0 comments on commit addd2ef

Please sign in to comment.