Recieve files over the current Session

Welcome Forums General PowerShell Q&A Recieve files over the current Session

This topic contains 2 replies, has 2 voices, and was last updated by

 
Participant
2 years, 9 months ago.

  • Author
    Posts
  • #45412

    Participant
    Points: 0
    Rank: Member

    In an effort to continually improve my deployment scripts, I stumbled on a function someone wrote to allow me to push files over WinRM which alleviates me opening additional ports _just_ for installation. It's a nice little function I've start including in my scripts. I attached the code at the bottom for reference.

    That said, some of my installs I need to actually _fetch_ files from the resulting build, not just push files, so I was wondering if I should try to reverse engineer a "Get-File" function or if there was a more "natural" way to use the same logic but in reverse: use the WINRM service to retrieve a file rather than opening additional ports. Has anyone done anything like this? I'm curious as to other people's approach.

    To restate the goal: I'd like to be able to push/pull small simple configs to/from remote systems without having to open the additional file and print sharing ports.

    function Send-File
    {
    	
    	[CmdletBinding()]
    	param
    	(
    		[Parameter(Mandatory)]
    		[ValidateNotNullOrEmpty()]
    		[string[]]$Path,
    		
    		[Parameter(Mandatory)]
    		[ValidateNotNullOrEmpty()]
    		[string]$Destination,
    		
    		[Parameter(Mandatory)]
    		[System.Management.Automation.Runspaces.PSSession]$Session
    	)
    	process
    	{
    		foreach ($p in $Path)
    		{
    			try
    			{
    				if ($p.StartsWith('\\'))
    				{
    					Write-Verbose -Message "[$($p)] is a UNC path. Copying locally first"
    					Copy-Item -Path $p -Destination ([environment]::GetEnvironmentVariable('TEMP', 'Machine'))
    					$p = "$([environment]::GetEnvironmentVariable('TEMP', 'Machine'))\$($p | Split-Path -Leaf)"
    				}
    				if (Test-Path -Path $p -PathType Container)
    				{
    					Write-Log -Source $MyInvocation.MyCommand -Message "[$($p)] is a folder. Sending all files"
    					$files = Get-ChildItem -Path $p -File -Recurse
    					$sendFileParamColl = @()
    					foreach ($file in $Files)
    					{
    						$sendParams = @{
    							'Session' = $Session
    							'Path' = $file.FullName
    						}
    						if ($file.DirectoryName -ne $p) ## It's a subdirectory
    						{
    							$subdirpath = $file.DirectoryName.Replace("$p\", '')
    							$sendParams.Destination = "$Destination\$subDirPath"
    						}
    						else
    						{
    							$sendParams.Destination = $Destination
    						}
    						$sendFileParamColl += $sendParams
    					}
    					foreach ($paramBlock in $sendFileParamColl)
    					{
    						Send-File @paramBlock
    					}
    				}
    				else
    				{
    					Write-Verbose -Message "Starting WinRM copy of [$($p)] to [$($Destination)]"
    					# Get the source file, and then get its contents
    					$sourceBytes = [System.IO.File]::ReadAllBytes($p);
    					$streamChunks = @();
    					
    					# Now break it into chunks to stream.
    					$streamSize = 1MB;
    					for ($position = 0; $position -lt $sourceBytes.Length; $position += $streamSize)
    					{
    						$remaining = $sourceBytes.Length - $position
    						$remaining = [Math]::Min($remaining, $streamSize)
    						
    						$nextChunk = New-Object byte[] $remaining
    						[Array]::Copy($sourcebytes, $position, $nextChunk, 0, $remaining)
    						$streamChunks +=, $nextChunk
    					}
    					$remoteScript = {
    						if (-not (Test-Path -Path $using:Destination -PathType Container))
    						{
    							$null = New-Item -Path $using:Destination -Type Directory -Force
    						}
    						$fileDest = "$using:Destination\$($using:p | Split-Path -Leaf)"
    						## Create a new array to hold the file content
    						$destBytes = New-Object byte[] $using:length
    						$position = 0
    						
    						## Go through the input, and fill in the new array of file content
    						foreach ($chunk in $input)
    						{
    							[GC]::Collect()
    							[Array]::Copy($chunk, 0, $destBytes, $position, $chunk.Length)
    							$position += $chunk.Length
    						}
    						
    						[IO.File]::WriteAllBytes($fileDest, $destBytes)
    						
    						Get-Item $fileDest
    						[GC]::Collect()
    					}
    					
    					# Stream the chunks into the remote script.
    					$Length = $sourceBytes.Length
    					$streamChunks | Invoke-Command -Session $Session -ScriptBlock $remoteScript
    					Write-Verbose -Message "WinRM copy of [$($p)] to [$($Destination)] complete"
    				}
    			}
    			catch
    			{
    				Write-Error $_.Exception.Message
    			}
    		}
    	}
    	
    }#End Function Send-File
    
  • #45417

    Keymaster
    Points: 1,811
    Helping HandTeam Member
    Rank: Community Hero

    As a note, Remoting in v5 natively supports in-channel file copy.

    • #45419

      Participant
      Points: 0
      Rank: Member

      Thats certainly good to know, unfortunately it's a no-fly-zone for us right now, likely until we standardize on 2016 so v5 is prepackaged.

      Still nice to know it's incoming 🙂

      Anyone else write something in the meantime that works on v4?

The topic ‘Recieve files over the current Session’ is closed to new replies.

denizli escort samsun escort muğla escort ataşehir escort kuşadası escort