Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public class ExperimentalFeature
internal const string EngineSource = "PSEngine";
internal const string PSSerializeJSONLongEnumAsNumber = nameof(PSSerializeJSONLongEnumAsNumber);
internal const string PSProfileDSCResource = "PSProfileDSCResource";
internal const string PSProcessPathAutomaticVariable = "PSProcessPathAutomaticVariable";

#endregion

Expand Down Expand Up @@ -114,6 +115,10 @@ static ExperimentalFeature()
new ExperimentalFeature(
name: PSProfileDSCResource,
description: "DSC v3 resources for managing PowerShell profile."
),
new ExperimentalFeature(
name: PSProcessPathAutomaticVariable,
description: "Adds the $PSProcessPath automatic variable containing the path to the current PowerShell process executable."
)
};

Expand Down
15 changes: 9 additions & 6 deletions src/System.Management.Automation/engine/SessionState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -377,12 +377,15 @@ internal void InitializeFixedVariables()
RunspaceInit.EnabledExperimentalFeatures);
this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);

// $PSProcessPath
v = new PSVariable(SpecialVariables.PSProcessPath,
Environment.ProcessPath,
ScopedItemOptions.Constant | ScopedItemOptions.AllScope,
RunspaceInit.PSProcessPathDescription);
this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);
// $PSProcessPath - only registered when the experimental feature is enabled
if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSProcessPathAutomaticVariable))
{
v = new PSVariable(SpecialVariables.PSProcessPath,
Environment.ProcessPath,
ScopedItemOptions.Constant | ScopedItemOptions.AllScope,
RunspaceInit.PSProcessPathDescription);
this.GlobalScope.SetVariable(v.Name, v, asValue: false, force: true, this, CommandOrigin.Internal, fastPath: true);
}
}

/// <summary>
Expand Down
43 changes: 43 additions & 0 deletions test/powershell/Language/Parser/AutomaticVariables.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -22,28 +22,71 @@ Describe 'Automatic variable $input' -Tags "CI" {
}

Describe 'Automatic variable $PSProcessPath' -Tags "CI" {
BeforeAll {
$script:psProcessPathFeatureEnabled = $EnabledExperimentalFeatures.Contains('PSProcessPathAutomaticVariable')
$script:psProcessPathSkipMessage = "The experimental feature 'PSProcessPathAutomaticVariable' must be enabled to use `$PSProcessPath."
}

It '$PSProcessPath should return a non-empty string' {
if (-not $script:psProcessPathFeatureEnabled) {
Set-ItResult -Skipped -Because $script:psProcessPathSkipMessage
return
}
$PSProcessPath | Should -Not -BeNullOrEmpty
}

It '$PSProcessPath should be a string' {
if (-not $script:psProcessPathFeatureEnabled) {
Set-ItResult -Skipped -Because $script:psProcessPathSkipMessage
return
}
$PSProcessPath | Should -BeOfType [string]
}

It '$PSProcessPath should point to an existing file' {
if (-not $script:psProcessPathFeatureEnabled) {
Set-ItResult -Skipped -Because $script:psProcessPathSkipMessage
return
}
Test-Path -LiteralPath $PSProcessPath -PathType Leaf | Should -BeTrue
}

It '$PSProcessPath should be a constant variable' {
if (-not $script:psProcessPathFeatureEnabled) {
Set-ItResult -Skipped -Because $script:psProcessPathSkipMessage
return
}
$var = Get-Variable -Name PSProcessPath
$var.Options | Should -Match 'Constant'
}

It '$PSProcessPath should be read-only (cannot be overwritten)' {
if (-not $script:psProcessPathFeatureEnabled) {
Set-ItResult -Skipped -Because $script:psProcessPathSkipMessage
return
}
{ $PSProcessPath = 'something' } | Should -Throw
}

It '$PSProcessPath should match the current process path' {
if (-not $script:psProcessPathFeatureEnabled) {
Set-ItResult -Skipped -Because $script:psProcessPathSkipMessage
return
}
$PSProcessPath | Should -Be ([System.Environment]::ProcessPath)
}
}

Describe 'Automatic variable $PSProcessPath - feature disabled' -Tags "CI" {
BeforeAll {
$script:psProcessPathFeatureEnabled = $EnabledExperimentalFeatures.Contains('PSProcessPathAutomaticVariable')
}

It '$PSProcessPath should not exist when experimental feature is disabled' {
if ($script:psProcessPathFeatureEnabled) {
Set-ItResult -Skipped -Because "The experimental feature 'PSProcessPathAutomaticVariable' is enabled; test requires the feature to be disabled."
return
}
{ Get-Variable -Name PSProcessPath -ErrorAction Stop } | Should -Throw
}
}