Jenkins + PowerShell - 将 Zip 文件转换为字节,传输字节,然后将字节重建为 Zip
Jenkins + PowerShell - Converting Zip File to Bytes, Transfer Bytes, Then Reconstruct Bytes to Zip
由于这个复杂的问题现在有了可行的解决方案,我想更新它以适应该解决方案,以便其他人可以从中受益。
问题
我正在使用 Jenkins 和 PowerShell 执行一系列操作。其中一项操作是将所有相关日志文件收集并合并到一个相应命名的文件夹中,以将其与原始 machine/server 相关联,将文件夹压缩,以某种方式将其传输回 Jenkins 工作区环境,将压缩文件存储到一个主文件夹,并将所述主文件夹转换为一个工件,稍后可以下载 time/date 进行调试。但是,由于此操作往往涉及两跳交换,因此我遇到了很多限制我执行简单文件传输能力的障碍。所以我转向社区寻求那些希望有更多做这类事情经验的人的帮助。
我执行许多我需要的操作的唯一方法(到目前为止我已经找到)是通过 Invoke-Command
连接到目标机器;然而,没过多久我就开始 运行 撞墙了。其中一堵墙是 Jenkins 和目标机器之间的文件传输问题。我发现,通过创建一个等于调用的命令的对象(例如:$returnMe = Invoke-Command {}
),我能够 return 操作中的对象存储在变量中。这给了我一个可能的解决方案,以解决通过会话 return 将项目发送给 Jenkins 的问题......但现在提出问题:
问题
- 使用 PowerShell,是否可以压缩文件夹,然后转换
将该 zip 文件转换为要传递的对象,然后重建该对象
使用对象内容的 zip 文件?如果是,怎么做?
分辨率:
特别感谢@ArcSet 的帮助,以使其正常工作。
好吧,所以这是极有可能做到的;然而,它需要一系列关键步骤才能实现。这是一个四到五个步骤的过程:
1) 将文件收集到目标文件夹中并压缩文件夹
2) 将 zip 文件转换为可以轻松传输的字节
3)通过一个特殊的自定义对象传递这些字节
4) 解析对象以确保没有多余的字节进入文件。
5) 在 Jenkins
上将字节转换回 zip 文件
下面是显示这是如何实现的代码(带注释):
# Parse Through Each Server One By One
ForEach ($server in $servers) {
# Create a Variable to Take in the Invoke-Command and Receive what is Returned
$packet = Invoke-Command -ComputerName $server -ArgumentList $server -Credential $creds -ScriptBlock {
# Function for Creating a Zip File
Function Create-ZipFromFolder ([string]$Source, [string]$SaveAs) {
Add-Type -Assembly "System.IO.Compression.FileSystem"
[IO.Compression.ZipFile]::CreateFromDirectory($Source, $SaveAs)
}
# Function for Converting Zip to Bytes For File Transfer
Function Get-BytesFromFile($Path) {
return [System.IO.File]::ReadAllBytes($Path)
}
# Absorb and Maske Server IP for the Server to Use For Logging Purposes and FileNaming
$maskedAddress = $args[0] -Replace ('.+(?=\.\d+$)', 'XX.XX.XX')
# Construct the Path For Consolidated Log Files
$masterLogFolderPath = ("C:\Logs\RemoteLogs$maskedAddress")
# Series of Code to Create Log Folder, Consolidate Files, And Delete Unnecessary Data For Cleanup
# Establish what to Save the Zip As. You Will Want The Path Included to Prevent it From Finding Path of Least Resistance Upon Saving
$zipFile = ($masterLogFolderPath + ".zip")
Try {
# Here is Where We Call Our Compression Function
Create-ZipFromFolder -Source $masterLogFolderPath -SaveAs ZipFile
# Next We Convert the Zip to Bytes
[byte[]]$FileAsBytes = Get-BytesFromFile -Path $zipFile
}
Catch {
Write-Error $_.Exception.Message
}
# Now We Return the New Object to Jenkins
return New-Object -TypeName PSCustomObject -Property @{Response=$FileAsBytes}
}
# Function to Convert the Bytes Back Into a Zip File
Function Create-FileFromBytes([byte[]]$Bytes, [string]$SaveAs) {
# It was Discovered that Depending Upon the Environment, Extra Bytes Were Sometimes Added
# These Next Lines Will Help to Remove Those
For (($k = 0), ($kill = 0); $kill -lt 1; $k++) {
If ($Bytes[$k] -gt 0) {
$kill = 1
# Truncate the Excess Bytes
$newByteArray = ($Bytes)[$k..(($Bytes).Length -1)]
}
}
# Reconstruct the Zip File
[System.IO.File]::WriteAllBytes($SaveAs, $NewByteArray)
}
Try {
# Call the Function to Begin Reconstruction
Create-FileFromBytes -SaveAs "$env:Workspace\MasterLog$maskedAddress.zip" -Bytes $packet.response
}
Catch {
Write-Error $_.Exception.Message
}
现在这只是一个基本骨架,没有所有沉重的东西,但这些是将所有东西组合在一起的关键部分。在大多数情况下,遵循此公式将 return 获得所需的结果。我希望这可以帮助其他遇到类似情况的人。
再次感谢大家的帮助
因此,首先您需要创建一个 zip 文件。
您需要先使用 add-type 加载程序集系统。
使用 CreateFromDirectory 方法构建并保存 zip 文件。
使用 System.IO.File class 从 zip 中读取所有字节。此时您可以将此数据发送到另一台计算机。最后使用 System.IO.File class 将字节数组转回文件
function Create-ZipFromFrolder([string]$Source,[string]$SaveAs){
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($Source, $SaveAs)
return $SaveAs
}
function Get-BytesFromFile([string]$File){
return [byte[]]$ZipFileBytes = [System.IO.File]::ReadAllBytes($File)
}
function Create-FileFromBytes([byte[]]$Bytes, [string]$SaveAs){
return [System.IO.File]::WriteAllBytes($SaveAs, $Bytes)
}
[byte[]]$FileAsBytes = Get-BytesFromFile -File (Create-ZipFromFrolder -Source "C:\ZipFolder" -SaveAs "C:\Test\test.zip")
Create-FileFromBytes -SaveAs "C:\ZipFolder\Test.zip" -Bytes $FileAsBytes
由于这个复杂的问题现在有了可行的解决方案,我想更新它以适应该解决方案,以便其他人可以从中受益。
问题
我正在使用 Jenkins 和 PowerShell 执行一系列操作。其中一项操作是将所有相关日志文件收集并合并到一个相应命名的文件夹中,以将其与原始 machine/server 相关联,将文件夹压缩,以某种方式将其传输回 Jenkins 工作区环境,将压缩文件存储到一个主文件夹,并将所述主文件夹转换为一个工件,稍后可以下载 time/date 进行调试。但是,由于此操作往往涉及两跳交换,因此我遇到了很多限制我执行简单文件传输能力的障碍。所以我转向社区寻求那些希望有更多做这类事情经验的人的帮助。
我执行许多我需要的操作的唯一方法(到目前为止我已经找到)是通过 Invoke-Command
连接到目标机器;然而,没过多久我就开始 运行 撞墙了。其中一堵墙是 Jenkins 和目标机器之间的文件传输问题。我发现,通过创建一个等于调用的命令的对象(例如:$returnMe = Invoke-Command {}
),我能够 return 操作中的对象存储在变量中。这给了我一个可能的解决方案,以解决通过会话 return 将项目发送给 Jenkins 的问题......但现在提出问题:
问题
- 使用 PowerShell,是否可以压缩文件夹,然后转换 将该 zip 文件转换为要传递的对象,然后重建该对象 使用对象内容的 zip 文件?如果是,怎么做?
分辨率:
特别感谢@ArcSet 的帮助,以使其正常工作。
好吧,所以这是极有可能做到的;然而,它需要一系列关键步骤才能实现。这是一个四到五个步骤的过程:
1) 将文件收集到目标文件夹中并压缩文件夹 2) 将 zip 文件转换为可以轻松传输的字节 3)通过一个特殊的自定义对象传递这些字节 4) 解析对象以确保没有多余的字节进入文件。 5) 在 Jenkins
上将字节转换回 zip 文件下面是显示这是如何实现的代码(带注释):
# Parse Through Each Server One By One
ForEach ($server in $servers) {
# Create a Variable to Take in the Invoke-Command and Receive what is Returned
$packet = Invoke-Command -ComputerName $server -ArgumentList $server -Credential $creds -ScriptBlock {
# Function for Creating a Zip File
Function Create-ZipFromFolder ([string]$Source, [string]$SaveAs) {
Add-Type -Assembly "System.IO.Compression.FileSystem"
[IO.Compression.ZipFile]::CreateFromDirectory($Source, $SaveAs)
}
# Function for Converting Zip to Bytes For File Transfer
Function Get-BytesFromFile($Path) {
return [System.IO.File]::ReadAllBytes($Path)
}
# Absorb and Maske Server IP for the Server to Use For Logging Purposes and FileNaming
$maskedAddress = $args[0] -Replace ('.+(?=\.\d+$)', 'XX.XX.XX')
# Construct the Path For Consolidated Log Files
$masterLogFolderPath = ("C:\Logs\RemoteLogs$maskedAddress")
# Series of Code to Create Log Folder, Consolidate Files, And Delete Unnecessary Data For Cleanup
# Establish what to Save the Zip As. You Will Want The Path Included to Prevent it From Finding Path of Least Resistance Upon Saving
$zipFile = ($masterLogFolderPath + ".zip")
Try {
# Here is Where We Call Our Compression Function
Create-ZipFromFolder -Source $masterLogFolderPath -SaveAs ZipFile
# Next We Convert the Zip to Bytes
[byte[]]$FileAsBytes = Get-BytesFromFile -Path $zipFile
}
Catch {
Write-Error $_.Exception.Message
}
# Now We Return the New Object to Jenkins
return New-Object -TypeName PSCustomObject -Property @{Response=$FileAsBytes}
}
# Function to Convert the Bytes Back Into a Zip File
Function Create-FileFromBytes([byte[]]$Bytes, [string]$SaveAs) {
# It was Discovered that Depending Upon the Environment, Extra Bytes Were Sometimes Added
# These Next Lines Will Help to Remove Those
For (($k = 0), ($kill = 0); $kill -lt 1; $k++) {
If ($Bytes[$k] -gt 0) {
$kill = 1
# Truncate the Excess Bytes
$newByteArray = ($Bytes)[$k..(($Bytes).Length -1)]
}
}
# Reconstruct the Zip File
[System.IO.File]::WriteAllBytes($SaveAs, $NewByteArray)
}
Try {
# Call the Function to Begin Reconstruction
Create-FileFromBytes -SaveAs "$env:Workspace\MasterLog$maskedAddress.zip" -Bytes $packet.response
}
Catch {
Write-Error $_.Exception.Message
}
现在这只是一个基本骨架,没有所有沉重的东西,但这些是将所有东西组合在一起的关键部分。在大多数情况下,遵循此公式将 return 获得所需的结果。我希望这可以帮助其他遇到类似情况的人。
再次感谢大家的帮助
因此,首先您需要创建一个 zip 文件。 您需要先使用 add-type 加载程序集系统。 使用 CreateFromDirectory 方法构建并保存 zip 文件。 使用 System.IO.File class 从 zip 中读取所有字节。此时您可以将此数据发送到另一台计算机。最后使用 System.IO.File class 将字节数组转回文件
function Create-ZipFromFrolder([string]$Source,[string]$SaveAs){
Add-Type -assembly "system.io.compression.filesystem"
[io.compression.zipfile]::CreateFromDirectory($Source, $SaveAs)
return $SaveAs
}
function Get-BytesFromFile([string]$File){
return [byte[]]$ZipFileBytes = [System.IO.File]::ReadAllBytes($File)
}
function Create-FileFromBytes([byte[]]$Bytes, [string]$SaveAs){
return [System.IO.File]::WriteAllBytes($SaveAs, $Bytes)
}
[byte[]]$FileAsBytes = Get-BytesFromFile -File (Create-ZipFromFrolder -Source "C:\ZipFolder" -SaveAs "C:\Test\test.zip")
Create-FileFromBytes -SaveAs "C:\ZipFolder\Test.zip" -Bytes $FileAsBytes