![](/img/trans.png)
[英]How do I call New-Object for a constructor which takes a single array parameter?
[英]How can I use the New-Object cmdlet in a PowerShell script when my constructor takes in a large array of bytes?
我正在编写一个 PowerShell 函数/脚本(使用 Windows 10 附带的版本,我相信它是 5.0)以接收 GZip 压缩的 Base64 字符串并解压缩它,然后在假设原始未压缩/解码字符串是Unicode 编码。
我正在尝试使用此构造函数和 New-Object cmdlet 实例化 MemoryStream 类型的新 object 实例。 它有一个参数,即一个字节数组。
PowerShell 无法找到接受我试图作为构造函数参数传递的字节数组的有效重载。 我认为问题是由于数组的长度相对较大。 请在下面查看我的代码:
Function DecompressString()
{
param([parameter(Mandatory)][string]$TextToDecompress)
try
{
$bytes = [Convert]::FromBase64String($TextToDecompress)
$srcStreamParameters = @{
TypeName = 'System.IO.MemoryStream'
ArgumentList = ([byte[]]$bytes)
}
$srcStream = New-Object @srcStreamParameters
$dstStream = New-Object -TypeName System.IO.MemoryStream
$gzipParameters = @{
TypeName = 'System.IO.Compression.GZipStream'
ArgumentList = ([System.IO.Stream]$srcStream, [System.IO.Compression.CompressionMode]::Decompress)
}
$gzip = New-Object @gzipParameters
$gzip.CopyTo($dstStream)
$output = [Text.Encoding]::Unicode.GetString($dstStream.ToArray())
Write-Output $output
}
catch
{
Write-Host "$_" -ForegroundColor Red
}
finally
{
if ($gzip -ne $null) { $gzip.Dispose() }
if ($srcStream -ne $null) { $srcStream.Dispose() }
if ($dstStream -ne $null) { $dstStream.Dispose() }
}
}
DecompressString
$ExitPrompt = Read-Host -Prompt 'Press Enter to Exit'
我收到的错误消息是: Cannot find an overload for "MemoryStream" and the argument count: "1764".
谁能阐明我如何让脚本解释器正确使用带有大字节数组的构造函数?
我想我会分享这个问题的答案,我发现这个问题非常有趣, Lance U. Matthews在他的有用评论中已经提供了错误的解决方案,方法是在分配给New-Object
的ArgumentList
的$bytes
之前添加一元运算,
New-Object
,通过这样做, $bytes
作为单个参数(字节数组)而不是作为单个元素传递给System.IO.MemoryStream
的构造函数:
$bytes = [Convert]::FromBase64String($compressedString)
$srcStreamParameters = @{
TypeName = 'System.IO.MemoryStream'
ArgumentList = , $bytes
}
$srcStream = New-Object @srcStreamParameters
从PowerShell 5.0开始,您可以使用以下语法构建您的 memory stream,这更加高效和直接:
$srcStream = [System.IO.MemoryStream]::new($bytes)
至于功能(压缩和扩展),我想分享我对这些很酷的功能的看法。
-Encoding
参数,需要using
语句和ArgumentCompleter
。using namespace System.Text
using namespace System.IO
using namespace System.IO.Compression
using namespace System.Collections
using namespace System.Management.Automation
using namespace System.Collections.Generic
using namespace System.Management.Automation.Language
Add-Type -AssemblyName System.IO.Compression
class EncodingCompleter : IArgumentCompleter {
[IEnumerable[CompletionResult]] CompleteArgument (
[string] $commandName,
[string] $parameterName,
[string] $wordToComplete,
[CommandAst] $commandAst,
[IDictionary] $fakeBoundParameters
) {
[CompletionResult[]] $arguments = foreach($enc in [Encoding]::GetEncodings().Name) {
if($enc.StartsWith($wordToComplete)) {
[CompletionResult]::new($enc)
}
}
return $arguments
}
}
function Compress-GzipString {
[cmdletbinding()]
param(
[Parameter(Mandatory, ValueFromPipeline)]
[string] $String,
[Parameter()]
[ArgumentCompleter([EncodingCompleter])]
[string] $Encoding = 'utf-8',
[Parameter()]
[CompressionLevel] $CompressionLevel = 'Optimal'
)
try {
$enc = [Encoding]::GetEncoding($Encoding)
$outStream = [MemoryStream]::new()
$gzip = [GZipStream]::new($outStream, [CompressionMode]::Compress, $CompressionLevel)
$inStream = [MemoryStream]::new($enc.GetBytes($string))
$inStream.CopyTo($gzip)
}
catch {
$PSCmdlet.WriteError($_)
}
finally {
$gzip, $outStream, $inStream | ForEach-Object Dispose
}
try {
[Convert]::ToBase64String($outStream.ToArray())
}
catch {
$PSCmdlet.WriteError($_)
}
}
function Expand-GzipString {
[cmdletbinding()]
param(
[Parameter(Mandatory, ValueFromPipeline)]
[string] $String,
[Parameter()]
[ArgumentCompleter([EncodingCompleter])]
[string] $Encoding = 'utf-8'
)
try {
$enc = [Encoding]::GetEncoding($Encoding)
$bytes = [Convert]::FromBase64String($String)
$outStream = [MemoryStream]::new()
$inStream = [MemoryStream]::new($bytes)
$gzip = [GZipStream]::new($inStream, [CompressionMode]::Decompress)
$gzip.CopyTo($outStream)
$enc.GetString($outStream.ToArray())
}
catch {
$PSCmdlet.WriteError($_)
}
finally {
$gzip, $outStream, $inStream | ForEach-Object Dispose
}
}
对于小长度比较,查询Loripsum API :
$loremIp = Invoke-RestMethod loripsum.net/api/10/long
$compressedLoremIp = Compress-GzipString $loremIp
$loremIp, $compressedLoremIp | Select-Object Length
Length
------
8353
4940
(Expand-GzipString $compressedLoremIp) -eq $loremIp # => Should be True
这两个函数以及从文件路径压缩和从文件路径扩展都可以在这个 repo上找到。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.