2012-05-17 23 views
19

Ho appena bruciato un paio d'ore alla ricerca di una soluzione per inviare file su una PSSession attiva. E il risultato è nada, niente. Sto cercando di invocare un comando su un computer remoto su una sessione attiva, che dovrebbe copiare qualcosa da una memoria di rete. Quindi, in sostanza è questo:Invia file tramite PSSession

icm -Session $s { 
Copy-Item $networkLocation $PCLocation } 

A causa del problema "secondo hop", non posso farlo direttamente, e perché sto correndo assistente 2003 di vittoria non posso abilitare CredSSP. Potrei prima copiare i file sul mio computer e poi inviarli/inviarli al computer remoto, ma come? Ho provato PModem, ma come ho visto può solo tirare dati e non spingere.

Qualsiasi aiuto è visualizzato.

+1

Perché non usi la condivisione in rete per copiare i tuoi file? – JPBlanc

+1

Bello, ma le autorità superiori non lo approvano :) –

+1

Se è possibile abilitare il computer remoto come "trusted per delega" in AD, è possibile eseguire il secondo hop senza CredSSP. –

risposta

17

Se si tratta di un file di piccole dimensioni, è possibile inviare i contenuti del file e il nome del file come parametri.

$f="the filename" 
$c=Get-Content $f 
invoke-command -session $s -script {param($filename,$contents) ` 
    set-content -path $filename -value $contents} -argumentlist $f,$c 

Se il file è troppo lungo per essere contenuto in qualsiasi limiti per la sessione sono, si poteva leggere il file come pezzi, e utilizzare una tecnica simile per aggiungere insieme nella posizione di destinazione

+1

'$ f == $ nomefile' e' $ c == $ contenuto' ?? –

+2

$ nomefile e $ contenuto sono i nomi dei parametri nel blocco di script. $ f e $ c sono variabili che vengono passate allo scriptblock. –

2

Ho affrontato lo stesso problema qualche tempo fa e ho messo insieme un proof-of-concept per l'invio di file su una sessione Remoting di PS. Troverete lo script qui:

https://gist.github.com/791112

#requires -version 2.0 

[CmdletBinding()] 
param (
    [Parameter(Mandatory=$true)] 
    [string] 
    $ComputerName, 

    [Parameter(Mandatory=$true)] 
    [string] 
    $Path, 

    [Parameter(Mandatory=$true)] 
    [string] 
    $Destination, 

    [int] 
    $TransferChunkSize = 0x10000 
) 

function Initialize-TempScript ($Path) { 
    "<# DATA" | Set-Content -Path $Path 
} 

function Complete-Chunk() { 
@" 
DATA #> 
`$TransferPath = `$Env:TEMP | Join-Path -ChildPath '$TransferId' 
`$InData = `$false 
`$WriteStream = [IO.File]::OpenWrite(`$TransferPath) 
try { 
    `$WriteStream.Seek(0, 'End') | Out-Null 
    `$MyInvocation.MyCommand.Definition -split "``n" | ForEach-Object { 
     if (`$InData) { 
      `$InData = -not `$_.StartsWith('DATA #>') 
      if (`$InData) { 
       `$WriteBuffer = [Convert]::FromBase64String(`$_) 
       `$WriteStream.Write(`$WriteBuffer, 0, `$WriteBuffer.Length) 
      } 
     } else { 
      `$InData = `$_.StartsWith('<# DATA') 
     } 
    } 
} finally { 
    `$WriteStream.Close() 
} 
"@ 
} 

function Complete-FinalChunk ($Destination) { 
@" 
`$TransferPath | Move-Item -Destination '$Destination' -Force 
"@ 
} 

$ErrorActionPreference = 'Stop' 
Set-StrictMode -Version Latest 

$EncodingChunkSize = 57 * 100 
if ($EncodingChunkSize % 57 -ne 0) { 
    throw "EncodingChunkSize must be a multiple of 57" 
} 

$TransferId = [Guid]::NewGuid().ToString() 


$Path = ($Path | Resolve-Path).ProviderPath 
$ReadBuffer = New-Object -TypeName byte[] -ArgumentList $EncodingChunkSize 

$TempPath = ([IO.Path]::GetTempFileName() | % { $_ | Move-Item -Destination "$_.ps1" -PassThru}).FullName 
$Session = New-PSSession -ComputerName $ComputerName 
$ReadStream = [IO.File]::OpenRead($Path) 

$ChunkCount = 0 
Initialize-TempScript -Path $TempPath 

