diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs index 9195e49052..53dc461dfb 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImportPowerShellDataFile.cs @@ -39,6 +39,13 @@ namespace Microsoft.PowerShell.Commands set { _isLiteralPath = true; Path = value; } } + /// + /// Gets or sets switch that determines if built-in limits are applied to the data. + /// + [Experimental("Microsoft.PowerShell.Utility.PSImportPSDataFileSkipLimitCheck", ExperimentAction.Show)] + [Parameter] + public SwitchParameter SkipLimitCheck { get; set; } + /// /// For each path, resolve it, parse it and write all hashtables to the output stream. /// @@ -61,7 +68,7 @@ namespace Microsoft.PowerShell.Commands var data = ast.Find(a => a is HashtableAst, false); if (data != null) { - WriteObject(data.SafeGetValue()); + WriteObject(data.SafeGetValue(SkipLimitCheck)); } else { diff --git a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 index 1ef5f3328e..b883acdd0d 100644 --- a/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 +++ b/src/Modules/Unix/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 @@ -38,6 +38,10 @@ PrivateData = @{ Name = 'Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace' Description = 'Enables -BreakAll parameter on Debug-Runspace and Debug-Job cmdlets to allow users to decide if they want PowerShell to break immediately in the current location when they attach a debugger. Enables -Runspace parameter on *-PSBreakpoint cmdlets to support management of breakpoints in another runspace.' } + @{ + Name = 'Microsoft.PowerShell.Utility.PSImportPSDataFileSkipLimitCheck' + Description = 'Enable -SkipLimitCheck switch for Import-PowerShellDataFile to not enforce built-in hashtable limits' + } ) } } diff --git a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 index 3b401f039e..5ea504197f 100644 --- a/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 +++ b/src/Modules/Windows/Microsoft.PowerShell.Utility/Microsoft.PowerShell.Utility.psd1 @@ -37,6 +37,10 @@ PrivateData = @{ Name = 'Microsoft.PowerShell.Utility.PSManageBreakpointsInRunspace' Description = 'Enables -BreakAll parameter on Debug-Runspace and Debug-Job cmdlets to allow users to decide if they want PowerShell to break immediately in the current location when they attach a debugger. Enables -Runspace parameter on *-PSBreakpoint cmdlets to support management of breakpoints in another runspace.' } + @{ + Name = 'Microsoft.PowerShell.Utility.PSImportPSDataFileSkipLimitCheck' + Description = 'Enable -NoLimit switch for Import-PowerShellDataFile to not enforce built-in hashtable limits' + } ) } } diff --git a/src/System.Management.Automation/engine/parser/SafeValues.cs b/src/System.Management.Automation/engine/parser/SafeValues.cs index d7ef5b4cae..a727ae1d28 100644 --- a/src/System.Management.Automation/engine/parser/SafeValues.cs +++ b/src/System.Management.Automation/engine/parser/SafeValues.cs @@ -362,7 +362,8 @@ namespace System.Management.Automation.Language { Default, GetPowerShell, - ModuleAnalysis + ModuleAnalysis, + SkipHashtableSizeCheck, } // future proofing @@ -371,7 +372,8 @@ namespace System.Management.Automation.Language public static object GetSafeValue(Ast ast, ExecutionContext context, SafeValueContext safeValueContext) { t_context = context; - if (IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) + + if (safeValueContext == SafeValueContext.SkipHashtableSizeCheck || IsSafeValueVisitor.IsAstSafe(ast, safeValueContext)) { return ast.Accept(new GetSafeValueVisitor()); } diff --git a/src/System.Management.Automation/engine/parser/ast.cs b/src/System.Management.Automation/engine/parser/ast.cs index b9404afa73..e99fd1001c 100644 --- a/src/System.Management.Automation/engine/parser/ast.cs +++ b/src/System.Management.Automation/engine/parser/ast.cs @@ -198,6 +198,19 @@ namespace System.Management.Automation.Language /// If is deemed unsafe /// public object SafeGetValue() + { + return SafeGetValue(skipHashtableSizeCheck: false); + } + + /// + /// Constructs the resultant object from the AST and returns it if it is safe. + /// + /// Set to skip hashtable limit validation. + /// The object represented by the AST as a safe object. + /// + /// If is deemed unsafe. + /// + public object SafeGetValue(bool skipHashtableSizeCheck) { try { @@ -207,7 +220,7 @@ namespace System.Management.Automation.Language context = System.Management.Automation.Runspaces.Runspace.DefaultRunspace.ExecutionContext; } - return GetSafeValueVisitor.GetSafeValue(this, context, GetSafeValueVisitor.SafeValueContext.Default); + return GetSafeValueVisitor.GetSafeValue(this, context, skipHashtableSizeCheck ? GetSafeValueVisitor.SafeValueContext.SkipHashtableSizeCheck : GetSafeValueVisitor.SafeValueContext.Default); } catch { diff --git a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 index 6d13be5005..222bbf7e90 100644 --- a/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 +++ b/test/powershell/Modules/Microsoft.PowerShell.Utility/PowerShellData.tests.ps1 @@ -1,6 +1,19 @@ # Copyright (c) Microsoft Corporation. # Licensed under the MIT License. Describe "Tests for the Import-PowerShellDataFile cmdlet" -Tags "CI" { + BeforeAll { + $largePsd1Path = Join-Path -Path $TestDrive -ChildPath 'large.psd1' + $largePsd1Builder = [System.Text.StringBuilder]::new('@{') + 1..501 | ForEach-Object { + $largePsd1Builder.Append("key$_ = $_;") + } + $largePsd1Builder.Append('}') + Set-Content -Path $largePsd1Path -Value $largePsd1Builder.ToString() + + if ((Get-ExperimentalFeature Microsoft.PowerShell.Utility.PSImportPSDataFileSkipLimitCheck).Enabled -ne $true) { + $skipTest = $true + } + } It "Validates error on a missing path" { { Import-PowerShellDataFile -Path /SomeMissingDirectory -ErrorAction Stop } | @@ -32,4 +45,12 @@ Describe "Tests for the Import-PowerShellDataFile cmdlet" -Tags "CI" { $result.Hello | Should -BeExactly "World" } + It 'Fails if psd1 file has more than 500 keys' { + { Import-PowerShellDataFile $largePsd1Path } | Should -Throw -ErrorId 'System.InvalidOperationException,Microsoft.PowerShell.Commands.ImportPowerShellDataFileCommand' + } + + It 'Succeeds if -NoLimit is used and has more than 500 keys' -Skip:$skipTest { + $result = Import-PowerShellDataFile $largePsd1Path -SkipLimitCheck + $result.Keys.Count | Should -Be 501 + } }