I am uploading zip file using .NET Core application and pass it as a string parameter to PowerShell script and trying to use following command for copy
Invoke-Command -Session $Session -ScriptBlock { Param($uplodedZipFileAsString,$DestinationFilePath) New-Item -Path $DestinationFilePath -Value $uplodedZipFileAsString -Force } -ArgumentList ($uplodedZipFileAsString, $DestinationFilePath)
using above command file is copied at destination location, but while tried to unzip it. it gives an error as
The Compressed (zipped) Folder 'DestPath\uplodedZipFile.zip' is invalid.
Question :-
- How can copy zip file(passed as string parameter) to remote server?
- What are the best practices should follows in this scenario?
Note:- Assume that in above PowerShell command all parameters like $Session,$uplodedZipeFileAsString and $DestinationFolderFilePath are properly provided.
Edited:-
High level code details as follows
In .NET Core using file upload control we get IFormFile file(argument name) as parameter method looks as follows
public async Task<IActionResult> Index(IFormFile file)
{
// following method convert FileStream To Sting
string fileString = ConvertFileStreamToString(file); // this is zip as string
//following method execute powershell script
PowerShellHelper(string fileString,... other paramter)
//Other Code...
}
private string ConvertFileStreamToString(IFormFile file)
{
var fileString = new StringBuilder();
using (var reader = new StreamReader(file.OpenReadStream()))
{
while (reader.Peek() >= 0)
fileString.AppendLine(reader.ReadLine());
}
return fileString.ToString();
}
PowerShell as follows
function zipcopyfunction
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true,
Position=0,
HelpMessage='Please Provide Zip File')]
[ValidateNotNullOrEmpty()]
[string]$uplodedZipFileAsString,
#other necessary paramters goes here...
)
#Other code related to session creation
try
{
#other code including destination file path(DestinationFilePath) and $Session...
$DestinationFilePath = "C:\test\destFile.zip"
Invoke-Command -Session $Session -ScriptBlock { Param($uplodedZipFileAsString,$DestinationFilePath) New-Item -Path $DestinationFilePath -Value $uplodedZipFileAsString -Force } -ArgumentList ($uplodedZipFileAsString, $DestinationFilePath)
#remove session related code...
}
catch
{
Throw $_.exception.message
}
}
CodePudding user response:
As commented, don't try to read a binary file as if it were a text file.
Instead, read the file as an array of bytes ([Byte[]]
) to get the actual file content unaltered. Then you could change your code to do this:
# use the full, absolute filepaths as we're using .Net methods
$sourceFile = 'D:\somewhere\TheFile.zip'
# the path (in this demo 'D:\Test') MUST exist locally in the remote machine
$destination = 'D:\Test\TheFile.zip'
# read the file as an array of Bytes
[byte[]]$bytes = [System.IO.File]::ReadAllBytes($sourceFile)
Invoke-Command -Session $Session -ScriptBlock {
Param(
[byte[]]$ZipBytes,
[string]$DestinationFilePath
)
[System.IO.File]::WriteAllBytes($DestinationFilePath, $ZipBytes)
} -ArgumentList @($bytes ,$destination)
You could convert the binary data into a string, by converting the data to Base64 for instance using [Convert]::ToBase64String($bytes)
but then in the scriptblock you will first need to convert that string back to bytes using [byte[]]$bytes = [Convert]::FromBase64String($uplodedZipFileAsString)
and then write to file. This of course will use more processing time and the data you will be sending wil become much larger than the original number of bytes.