try { 
    do { 
     $ReadCount = $ReadStream.Read($ReadBuffer, 0, $EncodingChunkSize) 
     if ($ReadCount -gt 0) { 
      [Convert]::ToBase64String($ReadBuffer, 0, $ReadCount, 'InsertLineBreaks') | 
       Add-Content -Path $TempPath 
     } 
     $ChunkCount += $ReadCount 
     if ($ChunkCount -ge $TransferChunkSize -or $ReadCount -eq 0) { 
      # send 
      Write-Verbose "Sending chunk $TransferIndex" 
      Complete-Chunk | Add-Content -Path $TempPath 
      if ($ReadCount -eq 0) { 
       Complete-FinalChunk -Destination $Destination | Add-Content -Path $TempPath 
       Write-Verbose "Sending final chunk" 
      } 
      Invoke-Command -Session $Session -FilePath $TempPath 

      # reset 
      $ChunkCount = 0 
      Initialize-TempScript -Path $TempPath 
     } 
    } while ($ReadCount -gt 0) 
} finally { 
    if ($ReadStream) { $ReadStream.Close() } 
    $Session | Remove-PSSession 
    $TempPath | Remove-Item 
} 

Alcune piccole modifiche permetterebbero di accettare una sessione come parametro invece di esso uno nuovo. Ho trovato che il consumo di memoria sul servizio Remoting sul computer di destinazione potrebbe aumentare notevolmente durante il trasferimento di file di grandi dimensioni. Sospetto che PS Remoting non sia stato progettato per essere utilizzato in questo modo.

31

questo è ora possibile in PowerShell/WMF 5,0

Copy-Item ha -FromSession e -toSession parametri. Puoi usare uno di questi e passare una variabile di sessione.

es.

$cs = New-PSSession -ComputerName 169.254.44.14 -Credential (Get-Credential) -Name SQL 
Copy-Item Northwind.* -Destination "C:\Program Files\Microsoft SQL Server\MSSQL10_50.SQL2008R2\MSSQL\DATA\" -ToSession $cs 

Vedi altri esempi in https://richardspowershellblog.wordpress.com/2015/05/28/copy-files-over-ps-remoting-sessions/

0
$data = Get-Content 'C:\file.exe' -Raw 
Invoke-Command -ComputerName 'server' -ScriptBlock { $using:data | Set-Content -Path 'D:\filecopy.exe' } 

Non sa cosa il limite massimo di dimensione del file è.

+0

Che cosa significa 'get-data'? – Mark

+0

Sarei io a scrivere PowerShell dalla cima della mia testa. Dovrebbe essere 'Get-Content' ovviamente – mtnielsen

1

NET USE consente di aggiungere una lettera di unità locale per il sistema remoto, che poi poi consente di utilizzare la lettera di unità nel vostro PSSession, o anche senza una sessione PSSession. Questo è utile se non hai Powershell v5.0, e anche se lo fai,

È possibile utilizzare il nome del computer remoto o il suo indirizzo IP come parte del percorso UNC remoto ed è possibile specificare le credenziali di nome utente e password sulla stessa linea:

NET USE Z: \\192.168.1.50\ShareName /USER:192.168.1.50\UserName UserPassword 

Un altro esempio:

NET USE Z: \\RemoteSystem\ShareName /USER:RemoteSystem\UserName UserPassword 

O

NET USE Z: \\RemoteSystem\ShareName /USER:Domain\UserName UserPassword 

Se non si forniscono il cr utente edentials sulla stessa linea, verrà richiesto per loro:

>NET USE Z: \\192.168.1.50\ShareName 
Enter the user name for '192.168.1.50': 192.168.1.50\UserName 
Enter the password for 192.168.1.50: ***** 
The command completed successfully. 

è possibile rimuovere la lettera di unità quando hai finito con il seguente:

NET USE Z: /delete 

È possibile ottenere la sintassi completa con NET USO /?

>net use /? 
The syntax of this command is: 

NET USE 
[devicename | *] [\\computername\sharename[\volume] [password | *]] 
     [/USER:[domainname\]username] 
     [/USER:[dotted domain name\]username] 
     [/USER:[[email protected] domain name] 
     [/SMARTCARD] 
     [/SAVECRED] 
     [[/DELETE] | [/PERSISTENT:{YES | NO}]] 

NET USE {devicename | *} [password | *] /HOME 

NET USE [/PERSISTENT:{YES | NO}] 

NET è un comando standard .exe esterno nella cartella di sistema e lavora a PowerShell bene.

+0

Non è molto più semplice aggiornare il tuo powershell alla v5 +? – Liam