在Hyper-V主机和来宾之间的带有-FromSession的脚本中使用Copy-Item时失败

时间:2019-09-14 00:52:26

标签: powershell hyper-v powershell-remoting

  

主机:Windows Server 2016

     

客人:Windows 10 x64 1903

     

VM版本:8.0

首先,此VM与主机位于不同的VLAN中,并且专用于该VLAN的NIC无法与主机共享。同样,来宾和主机之间的第二个仅主机的网络也不是可接受的解决方案。

如果我在每个文件的交互式会话中使用Copy-Item -FromSession,则文件复制不会出现问题。但是,当我尝试在脚本中使用它时,收到一条错误消息,指出源文件的路径不存在,这是有道理的,因为该路径应该在来宾而不是主机上。尝试使用Get-ChildItem时,我遇到了同样的问题,因为该操作是在Hyper-V主机而非来宾的上下文中执行的。但是,如果我尝试将Copy-Item -FromSession包装在Invoke-Command中并插入$Using:<var>语法,则会收到一条错误消息,指出找不到参数

$VMRootDir = "Z:\vmshare\Completed\"     <# On the guest #>
$DestDir = "D:\Encoding Work\VMshare\"   <# Local to the host #>

# Setup Remote Session
$User = ".\psdirect"
$Pword = ConvertTo-SecureString -String "********" -AsPlainText -Force
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $Pword
$VMName = "TranscodeBox"
$S = New-PSSession -Credential $Cred -VMName $VMName
Enter-PSSession -Session $S

# Get Files to Copy
$files = Invoke-Command -Session $S -ScriptBlock { Get-ChildItem $Using:VMRootDir -Recurse | Where-Object {!$_.PSIsContainer } | % { $_.FullName } } 


# Copy Each File
Foreach ($file in $files) {
    # Get the new name
    $DestFileStr = $DestDir + $file.ToString().TrimStart($VMRootDir)

    #tell 'em what's happening
    write-host $file " -> " $DestFileStr


    #Do the copying
    <# This is were the error occurs #>
    Copy-Item -FromSession $S -Path $file -Destination $DestFileStr -Force
    Invoke-Command -Session $S -ScriptBlock { Copy-Item -FromSession $Using:S -Path $Using:file -Destination $Using:DestFileStr -Force}

    # Cleanup if the new file exists
    If (Test-Path $DestFileStr) {
        #Remove-Item $file
        Write-Host "Success  " $DestFileStr
    }
}

#Cleanup the Session
Exit-PSSession
Remove-PSSession -Session $S

错误消息(每个文件重复):

Copy-Item : Cannot find path 'Z:\vmshare\Completed\***\*****.mkv' because it does not exist.
At C:\Users\******\Desktop\cpTranscodeBox.ps1:23 char:5
+     Copy-Item -FromSession $S -Path $file -Destination $DestFileStr - ...
+     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (Z:\vmshare\Comp... *****.mkv:String) [Copy-Item], ArgumentException
    + FullyQualifiedErrorId : RemotePathNotFound,Microsoft.PowerShell.Commands.CopyItemCommand

A parameter cannot be found that matches parameter name 'FromSession'.
    + CategoryInfo          : InvalidArgument: (:) [Copy-Item], ParameterBindingException
    + FullyQualifiedErrorId : NamedParameterNotFound,Microsoft.PowerShell.Commands.CopyItemCommand
    + PSComputerName        : TranscodeBox

1 个答案:

答案 0 :(得分:0)

在这种情况下,此问题是由源文件名中包含[]引起的,我通过转义源文件名来解决了该问题

[Management.Automation.WildcardPattern]::Escape($<var>)

完整脚本:

$VMRootDir = "Z:\vmshare\Completed\"    <# On the guest #>
$DestDir = "D:\Encoding Work\VMshare\"  <# Local to the host #>

# Setup Remote Session
$User = ".\psdirect"
$Pword = ConvertTo-SecureString -String "********" -AsPlainText -Force
$Cred = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $User, $Pword
$VMName = "TranscodeBox"
$S = New-PSSession -Credential $Cred -VMName $VMName
Enter-PSSession -Session $S

# Get Files to Copy
$files = Invoke-Command -Session $S -ScriptBlock { Get-ChildItem $Using:VMRootDir -Recurse | Where-Object {!$_.PSIsContainer } | % { $_.FullName } } 


# Copy Each File
Foreach ($file in $files) {
    # Get the new name
    $DestFileStr = $DestDir + $file.TrimStart($VMRootDir)

    #tell 'em what's happening
    write-host $file " -> " $DestFileStr

    #Create the Directory if it doesn't exist
    $newDir = ([System.IO.Path]::GetDirectoryName($DestFileStr))
    if (!(Test-Path([Management.Automation.WildcardPattern]::Escape($newDir)))) { mkdir $newDir }

    #Do the copying
    Copy-Item -FromSession $S -Path ([Management.Automation.WildcardPattern]::Escape($file)) -Destination $DestFileStr 

    # Cleanup if the new file exists
        If (Test-Path ([Management.Automation.WildcardPattern]::Escape($DestFileStr))) {
        invoke-Command -Session $S -ScriptBlock {Remove-Item ([Management.Automation.WildcardPattern]::Escape($Using:file))}
        Write-Host "Success  " $DestFileStr
    }  
}

#Cleanup the Session
Exit-PSSession
Remove-PSSession -Session $S