Start a new topic
Implemented

Evolution proposals for dynamic folder with PowerShell

Here are a few limitations with the way dynamic folder works in PowerShell today:

1. Impossible to get the ' character (simple quote) in a token provided by Royal TS
If we want to retrieve the description, we'll do it like this in PowerShell:
$TargetDescription = '$Target.Description$'
except that "$Target.Description$" will be replaced by the correct value in the temporary PowerShell script generated by Royal TS and then executed. If the description is "Sam's VM for testing", we'll get:
$TargetDescription = 'Sam's VM for testing'.
but this PowerShell code is invalid and cannot be executed.

The same applies to passwords. This is even more problematic as it prevents the ' character from being used in passwords.
$AccountPassword = '$EffectivePassword$'
In strong passwords (for admin access to servers, for example), it's very likely to have all kinds of special characters, so preventing the ' character is a limitation.
This limitation is also present in the dynamic file models integrated into Royal TS (also available here https://github.com/royalapplications/toolbox/tree/master/Dynamic%20Folder).

Alternatively, if or uses this code:
$TargetDescription = "$Target.Description$"
the single quotation mark will work, but it's the double quotation mark that will generate errors. And if the text contains a $, both the $ and the text after it will be deleted, as the double quote seeks to interpret variables in PowerShell ("$Target" will be considered by PowerShell as a variable to be replaced).

2. The password is stored in plain text (in a PowerShell file and in RAM) throughout the execution of the PowerShell script (for both folder and credentials scripts).
If the dynamic folder uses credentials and the PowerShell script uses the token '$EffectivePassword$', the latter will be written in plain text in a temporary file at this path "C:\Users\<username>\AppData\Local\Temp\Royal TS V7\DynF_<random-hash>.ps1" and it will be executed and thus be in plain text in RAM.

At present, only Javascript does not use temporary files (see https://support.royalapps.com/support/solutions/articles/17000072533), but this is not available on Windows.

3. Warning for token resolution problems 
Warnings can be raised when Royal TS fails to resolve tokens. Sometimes these warnings are wrongly raised. See post https://support.royalapps.com/support/discussions/topics/17000024226

4. Difficulties in dynamically generating command tasks or task sequences with tokens
If you wish to dynamically generate commands tasks or sequences tasks and use tokens, these will be rewritten when the temporary PowerShell file is generated.
For example, if you have:
@{
    Objects = @(
        @{
            Type = 'CommandTask';
            Name = 'My-custom-task-command';
            Description = 'Task example';
            Properties = @{
                CommandLine = 'MyScript.exe';
                Arguments = '/Name="$Name$" /Description="$Description$" /URI=$URI$ /EffectiveUsername="$EffectiveUsername$" /EffectivePassword="$EffectivePassword$" /Config="$CustomField1$"';
            }
        }
    )
} |
ConvertTo-Json -Depth 100 |
Write-Host

This will produce the following task command:
Command: MyScript.exe
Arguments: /Name="Dynamic folder example" /Description="" /URI=$URI$ /EffectiveUsername="hello" /EffectivePassword="world" /Config=""
Whereas our objective is to obtain:
Command: MyScript.exe
Arguments: /Name="$Name$" /Description="$Description$" /URI=$URI$ /EffectiveUsername="$EffectiveUsername$" /EffectivePassword="$EffectivePassword$" /Config="$CustomField1$"
Generating Command Task or Key Sequence Task requires some tinkering to avoid having to replace tokens at the wrong time.


Here are some suggestions for evolving the dynamic folder in PowerShell:
1. No longer replace tokens in the script but provide variables containing the value.
The idea would be to inject a block like this at the beginning of the temporary PowerShell script:
$ROYALTS_DOCUMENT_FOLDER_PATH = 'C:\Users\<username>\Documents\'
$ROYALTS_EFFECTIVE_USERNAME = 'John
$ROYALTS_TARGET_NAME = 'MyServer
$ROYALTS_TARGET_CUSTOMFIELD1 = 'Data 1'
[...]
so that these variables can be used within the script.
 
When generating this block, you can replace the ' character with '' in the variable values.
$ROYALTS_TARGET_DESCRIPTION = 'Sam''s VM for testing'
The use of this variable will therefore be as expected:
$> Write-Host $ROYALTS_TARGET_DESCRIPTION
Sam's VM for testing
 
This variable injection also means that tokens will no longer be replaced in scripts, and warnings will no longer be raised for token resolution problems (which are sometimes incorrectly resolved). This will also no longer be a problem for Command Task or Key Sequence Task generation.

2. Password protection with a SecureString variable
The password could be supplied as a SecureString instead of a String to improve security.
The idea is to retrieve:
a) either a $ROYALTS_EFFECTIVE_PASSWORD variable of type SecureString
b) or a path to the temporary secure password $ROYALTS_EFFECTIVE_PASSWORD_PATH



