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 :
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.
Hi,
Thank you for implementing this proposal.
I made some tests and here are my remarks:
In reference to my comments above:
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
I've tested the new beta version 7.03.11022 and everything seems fine. Thanks
Hi Stefan,
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:
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 :
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.
Damien
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