From f8b9e8e9db88a7f9a385c8e680213934a384f679 Mon Sep 17 00:00:00 2001 From: "James Truher [MSFT]" Date: Mon, 17 Aug 2020 22:19:22 -0700 Subject: [PATCH] Create warnings when UTF7 is specified as an encoding (#13430) --- .../commands/utility/CsvCommands.cs | 32 +++++++++++++++++-- .../FormatAndOutput/format-hex/Format-Hex.cs | 15 ++++++++- .../FormatAndOutput/out-file/Out-File.cs | 16 +++++++++- .../utility/ImplicitRemotingCommands.cs | 16 +++++++++- .../commands/utility/MatchString.cs | 16 +++++++++- .../commands/utility/Send-MailMessage.cs | 16 +++++++++- .../commands/utility/XmlCommands.cs | 16 +++++++++- .../namespaces/FileSystemProvider.cs | 19 +++++++++-- .../resources/PathUtilsStrings.resx | 3 ++ .../utils/EncodingUtils.cs | 19 +++++++++++ .../engine/Basic/Encoding.Tests.ps1 | 26 +++++++++++++++ 11 files changed, 184 insertions(+), 10 deletions(-) diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs index 0372298d7b..dab4a4b334 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/CsvCommands.cs @@ -217,7 +217,21 @@ namespace Microsoft.PowerShell.Commands [ArgumentToEncodingTransformationAttribute] [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] - public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); + public Encoding Encoding + { + get + { + return _encoding; + } + + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = ClrFacade.GetDefaultEncoding(); /// /// Gets or sets property that sets append parameter. @@ -592,7 +606,21 @@ namespace Microsoft.PowerShell.Commands [ArgumentToEncodingTransformationAttribute] [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] - public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); + public Encoding Encoding + { + get + { + return _encoding; + } + + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = ClrFacade.GetDefaultEncoding(); /// /// Avoid writing out duplicate warning messages when there are one or more unspecified names. diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs index a0225c8ea6..d370110b8f 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/format-hex/Format-Hex.cs @@ -71,7 +71,20 @@ namespace Microsoft.PowerShell.Commands [ArgumentToEncodingTransformationAttribute()] [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] - public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); + public Encoding Encoding + { + get + { + return _encoding; + } + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = ClrFacade.GetDefaultEncoding(); /// /// Gets or sets count of bytes to read from the input stream. diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs index f3f84c6da3..9885cbcaa4 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/FormatAndOutput/out-file/Out-File.cs @@ -78,7 +78,21 @@ namespace Microsoft.PowerShell.Commands [ArgumentToEncodingTransformationAttribute()] [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] - public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); + public Encoding Encoding + { + get + { + return _encoding; + } + + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = ClrFacade.GetDefaultEncoding(); /// /// Property that sets append parameter. diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs index feeb0cd091..9198250dd7 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/ImplicitRemotingCommands.cs @@ -76,7 +76,21 @@ namespace Microsoft.PowerShell.Commands [ArgumentToEncodingTransformationAttribute()] [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] - public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); + public Encoding Encoding + { + get + { + return _encoding; + } + + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = ClrFacade.GetDefaultEncoding(); #endregion Parameters diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs index 3a5d4c77a5..667f55e50c 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/MatchString.cs @@ -1349,7 +1349,21 @@ namespace Microsoft.PowerShell.Commands [ArgumentToEncodingTransformationAttribute()] [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] - public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); + public Encoding Encoding + { + get + { + return _encoding; + } + + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = ClrFacade.GetDefaultEncoding(); /// /// Gets or sets the number of context lines to collect. If set to a diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs index 78e65d806a..957c21d465 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Send-MailMessage.cs @@ -63,7 +63,21 @@ namespace Microsoft.PowerShell.Commands [ValidateNotNullOrEmpty] [ArgumentEncodingCompletionsAttribute] [ArgumentToEncodingTransformationAttribute] - public Encoding Encoding { get; set; } = Encoding.ASCII; + public Encoding Encoding + { + get + { + return _encoding; + } + + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = Encoding.ASCII; /// /// Gets or sets the address collection that contains the diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs index 8736965fd6..9d4264b8b1 100644 --- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs +++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/XmlCommands.cs @@ -114,7 +114,21 @@ namespace Microsoft.PowerShell.Commands [ArgumentToEncodingTransformationAttribute()] [ArgumentEncodingCompletionsAttribute] [ValidateNotNullOrEmpty] - public Encoding Encoding { get; set; } = ClrFacade.GetDefaultEncoding(); + public Encoding Encoding + { + get + { + return _encoding; + } + + set + { + EncodingConversion.WarnIfObsolete(this, value); + _encoding = value; + } + } + + private Encoding _encoding = ClrFacade.GetDefaultEncoding(); #endregion Command Line Parameters diff --git a/src/System.Management.Automation/namespaces/FileSystemProvider.cs b/src/System.Management.Automation/namespaces/FileSystemProvider.cs index 6c91b806df..eab04cb6e4 100644 --- a/src/System.Management.Automation/namespaces/FileSystemProvider.cs +++ b/src/System.Management.Automation/namespaces/FileSystemProvider.cs @@ -6744,7 +6744,7 @@ namespace Microsoft.PowerShell.Commands /// public object GetContentReaderDynamicParameters(string path) { - return new FileSystemContentReaderDynamicParameters(); + return new FileSystemContentReaderDynamicParameters(this); } /// @@ -6878,7 +6878,7 @@ namespace Microsoft.PowerShell.Commands /// public object GetContentWriterDynamicParameters(string path) { - return new FileSystemContentWriterDynamicParameters(); + return new FileSystemContentWriterDynamicParameters(this); } /// @@ -7593,6 +7593,13 @@ namespace Microsoft.PowerShell.Commands /// public class FileSystemContentDynamicParametersBase { + internal FileSystemContentDynamicParametersBase(FileSystemProvider provider) + { + _provider = provider; + } + + private FileSystemProvider _provider; + /// /// Gets or sets the encoding method used when /// reading data from the file. @@ -7610,6 +7617,10 @@ namespace Microsoft.PowerShell.Commands set { + if (value == System.Text.Encoding.UTF7) + { + _provider.WriteWarning(PathUtilsStrings.Utf7EncodingObsolete); + } _encoding = value; // If an encoding was explicitly set, be sure to capture that. WasStreamTypeSpecified = true; @@ -7659,6 +7670,8 @@ namespace Microsoft.PowerShell.Commands /// public class FileSystemContentWriterDynamicParameters : FileSystemContentDynamicParametersBase { + internal FileSystemContentWriterDynamicParameters(FileSystemProvider provider) : base(provider) { } + /// /// False to add a newline to the end of the output string, true if not. /// @@ -7684,6 +7697,8 @@ namespace Microsoft.PowerShell.Commands /// public class FileSystemContentReaderDynamicParameters : FileSystemContentDynamicParametersBase { + internal FileSystemContentReaderDynamicParameters(FileSystemProvider provider) : base (provider) { } + /// /// Gets or sets the delimiter to use when reading the file. Custom delimiters /// may not be used when the file is opened with a "Byte" encoding. diff --git a/src/System.Management.Automation/resources/PathUtilsStrings.resx b/src/System.Management.Automation/resources/PathUtilsStrings.resx index 16fb037a4d..217f2522ac 100644 --- a/src/System.Management.Automation/resources/PathUtilsStrings.resx +++ b/src/System.Management.Automation/resources/PathUtilsStrings.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + Encoding 'UTF-7' is obsolete, please use UTF-8. + File {0} already exists and {1} was specified. diff --git a/src/System.Management.Automation/utils/EncodingUtils.cs b/src/System.Management.Automation/utils/EncodingUtils.cs index 8206b5cf8a..6825a259da 100644 --- a/src/System.Management.Automation/utils/EncodingUtils.cs +++ b/src/System.Management.Automation/utils/EncodingUtils.cs @@ -63,6 +63,12 @@ namespace System.Management.Automation Encoding foundEncoding; if (encodingMap.TryGetValue(encoding, out foundEncoding)) { + // Write a warning if using utf7 as it is obsolete in .NET5 + if (string.Compare(encoding, Utf7, StringComparison.OrdinalIgnoreCase) == 0) + { + cmdlet.WriteWarning(PathUtilsStrings.Utf7EncodingObsolete); + } + return foundEncoding; } @@ -81,6 +87,19 @@ namespace System.Management.Automation return null; } + + /// + /// Warn if the encoding has been designated as obsolete. + /// + /// A cmdlet instance which is used to emit the warning. + /// The encoding to check for obsolescence. + internal static void WarnIfObsolete(Cmdlet cmdlet, Encoding encoding) + { + if (encoding == System.Text.Encoding.UTF7) + { + cmdlet.WriteWarning(PathUtilsStrings.Utf7EncodingObsolete); + } + } } /// diff --git a/test/powershell/engine/Basic/Encoding.Tests.ps1 b/test/powershell/engine/Basic/Encoding.Tests.ps1 index 2569f8619b..dc1a0b15ba 100644 --- a/test/powershell/engine/Basic/Encoding.Tests.ps1 +++ b/test/powershell/engine/Basic/Encoding.Tests.ps1 @@ -99,4 +99,30 @@ Describe "File encoding tests" -Tag CI { (Get-Content $testFile -AsByteStream) -join "-" | Should -BeExactly $expectedBytes } } + + Context "Using encoding utf7 results in a warning" { + BeforeAll { + $expectedString = "Encoding 'UTF-7' is obsolete, please use UTF-8." + $testCases = @( + @{ Command = 'Add-Content'; Script = { "test" | Add-Content -Encoding utf7 -Path TESTDRIVE:/file 3>TESTDRIVE:/warning } } + @{ Command = 'Export-CliXml'; Script = { "test" | Export-Clixml -Path TESTDRIVE:/file.ps1xml -Encoding utf7 3>TESTDRIVE:/warning } } + @{ Command = 'Export-Csv'; Script = { "test" | Export-Csv -Path TESTDRIVE:/export.csv -Encoding utf7 3>TESTDRIVE:/warning } } + @{ Command = 'Format-Hex'; Script = { "test" | Format-Hex -Encoding utf7 > TESTDRIVE:/output 3>TESTDRIVE:/warning } } + @{ Command = 'Get-Content'; Script = { "output" > TESTDRIVE:/input; $null = Get-Content -Path TESTDRIVE:/input -Encoding utf7 3>TESTDRIVE:/warning } } + @{ Command = 'Import-Csv'; Script = { "test" | Export-Csv -Path TESTDRIVE:/output.csv; $null = Import-Csv -Path TESTDRIVE:/output.csv -Encoding utf7 3>TESTDRIVE:/warning } } + @{ Command = 'Out-File'; Script = { "test" | Out-File -Path TESTDRIVE:/output.txt -Encoding utf7 3>TESTDRIVE:/warning } } + @{ Command = 'Select-String'; Script = { "aa" | Select-String -pattern bb -Encoding utf7 3>TESTDRIVE:/warning } } + @{ Command = 'Set-Content'; Script = { "aa" | Set-Content -Path TESTDRIVE:/output.txt -Encoding utf7 3>TESTDRIVE:/warning } } + ) + } + BeforeEach { + Remove-Item TESTDRIVE:/* -force -ErrorAction Ignore + } + It "' has a warning when '-Encoding utf7' is used" -TestCases $testCases { + param ($command, $script) + & $script + $observed = Get-Content TESTDRIVE:/warning + $observed | Should -BeExactly $expectedString + } + } }