【问题标题】:Send files over PSSession通过 PSSession 发送文件
【发布时间】:2012-05-17 11:51:51
【问题描述】:

我花了几个小时寻找通过活动 PSSession 发送文件的解决方案。结果是nada,niente。我正在尝试通过活动会话在远程计算机上调用命令,该会话应该从网络存储中复制某些内容。所以,基本上就是这样:

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

由于“第二跳”问题,我不能直接这样做,而且因为我运行的是 win server 2003,所以我无法启用 CredSSP。我可以先将文件复制到我的计算机,然后将它们发送/推送到远程计算机,但是如何?我试过 PModem,但我看到它只能拉数据而不能推。

感谢任何帮助。

【问题讨论】:

  • 你为什么不使用网络共享来复制你的文件?
  • 不错,但上级不批准:)
  • 如果您可以在 AD 中启用远程计算机“信任委派”,那么您可以在没有 CredSSP 的情况下执行第二跳。

标签: powershell winrm


【解决方案1】:

这现在可以在 PowerShell / WMF 5.0 中实现

Copy-Item 具有 -FromSession-toSession 参数。您可以使用其中之一并传入会话变量。

例如。

$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

here查看更多示例,或者您可以查看official documentation

【讨论】:

  • 如何使用 ComputerNames 列表执行此操作?
  • 您需要为每个目标会话多次调用 Copy-Item。
【解决方案2】:

如果是小文件,可以将文件内容和文件名作为参数发送。

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

如果文件太长而无法满足会话的任何限制,您可以将文件作为块读取,并使用类似的技术将它们一起附加到目标位置


PowerShell 5+ 已内置支持此操作,如 David's answer 中所述。

【讨论】:

  • $f == $filename$c == $contents??
  • $filename 和 $contents 是脚本块中参数的名称。 $f 和 $c 是传递给脚本块的变量。
【解决方案3】:

不久前我遇到了同样的问题,并整理了一个概念验证,用于通过 PS Remoting 会话发送文件。您可以在此处找到脚本:

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
}

一些小的更改将允许它接受一个会话作为参数,而不是开始一个新的。我发现在传输大文件时,目标计算机上的远程处理服务的内存消耗可能会变得非常大。我怀疑 PS Remoting 并不是真正设计用于这种方式的。

【讨论】:

    【解决方案4】:

    NET USE 允许您为远程系统添加本地驱动器号,然后允许您在 PSSession 中使用驱动器号,甚至不使用PSSession。如果您没有 Powershell v5.0,这很有帮助,即使您有,

    您可以使用远程机器名称或其 IP 地址作为远程 UNC 路径的一部分,并且可以在同一行指定用户名和密码凭据:

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

    另一个例子:

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

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

    如果您没有在同一行提供用户凭据,系统将提示您输入:

    >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.
    

    完成以下操作后,您可以删除驱动器号:

        NET USE Z: /delete
    

    您可以使用 NET USE /? 获得完整的语法。

    >net use /?
    The syntax of this command is:
    
    NET USE
    [devicename | *] [\\computername\sharename[\volume] [password | *]]
            [/USER:[domainname\]username]
            [/USER:[dotted domain name\]username]
            [/USER:[username@dotted domain name]
            [/SMARTCARD]
            [/SAVECRED]
            [[/DELETE] | [/PERSISTENT:{YES | NO}]]
    
    NET USE {devicename | *} [password | *] /HOME
    
    NET USE [/PERSISTENT:{YES | NO}]  
    

    NET 是系统文件夹中的标准外部 .exe 命令,在 Powershell 中运行良好。

    【讨论】:

    • 将你的powershell升级到v5+不是更容易吗?
    【解决方案5】:
    $data = Get-Content 'C:\file.exe' -Raw
    Invoke-Command -ComputerName 'server' -ScriptBlock { $using:data | Set-Content -Path 'D:\filecopy.exe' }
    

    实际上并不知道最大文件大小限制是多少。

    【讨论】:

    • 什么是get-data
    • 那将是我从头顶输入 powershell。显然应该是Get-Content
    猜你喜欢
    • 2012-09-16
    • 2015-01-26
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多