![](/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.