Support non-script based file configuration of options
Relying on profile.ps1 may not fit scenarios where we want to set-executionpolicy to ban scripts.
Would it be possible to populate options from the registry or json file? I would image modifying PSConsoleReadlineOptions is all that it takes?
I'm definitely open to the idea.
Now that PSReadLine is portable to Mac/Linux, we should avoid the registry.
If this is implemented, my priorities are:
- Be portable between:
- Windows/Non-Windows
- Full CLR/Core CLR
- Avoid new dependencies, e.g. don't require shipping
Newtonsoft.Json- Helps avoid introducing versioning problems w/ popular nuget packages
- Helps simplify bringing this feature back into Windows
I think this rules out json and probably yaml (writing yet another parser is usually not a good idea.)
When I originally considered the problem of configuration, I settled on script because I hated xml. I still hate xml, but it might be the simplest option.
Maybe a better (but more complicated option) - use script, but don't execute it, instead interpret the Ast. You couldn't use arbitrary script, e.g. you could only call Set-PSReadLIneOption and Set-PSReadLineKeyHandler, pass only constants, no variables except perhaps reading environment variables, etc. It would be similar to the PowerShell data language (psd1 files) - so maybe we would just check for the file PSReadLineConfig.psd1 in the same directory as the user profile or something like that.
wow that sounds great. I am happy to work on this feature if you like
Or we can use a real script PSReadLine.profile.ps1 and "invoke" it by reading, creating a script block and invoking it. This bypasses the execution policy.
Invoking wouldn't work in restricted language mode.
I don't know. Why insist on a script when all we want to do is something simple? For my case, I just customized HKCU:\Console\ColorTable## to solarized and can't see anything dark gray with the default PSReadLine options. All I want to do is set parameter color to something that is not dark gray!
I thought OP was talking about execution policy. It does not imply restricted language mode, it just does not allow invoke script directly. But they still may be invoked in many ways.
@imacks The script approach has some advantages. Personally, I would prefer it regardless of the execution policy, at least to make my usual profile cleaner.
@nightroman i don’t see a problem with script or xml or whatnot, so long as we can keep it as a simple way to change the defaults. I mean, the profile is always there.
@nightroman - PSReadLine has extra security concerns that other modules might not when it ships with Windows, so I need to avoid exposing potentially exploitable holes.
That said, there is a way to invoke the script without violating the machine lockdown policy.
@imacks - thanks for offering to implement this. I think the script solution is better than xml because:
- it should be less code
- script blocks in xml can be painful if you need to escape anything
- nobody wants xml :)
We'll need code similar to the following to invoke the configuration script block and not create a security hole.
var origLanguageMode = runspace.LanguageMode;
try {
if (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Enforce)
{
runspace.LanguageMode = PSLanguageMode.ConstrainedLanguage;
}
scriptBlock.Invoke();
} finally {
runspace.LanguageMode = origLanguageMode;
}
So... it is a file. What options are in there?
Here's what I can think of (convertfrom-stringdata styled capable of handling env variables)
EditMode = default
ContinuationPrompt = >>>
ContinuationPromptColor = green
ExtraPromptLineCount = default
# AddToHistoryHandler = null
HistoryNoDuplicates = default
MaximumHistoryCount = default
MaximumKillRingCount = default
HistorySearchCursorMovesToEnd = default
ShowToolTips = true
DingDuration = 15
DingTone = default
BellStyle = default
CompletionQueryItems = default
WordDelimiters = default
HistorySearchCaseSensitive = default
HistorySaveStyle = default
AnsiEscapeTimeout = default
HistorySavePath = ${env:userprofile}/.history.log
CommentColor =DarkGreen
KeywordColor = Green
StringColor = DarkCyan
OperatorColor = DarkGray
VariableColor = Green
CommandColor = Yellow
ParameterColor = DarkGray
TypeColor = Gray
NumberColor = White
MemberColor = Gray
EmphasisColor = Cyan
ErrorColor = Red
Oh, @nightroman was just suggesting you still use a ps1 file like you would today, but PSReadLine would invoke it in a way that is not affected by the execution policy.
I use the following pattern in my profile to make it feel more like a configuration and less like calling a bunch of commands:
$options =
@{
PromptText = '> '
AddToHistoryHandler = {
param([string]$line)
return $line.Length -gt 3 -and $line[0] -ne ' ' -and $line[0] -ne ';'
}
HistorySavePath = "${env:HOMEDRIVE}${env:HOMEPATH}/PSReadLine_history.txt"
EditMode = 'Emacs'
ExtraPromptLineCount = 1
Colors = @{
Error = "$([char](0x1b))[44;91m"
}
}
Set-PSReadLineOption @options
I suppose one option is to mimic the module manifest, basically remove the first and last lines in my example above, then apply the options. This would also need to allow specifying key bindings, maybe like:
@{
KeyBindings = @{
UpArrow = 'HistorySearchBackward'
DownArrow = 'HistorySearchForward'
'Alt+F1' = @{
BriefDescription = 'CommandHelp'
LongDescription = 'Open the help window for the current command'
ScriptBlock = { ... }
}
}
}
There's precedent for this kind of configuration data in .psd1 files with DSC as well: https://docs.microsoft.com/en-us/powershell/dsc/separatingenvdata