虚拟移动硬盘

本贴最后更新于 2314 天前,其中的信息可能已经时移世易

虚拟移动硬盘

背景

目前的工作需要在虚拟机中进行,因为笔记本电脑配置不高,为了让虚拟机中的 win10 系统运行流畅,因此除了公司登陆内网的安全软件外,其余软件一概不装。但是这就带来一个问题,工作中需要使用的 office 办公软件虚拟机中没有安装,这时候就要将虚拟机中的文件拿到物理机中用 office 打开。当然,解决的方法多种多样,VMWare 虚拟机可以直接将文件复制出来,我现在用的 Hyper-V 的话可以通过共享文件的方式访问。我这里用的虚拟机是 win10 自带的 Hyper-V,直接复制文件出来的办法行不通,共享文件倒是可以实现,但是因为虚拟机里的工作环境装有公司的安全软件,如果开启共享,就无法连接到公司内网,所以这个方法也 pass 掉。怎么办?还有一个方法。创建一个 vhd 虚拟硬盘挂载到虚拟机中,用来存放工作中用到的文件,当需要在物理机中打开这些文件时,先卸载虚拟机中的 vhd,然后在挂载到物理机中,这就像是两台电脑之间通过移动硬盘传输文件一样,只不过这个移动硬盘是个“假的”。但是每次需要打开一个文件的时候,都要先在 Hyper-V 里操作卸载 vhd,然后又要在物理机中挂载这个 vhd,有些时候只是需要打开文件看一眼,也就几秒钟,但是这一系列操作下来花了 1 分钟,很繁琐。刚好这几天在学 PowerShell,就想到用它实现这些操作的自动化。

用到的 PowerShell 命令

获取 VHD:Get-VHD

获取虚拟机:Get-VM

获取虚拟机磁盘驱动器:Get-VMHardDiskDrive

增加一个磁盘驱动到虚拟机:Add-VMHardDiskDrive

删除磁盘驱动:Remove-VMHardDiskDrive

卸载 VHD:Dismount-VHD

装载一个或多个虚拟磁盘:Mount-VHD

打印信息到控制台:Write-Output

代码实现

if( $args.Length -ne 2 ){
    Write-Output "请传入参数:虚拟机名称 VHD路径"
    exit
}
$vmName = $args[0]
$vhdPath = $args[1]
$vhdObj = Get-VHD -Path $vhdPath
if (!$?) {
    Write-Output "VHD不存在! ---> $vhdPath"
    exit
}
$vmm = Get-VM -Name $vmName
# 判断虚拟机是否存在
if ($?) {
    # 获取虚拟机中的虚拟磁盘驱动器
    $vmHardDiskDriveList = Get-VMHardDiskDrive -VMName $vmName
    # 判断是否已经挂着了“移动VHD”
    foreach ( $vmHardDiskDrive in $vmHardDiskDriveList ) {
        if ( $vmHardDiskDrive.Path -like $vhdObj.Path ) {
            Write-Output "准备卸载虚拟机中的VHD,挂载到物理机..."
            Remove-VMHardDiskDrive -VMName $vmName -ControllerType $vmHardDiskDrive.ControllerType -ControllerNumber $vmHardDiskDrive.ControllerNumber -ControllerLocation $vmHardDiskDrive.ControllerLocation
            if ($?) {
                Write-Output "虚拟机卸载VHD成功!准备挂载到物理机..."
            } else {
                Write-Output "虚拟机卸载VHD失败,退出脚本!"
                exit
            }
            if (!$vhdObj.Attached -or ($null -eq $vhdObj.Number)) {
                # 物理机挂载VHD
                Mount-VHD -Path $vhdPath
                if ($?) {
                    Write-Output "物理机挂载VHD成功!"
                } else {
                    Write-Output "物理机挂载VHD失败,退出脚本!"
                    exit
                }
            } else {
                Write-Output "物理机VHD已挂载,无需重复操作。"
            }
            exit
        }
    }
    Write-Output "准备卸载物理机中的VHD,挂载到虚拟机..."
    if ( $vhdObj.Attached ) {
        Dismount-VHD -Path $vhdObj.Path
        if ($?) {
            Write-Output "物理机卸载VHD成功!准备挂载到虚拟机..."
        } else {
            Write-Output "物理机卸载VHD失败,退出脚本!"
            exit
        }
    } else {
        Write-Output "物理机VHD没有挂载!准备挂载到虚拟机..."
    }
    Add-VMHardDiskDrive -VMName $vmName -ControllerType SCSI -ControllerLocation $vmHardDiskDriveList.Length -Path $vhdObj.Path
    if ($?) {
        Write-Output "虚拟机挂载VHD成功!"
    } else {
        Write-Output "虚拟机挂载VHD失败,退出脚本!"
    }
    exit
} else {
    Write-Output "虚拟机不存在! ---> $vmName"
    exit
}

OK 了吗

代码写完了,但是执行却遇到麻烦。首先,默认情况下,脚本的运行策略是 Restricted,也就是不执行脚本,需要调整。第二,脚本必须以管理员身份运行,但是在脚本的右键菜单里并没有这个选项,属性中也没有这项设置。解决方法也简单:

1.需要调整计算机的脚本运行默认策略
将脚本执行策略调整为‘REMOTESIGNED’网络上下载的脚本执行需要签名,本地脚本执行不需要签名

Set-ExecutionPolicy -ExecutionPolicy REMOTESIGNED

2.需要以管理员方式运行,执行脚本
通过 bat 调用 ps 脚本,bat 脚本右键菜单中有“以管理员身份运行”

powershell.exe -file D:\MtK\PowerShell\自动化虚拟移动硬盘.ps1 "win10工作" "D:\Hyper-V\Virtual hard disks\移动虚拟硬盘.vhdx"

@pause
exit

资料

PowerShell 脚本执行策略

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1083 引用 • 3461 回帖 • 287 关注
  • Shell

    Shell 脚本与 Windows/Dos 下的批处理相似,也就是用各类命令预先放入到一个文件中,方便一次性执行的一个程序文件,主要是方便管理员进行设置或者管理用的。但是它比 Windows 下的批处理更强大,比用其他编程程序编辑的程序效率更高,因为它使用了 Linux/Unix 下的命令。

    122 引用 • 73 回帖
  • 脚本
    18 引用 • 42 回帖 • 1 关注
  • 技术

    到底什么才是技术呢?

    88 引用 • 179 回帖 • 4 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...