a) In this case, the $ROYALTS_EFFECTIVE_PASSWORD variable with the SecureString password should be transmitted to the PowerShell context before the PowerShell script is executed. This would prevent it from being stored in plain text in RAM and in a PowerShell file.

b) Alternatively, you can generate a temporary file with the encrypted password and provide a variable containing the path to this file.
Proposed execution of the PowerShell script for the dynamic folder:
- When executing a dynamic folder or dynamic credentials, generate a temporary file with the password
'MySecretPassword' | ConvertFrom-SecureString | Out-File -FilePath "C:\Users\<username>\AppData\Local\Temp\Royal TS V7\DynF_<random-hash>.pwd”
- Generate temporary PowerShell script in C:\Users\<username>\AppData\Local\Temp\Royal TS V7\DynF_<random-hash>.ps1
- Injection of the variable $ROYALTS_EFFECTIVE_PASSWORD_PATH='C:\Users\<username>\AppData\Local\Temp\Royal TS V7\DynF_<random-hash>.pwd' at the beginning of the script C:\Users\<username>\AppData\Local\Temp\Royal TS V7\DynF_<random-hash>.ps1
- Running the PowerhShell script
- Delete temporary Powerhshell script
- Delete temporary pwd file

This solution greatly reduces risk and exposure:
- no clear password in RAM
- no plaintext password in a file
- only an encrypted password in a file readable by PowerhShell only on the current computer and session
- possibility of using any character (including the single quotation mark ') for the password


It would even be possible to implement this solution in parallel with the current one.
For a few versions, you could inject these variables systematically + replace tokens (if present in the script).
For users who have not yet migrated their scripts:
- they will have variables injected that will have no impact on their script.
- if at least 1 token is replaced, you add a warning in the logs to say that it's deprecated and that token "xxxx" should be replaced by variable "yyyy". This makes migration easy: all you must do is apply the token change with a variable.
For users who have already migrated:
- the token replacement will have no impact, as there will be no "change of token" in the script.


In the meantime, a workaround is not to bind identifiers to a dynamic folder and to use "Get-Credential" in the PowerShell script to require manual input from the user each time the folder is reloaded. It's a pity not to use the credentials securely stored in the Royal TS "Credentials" items, but it's still more secure for the time being.



I hope that my vision/suggestions will also be shared by other Royal TS users and developers and that a better solution for PowerShell can be implemented.
Thanks


Hi Damien,


what a great summary and thanks for your awesome suggestions.


We are aware that the current implementation has limits, quirks and problems. Your suggestions are great and would work well with PowerShell. We are considering a different approach in the future and would like to know what you think about it.


The main problem with the script block containing the variables is that escaping those characters is different for each language and script interpreter. We actually think about setting those variables as environment variable when we execute that script. This has two advantages:

- we get rid of replacement tokens and potential security risks leaking passwords in a plain text script file on disk

- all the values are in memory for a very short period of time (the time of the script execution) - but never on disk


The result, of course, is that those values must be accessed in each scripting language individually by accessing the environment variables (which should be possible for all our supported script interpreters, I guess).


What do you think?


Regards,
Stefan


Hi,


Indeed, I didn't consider the need to have uniformity in the process between all scripting languages.


Your idea of using environment variables will correct :

  • Allow all characters to be used, including the ' (single quotation mark)
  • No more warnings when resolving tokens
  • Simplify the generation of command tasks and task sequences with tokens

There's still the security's question: using environment variables isn't as good as SecureString in PowerShell, but it's already better than it is at present (plain text in a *.ps1 file + plain text in RAM). It's probably a good compromise between uniformity, maintainability and security.


Are you planning to inject environment variables only into the process scope?


I have a case where unfortunately the script in my dynamic folder takes a long time to run, but I could retrieve the password from the environment variable, convert it to SecureString and replace the contents of the environment variable to limit RAM time. So environment variables come in useful for that too.


For folder dynamics that are directly in JSON, are you also going to provide a mechanism for using environment variables or something equivalent?


Thank you for your consideration.


Regards,

Damien

Hi!


7.3 beta is available here: 

https://www.royalapps.com/go/kb-ts-win-downloadbeta


On the Advanced page in your Dynamic Folder configuration you can now use environment variables as an alternative in your dynamic folder and credential scripts.


Would be great if you can test that feature and provide feedback.


1 person likes this

Hi,

Thank you for implementing this proposal.

I made some tests and here are my remarks:

  • The Dynamic Credential Script continues to replace tokens even when in “Environment variables” mode. (Tested with PowerShell)
  • In the Dynamic Folder advanced menu, help is only displayed if the token handling is on “Environment variables” for the script and credentials, whereas it should also be displayed if only one of the 2 is on “Environment variables”.


In reference to my comments above:

  • All characters are now possible in the password (tested in PowerShell)
  • No more token resolution warning for script (need to be corrected for credentials script)
  • No more difficulties generating command tasks or task sequences with tokens
  • No more plaintext password in a file and it is a very good point (It's still present in RAM)


Regards,

Damien

Hi Damien,


thanks for testing the beta build.


I fixed the issue with the dynamic credential script token replacement when environment variables are used. I also put the information in each box (folder script, credential script) to ensure the info is not easily overlooked.


Try to release the next beta in the next couple of days...


Regards,
Stefan


1 person likes this

I've tested the new beta version 7.03.11022 and everything seems fine. Thanks

Hi Stefan,


  • I found another bug in beta 7.3.11022: if you enter nothing in the text box next to “Token” but press “Add”, a blank line is added to the list of “Tokens”.

image

 


  • How are JSON environment variables implemented?


  • The documentation should provide an example specific to the selected language. For example, in PowerShell give the example “$env:DynFolder_EffectiveUsername” and do the same for other languages. Or at the very least, add a link to a more detailed documentation web page.

image


Regards,

Damien

Hi Damien,


thanks for the feedback once again. I've fixed the issue where empty tokens can be added to the list.


Regarding your other points:

  • What do you mean with "JSON environment variables"? Can you expand on that?
  • I think providing samples for accessing the environment variables is a bit of an overkill. Dynamic folders is considered an expert feature where knowledge about scripting is a pre-requisite. Accessing environment variables in a script shouldn't be an obstacle.


Regards,

Stefan


Hi Stefan,


In the case of dynamic folders with JSON as script interpreter, will there be an environment variable feature?
Just as in PowerShell, some characters can't be used in passwords.
For example, I have this in the "Dynamic Credential Script" :

{
	"Username": "$Target.CustomField3$:$EffectiveUsername$",
	"Password": "$EffectivePassword$"
}

 In this case, it is not possible to include the " character in the password otherwise the JSON is invalid after token replacement.


Regards,

Damien

In theory it should work to just add the $Target.CustomField3$ and $EffectiveUsername$ token in the Advanced page to the token list for the credential script and then you should be able to refer to it using the Dyn_Target_CustomField3 and Dyn_EffectiveUsername environment variable. Doesn't that work for you?


Regards,
Stefan

Hi Stefan,


My question is: how do I call an environment variable in JSON?

In PowerShell, I do: $env:Dyn_EffectiveUsername
But in JSON, I don't know how to do it. I tried :

  • $Dyn_EffectiveUsername
  • $env:Dyn_EffectiveUsername
  • $env.Dyn_EffectiveUsername
  • %Dyn_EffectiveUsername%

but nothing seems to work.

You can't do that in JSON as it's only a simple text output. Your script needs to gather the content of the environment variable and when you create the JSON output using the script, you can put the content of that variable where you need it. I hope this makes sense.

Login or Signup to post a comment