简体   繁体   English

当我的构造函数接收大量字节时,如何在 PowerShell 脚本中使用 New-Object cmdlet?

[英]How can I use the New-Object cmdlet in a PowerShell script when my constructor takes in a large array of bytes?

I am writing a PowerShell function/script (using the version that ships with Windows 10, which I believe is 5.0) to take in a GZip compressed Base64 string and decompress it, and then decode it under the assumption the original uncompressed/decoded string was Unicode encoded.我正在编写一个 PowerShell 函数/脚本(使用 Windows 10 附带的版本,我相信它是 5.0)以接收 GZip 压缩的 Base64 字符串并解压缩它,然后在假设原始未压缩/解码字符串是Unicode 编码。

I am trying to instantiate a new object instance of type MemoryStream using this constructor and the New-Object cmdlet.我正在尝试使用此构造函数和 New-Object cmdlet 实例化 MemoryStream 类型的新 object 实例。 It takes one parameter, which is an array of bytes.它有一个参数,即一个字节数组。

PowerShell is unable to find a valid overload that accepts the array of bytes I am trying to pass as the constructor's parameter. PowerShell 无法找到接受我试图作为构造函数参数传递的字节数组的有效重载。 I believe the issue is due to the array's relatively large length.我认为问题是由于数组的长度相对较大。 Please see my code below:请在下面查看我的代码:

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'

The error message I get is: Cannot find an overload for "MemoryStream" and the argument count: "1764".我收到的错误消息是: Cannot find an overload for "MemoryStream" and the argument count: "1764".

Can anyone please clarify how I can get the script interpreter to use the constructor correctly with a large byte array?谁能阐明我如何让脚本解释器正确使用带有大字节数组的构造函数?

I thought I would share an answer to this question which I found very interesting, solution to the error has already been provided by Lance U. Matthews in his helpful comment, by adding the unary operator , before the $bytes assigned to the ArgumentList of New-Object , by doing so, the $bytes are passed as a single argument ( array of bytes ) and not as individual elements to the constructor of System.IO.MemoryStream :我想我会分享这个问题的答案,我发现这个问题非常有趣, Lance U. Matthews在他的有用评论中已经提供了错误的解决方案,方法是在分配给New-ObjectArgumentList$bytes之前添加一元运算, New-Object ,通过这样做, $bytes作为单个参数(字节数组)而不是作为单个元素传递给System.IO.MemoryStream的构造函数:

$bytes = [Convert]::FromBase64String($compressedString)
$srcStreamParameters = @{
    TypeName     = 'System.IO.MemoryStream'
    ArgumentList = , $bytes
}

$srcStream = New-Object @srcStreamParameters

Beginning in PowerShell 5.0 and going forward, you can construct your memory stream with the following syntax, which is more efficient and straight forward: PowerShell 5.0开始,您可以使用以下语法构建您的 memory stream,这更加高效和直接:

$srcStream = [System.IO.MemoryStream]::new($bytes)

As for the functions ( Compress & Expand ), I would like to share my take on these cool functions.至于功能(压缩扩展),我想分享我对这些很酷的功能的看法。

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
    }
}
  • Compression from string to Base64 GZip compressed string :字符串压缩到Base64 GZip 压缩字符串
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($_)
    }
}
  • Expansion from Base64 GZip compressed string to string :Base64 GZip 压缩字符串扩展为字符串
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
    }
}

And for the little Length comparison, querying the Loripsum API :对于小长度比较,查询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

These 2 functions as well as Compression From File Path and Expansion from File Path can be found on this repo .这两个函数以及从文件路径压缩和从文件路径扩展都可以在这个 repo上找到。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何为一个采用单个数组参数的构造函数调用New-Object? - How do I call New-Object for a constructor which takes a single array parameter? CodeGo.net>我如何解决我的方法来扫描较大的字节数组以较小的数组 - c# - How Can I Fix My Method To Scan large array of bytes for smaller arrays 我可以使用`obj.constructor === Array`来测试对象是否是数组? - Can I use `obj.constructor === Array` to test if object is Array? Powershell Set-Acl - 错误新对象:找不到“FileSystemAccessRule”的重载和参数计数:“1” - Powershell Set-Acl - Error New-Object : Cannot find an overload for "FileSystemAccessRule" and the argument count: "1" 如何在每种方法中使用对象数组? - How can I use my object array at every method? 如何使用使用JOptionPane的构造函数将对象从我的方法传递到空数组中? - How can i use a constructor using JOptionPane to pass objects from my method into a empty array? 我怎么知道什么时候一个对象已经进入我的数组 - How can I know when a object is already into my array 使用Measure-Object cmdlet在数组中修剪Powershell前导零 - Powershell Leading zeros are trimmed in array using Measure-Object cmdlet 如何使用默认构造函数创建我的类的数组? - How can i create array of my class with default constructor? 为什么我无法访问使用“new Array”构造函数创建的二维数组的 [0][0] position? - Why can't I access the [0][0] position of my 2 dimensional array created with 'new Array' constructor?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM